diff --git a/.gitignore b/.gitignore index df20c3f..3b1f19f 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,12 @@ build/ .vscode/ /cert/ /src/main/resources/dev/ + +### macOS ### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db diff --git a/docs/BSZX_ORDER_TOTAL_IMPLEMENTATION.md b/docs/BSZX_ORDER_TOTAL_IMPLEMENTATION.md new file mode 100644 index 0000000..608f4a8 --- /dev/null +++ b/docs/BSZX_ORDER_TOTAL_IMPLEMENTATION.md @@ -0,0 +1,187 @@ +# 百色中学订单总金额统计功能实现文档 + +## 功能概述 + +参考ShopOrderController的total方法,完善了BszxOrderController中的订单总金额统计功能,提供REST API接口用于统计百色中学所有捐款记录的总金额。 + +## API接口 + +### 统计订单总金额 + +**接口地址**: `GET /api/bszx/bszx-order/total` + +**接口描述**: 统计百色中学所有捐款记录的总金额 + +**请求参数**: 无 + +**响应格式**: +```json +{ + "code": 200, + "message": "操作成功", + "data": 12345.67 +} +``` + +**响应说明**: +- `data`: BigDecimal类型,表示捐款总金额 +- 统计所有捐款记录(bszx_pay表中的price字段) +- 使用COALESCE函数处理空值,确保返回值不为null + +## 实现细节 + +### 1. 接口层 (Controller) + +**文件**: `BszxOrderController.java` + +```java +@Operation(summary = "统计订单总金额") +@GetMapping("/total") +public ApiResult total() { + try { + BigDecimal totalAmount = bszxPayService.total(); + return success(totalAmount); + } catch (Exception e) { + // 异常时返回0,保持接口稳定性 + return success(BigDecimal.ZERO); + } +} +``` + +### 2. 服务层 (Service) + +**接口定义** (`BszxPayService.java`): +```java +/** + * 统计捐款总金额 + * + * @return 捐款总金额 + */ +BigDecimal total(); +``` + +**实现类** (`BszxPayServiceImpl.java`): +```java +@Override +public BigDecimal total() { + try { + // 使用数据库聚合查询统计捐款总金额,性能更高 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + BigDecimal total = baseMapper.selectSumMoney(wrapper); + + if (total == null) { + total = BigDecimal.ZERO; + } + + return total; + + } catch (Exception e) { + // 异常时返回0,确保接口稳定性 + return BigDecimal.ZERO; + } +} +``` + +### 3. 数据访问层 (Mapper) + +**Mapper接口** (`BszxPayMapper.java`): +```java +BigDecimal selectSumMoney(@Param("ew") Wrapper wrapper); +``` + +**XML映射** (`BszxPayMapper.xml`): +```xml + + +``` + +## 与ShopOrderController的对比 + +| 特性 | ShopOrderController | BszxOrderController | +|------|-------------------|-------------------| +| 统计字段 | pay_price | price | +| 过滤条件 | pay_status = 1 AND deleted = 0 | 无特殊过滤 | +| 数据表 | shop_order | bszx_pay | +| 业务场景 | 商城已支付订单 | 百色中学捐款记录 | +| 异常处理 | ✓ | ✓ | +| 空值处理 | ✓ | ✓ | + +## 统计规则 + +1. **全量统计**: 统计bszx_pay表中所有记录的price字段总和 +2. **空值处理**: 使用COALESCE函数,当没有记录时返回0 +3. **异常处理**: 包含完整的异常处理机制,确保接口稳定性 +4. **性能优化**: 使用数据库聚合查询,在数据库层面进行计算 + +## 性能优化 + +1. **数据库聚合**: 使用SQL的SUM函数在数据库层面进行聚合计算 +2. **复用现有方法**: 复用了已有的selectSumMoney方法,避免重复开发 +3. **异常处理**: 包含完整的异常处理机制,确保接口稳定性 +4. **索引建议**: 如果数据量大,建议在price字段上创建索引 + +## 测试用例 + +创建了测试类 `BszxOrderTotalTest.java` 用于验证功能: + +```java +@Test +void testBszxOrderTotal() { + BigDecimal total = bszxPayService.total(); + assertNotNull(total, "百色中学订单总金额不应该为null"); + assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "百色中学订单总金额应该大于等于0"); +} + +@Test +void testBszxOrderTotalPerformance() { + long startTime = System.currentTimeMillis(); + BigDecimal total = bszxPayService.total(); + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + assertTrue(duration < 5000, "查询时间应该在5秒以内"); +} +``` + +## 使用示例 + +### 前端调用示例 + +```javascript +// 获取百色中学订单总金额 +fetch('/api/bszx/bszx-order/total') + .then(response => response.json()) + .then(data => { + if (data.code === 200) { + console.log('百色中学订单总金额:', data.data); + } + }); +``` + +### cURL调用示例 + +```bash +curl -X GET "http://localhost:8080/api/bszx/bszx-order/total" \ + -H "Content-Type: application/json" +``` + +## 注意事项 + +1. **数据精度**: 使用BigDecimal确保金额计算的精度 +2. **并发安全**: 查询操作是只读的,天然支持并发访问 +3. **业务逻辑**: 与商城订单不同,百色中学捐款记录不需要过滤支付状态 +4. **扩展性**: 可以通过传入不同的查询条件实现更复杂的统计需求 + +## 扩展功能建议 + +1. **按时间范围统计**: 支持指定时间范围的捐款金额统计 +2. **按项目统计**: 支持按form_id进行分组统计 +3. **按用户统计**: 支持统计不同用户的捐款总额 +4. **缓存机制**: 对于大数据量场景,可以添加Redis缓存 +5. **权限控制**: 根据业务需要可以添加相应的权限控制注解 diff --git a/docs/COUPON_FEATURE_GUIDE.md b/docs/COUPON_FEATURE_GUIDE.md new file mode 100644 index 0000000..e6efbd0 --- /dev/null +++ b/docs/COUPON_FEATURE_GUIDE.md @@ -0,0 +1,191 @@ +# 优惠券功能使用指南 + +## 功能概述 + +本系统实现了完整的优惠券功能,包括优惠券模板管理、用户优惠券管理、优惠券使用、统计分析等功能。 + +## 核心功能 + +### 1. 优惠券模板管理 +- 创建优惠券模板(满减券、折扣券、免费券) +- 设置发放数量限制和个人领取限制 +- 配置适用范围(全部商品、指定商品、指定分类) +- 设置有效期(领取后生效或固定时间) + +### 2. 用户优惠券管理 +- 用户主动领取优惠券 +- 系统自动发放优惠券 +- 优惠券使用和退还 +- 优惠券状态管理(未使用、已使用、已过期) + +### 3. 订单优惠券功能 +- 获取订单可用优惠券 +- 计算优惠券优惠金额 +- 验证优惠券适用性 +- 推荐最优优惠券组合 + +### 4. 业务场景支持 +- 新用户注册赠送 +- 生日优惠券发放 +- 消费返券 +- 活动批量发放 + +## 数据库表结构 + +### 优惠券模板表 (shop_coupon) +```sql +- id: 主键 +- name: 优惠券名称 +- description: 优惠券描述 +- type: 优惠券类型(10满减券 20折扣券 30免费券) +- reduce_price: 满减金额 +- discount: 折扣率(0-100) +- min_price: 最低消费金额 +- total_count: 发放总数量(-1无限制) +- issued_count: 已发放数量 +- limit_per_user: 每人限领数量(-1无限制) +- expire_type: 到期类型(10领取后生效 20固定时间) +- expire_day: 有效天数 +- start_time: 有效期开始时间 +- end_time: 有效期结束时间 +- apply_range: 适用范围(10全部商品 20指定商品 30指定分类) +- apply_range_config: 适用范围配置(JSON格式) +- enabled: 是否启用 +- status: 状态 +``` + +### 用户优惠券表 (shop_user_coupon) +```sql +- id: 主键 +- coupon_id: 优惠券模板ID +- user_id: 用户ID +- name: 优惠券名称 +- type: 优惠券类型 +- reduce_price: 满减金额 +- discount: 折扣率 +- min_price: 最低消费金额 +- start_time: 有效期开始时间 +- end_time: 有效期结束时间 +- status: 使用状态(0未使用 1已使用 2已过期) +- use_time: 使用时间 +- order_id: 使用订单ID +- order_no: 使用订单号 +- obtain_type: 获取方式(10主动领取 20系统发放 30活动赠送) +- obtain_source: 获取来源描述 +``` + +## API接口说明 + +### 优惠券模板管理 +- `GET /api/shop/shop-coupon/page` - 分页查询优惠券模板 +- `POST /api/shop/shop-coupon` - 创建优惠券模板 +- `PUT /api/shop/shop-coupon` - 更新优惠券模板 +- `DELETE /api/shop/shop-coupon/{id}` - 删除优惠券模板 + +### 用户优惠券管理 +- `GET /api/shop/user-coupon/my` - 获取当前用户优惠券 +- `GET /api/shop/user-coupon/my/available` - 获取可用优惠券 +- `POST /api/shop/user-coupon/receive/{couponId}` - 领取优惠券 +- `PUT /api/shop/user-coupon/use` - 使用优惠券 +- `PUT /api/shop/user-coupon/return/{orderId}` - 退还优惠券 + +### 优惠券业务功能 +- `POST /api/shop/coupon-business/available-for-order` - 获取订单可用优惠券 +- `POST /api/shop/coupon-business/calculate-order-amount` - 计算使用优惠券后的订单金额 +- `POST /api/shop/coupon-business/recommend-best-combination` - 推荐最优优惠券组合 +- `POST /api/shop/coupon-business/batch-issue-activity` - 批量发放活动优惠券 + +## 使用示例 + +### 1. 创建优惠券模板 +```json +{ + "name": "新用户专享券", + "description": "新用户注册即可领取", + "type": 10, + "reducePrice": 20.00, + "minPrice": 100.00, + "totalCount": 1000, + "limitPerUser": 1, + "expireType": 10, + "expireDay": 30, + "applyRange": 10, + "enabled": 1 +} +``` + +### 2. 用户领取优惠券 +```javascript +// 前端调用 +POST /api/shop/user-coupon/receive/1 +``` + +### 3. 订单使用优惠券 +```json +{ + "goodsItems": [ + { + "goodsId": 1, + "categoryId": 1, + "price": 150.00, + "quantity": 1 + } + ], + "totalAmount": 150.00 +} +``` + +### 4. 计算优惠金额 +```javascript +// 获取可用优惠券 +POST /api/shop/coupon-business/available-for-order + +// 计算优惠金额 +POST /api/shop/coupon-business/calculate-order-amount?userCouponId=1 +``` + +## 定时任务 + +系统包含以下定时任务: + +1. **过期优惠券处理** - 每天凌晨2点执行 + - 自动更新过期优惠券状态 + +2. **优惠券到期提醒** - 每天上午10点执行 + - 提醒用户即将过期的优惠券 + +3. **生日优惠券发放** - 每天凌晨1点执行 + - 为当天生日的用户发放生日优惠券 + +## 配置说明 + +### 优惠券类型配置 +- `TYPE_REDUCE = 10` - 满减券 +- `TYPE_DISCOUNT = 20` - 折扣券 +- `TYPE_FREE = 30` - 免费券 + +### 适用范围配置 +- `APPLY_ALL = 10` - 全部商品 +- `APPLY_GOODS = 20` - 指定商品 +- `APPLY_CATEGORY = 30` - 指定分类 + +### 获取方式配置 +- `OBTAIN_RECEIVE = 10` - 主动领取 +- `OBTAIN_SYSTEM = 20` - 系统发放 +- `OBTAIN_ACTIVITY = 30` - 活动赠送 + +## 注意事项 + +1. **数据一致性**:优惠券使用和退还操作需要保证数据一致性 +2. **并发控制**:优惠券领取需要考虑并发情况,避免超发 +3. **性能优化**:大量用户时需要考虑查询性能优化 +4. **业务规则**:根据实际业务需求调整优惠券规则和限制 + +## 扩展功能 + +可以根据业务需要扩展以下功能: +- 优惠券分享功能 +- 优惠券兑换码功能 +- 优惠券组合使用 +- 优惠券使用统计分析 +- 优惠券营销活动管理 diff --git a/docs/ORDER_DATABASE_FIELDS_FIX.md b/docs/ORDER_DATABASE_FIELDS_FIX.md new file mode 100644 index 0000000..9ce868d --- /dev/null +++ b/docs/ORDER_DATABASE_FIELDS_FIX.md @@ -0,0 +1,149 @@ +# 订单数据库字段缺失默认值修复指南 + +## 问题描述 + +在提交订单时遇到以下数据库错误: + +``` +{"code":1,"message":"\n### Error updating database. Cause: java.sql.SQLException: Field 'pay_price' doesn't have a default value\n### The error may exist in com/gxwebsoft/shop/mapper/ShopOrderMapper.java (best guess)\n### The error may involve com.gxwebsoft.shop.mapper.ShopOrderMapper.insert-Inline\n### The error occurred while setting parameters\n### SQL: INSERT INTO shop_order (order_no, delivery_type, address_id, total_price, price, pay_user_id, pay_type, pay_status, user_id, comments, tenant_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 10550)\n### Cause: java.sql.SQLException: Field 'pay_price' doesn't have a default value\n; Field 'pay_price' doesn't have a default value; nested exception is java.sql.SQLException: Field 'pay_price' doesn't have a default value"} +``` + +## 根本原因 + +数据库表 `shop_order` 中的 `pay_price` 字段没有设置默认值,而在插入订单记录时没有为该字段提供值,导致 SQL 插入失败。 + +## 解决方案 + +### 1. 修改 `buildShopOrder` 方法 + +在 `OrderBusinessService.buildShopOrder()` 方法中添加了所有必需字段的默认值设置: + +```java +// 设置价格相关字段(解决数据库字段没有默认值的问题) +if (shopOrder.getPayPrice() == null) { + shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额 +} + +if (shopOrder.getPrice() == null) { + shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额 +} + +if (shopOrder.getReducePrice() == null) { + shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0 +} + +if (shopOrder.getMoney() == null) { + shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额 +} + +// 设置默认状态 +shopOrder.setPayStatus(false); // 未付款 +shopOrder.setOrderStatus(0); // 未使用 +shopOrder.setDeliveryStatus(10); // 未发货 +shopOrder.setIsInvoice(0); // 未开发票 +shopOrder.setIsSettled(0); // 未结算 +shopOrder.setCheckBill(0); // 未对账 +shopOrder.setVersion(0); // 当前版本 + +// 设置默认支付类型(如果没有指定) +if (shopOrder.getPayType() == null) { + shopOrder.setPayType(1); // 默认微信支付 +} +``` + +### 2. 修改 `applyBusinessRules` 方法 + +确保测试账号逻辑也正确设置所有相关字段: + +```java +// 测试账号处理 +if (orderConfig.isTestAccount(loginUser.getPhone())) { + BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); + shopOrder.setPrice(testAmount); + shopOrder.setTotalPrice(testAmount); + shopOrder.setPayPrice(testAmount); // 确保实际付款也设置为测试金额 + shopOrder.setMoney(testAmount); // 确保积分计算金额也设置为测试金额 + log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount); +} +``` + +## 修复的字段列表 + +| 字段名 | 默认值 | 说明 | +|--------|--------|------| +| `payPrice` | `totalPrice` | 实际付款金额,默认等于订单总额 | +| `price` | `totalPrice` | 用于统计的价格,默认等于订单总额 | +| `reducePrice` | `BigDecimal.ZERO` | 减少的金额(优惠券、折扣等) | +| `money` | `totalPrice` | 用于积分赠送的价格 | +| `payStatus` | `false` | 支付状态,默认未付款 | +| `orderStatus` | `0` | 订单状态,默认未使用 | +| `deliveryStatus` | `10` | 发货状态,默认未发货 | +| `isInvoice` | `0` | 发票状态,默认未开发票 | +| `isSettled` | `0` | 结算状态,默认未结算 | +| `checkBill` | `0` | 对账状态,默认未对账 | +| `version` | `0` | 系统版本,默认当前版本 | +| `payType` | `1` | 支付类型,默认微信支付 | + +## 测试验证 + +创建了专门的测试用例 `testBuildShopOrder_RequiredFields` 来验证所有必需字段都正确设置: + +```java +@Test +void testBuildShopOrder_RequiredFields() throws Exception { + // 验证必需字段都已设置 + assertNotNull(result.getPayPrice(), "payPrice 不能为空"); + assertNotNull(result.getPrice(), "price 不能为空"); + assertNotNull(result.getReducePrice(), "reducePrice 不能为空"); + assertNotNull(result.getMoney(), "money 不能为空"); + // ... 其他字段验证 + + // 验证默认值 + assertEquals(testRequest.getTotalPrice(), result.getPayPrice()); + assertEquals(testRequest.getTotalPrice(), result.getPrice()); + assertEquals(BigDecimal.ZERO, result.getReducePrice()); + // ... 其他默认值验证 +} +``` + +## 业务逻辑说明 + +### 价格字段关系 + +1. **totalPrice**: 订单总额,由商品价格计算得出 +2. **payPrice**: 实际付款金额,通常等于 totalPrice,但可能因优惠而不同 +3. **price**: 用于统计的价格,通常等于 totalPrice +4. **money**: 用于积分赠送计算的价格 +5. **reducePrice**: 优惠减免的金额(优惠券、VIP折扣等) + +### 计算公式 + +``` +payPrice = totalPrice - reducePrice +``` + +在没有优惠的情况下: +``` +payPrice = totalPrice +reducePrice = 0 +``` + +## 影响范围 + +这个修复解决了以下问题: + +1. ✅ **数据库插入错误**: 解决了 `pay_price` 等字段缺少默认值的问题 +2. ✅ **订单状态完整性**: 确保所有状态字段都有正确的初始值 +3. ✅ **价格计算一致性**: 保证各个价格字段的逻辑关系正确 +4. ✅ **测试账号兼容性**: 确保测试账号逻辑正常工作 + +## 注意事项 + +1. **向后兼容**: 修改保持了向后兼容性,不会影响现有功能 +2. **数据完整性**: 所有必需字段都有合理的默认值 +3. **业务逻辑**: 默认值符合业务逻辑,不会产生异常数据 +4. **测试覆盖**: 有完整的测试用例覆盖修改的功能 + +## 总结 + +通过在 `buildShopOrder` 方法中添加完整的字段默认值设置,成功解决了订单提交时的数据库字段缺失问题。这个修复不仅解决了当前的错误,还提高了系统的健壮性,确保订单数据的完整性和一致性。 diff --git a/docs/ORDER_GOODS_FEATURE_GUIDE.md b/docs/ORDER_GOODS_FEATURE_GUIDE.md new file mode 100644 index 0000000..7801d68 --- /dev/null +++ b/docs/ORDER_GOODS_FEATURE_GUIDE.md @@ -0,0 +1,215 @@ +# 订单商品保存功能使用指南 + +## 功能概述 + +本功能为下单接口添加了保存订单商品的能力,支持在创建订单时同时保存多个商品项到订单商品表中。 + +## 前端数据结构 + +根据您提供的前端数据结构,系统现在支持以下格式的订单创建请求: + +```json +{ + "goodsItems": [ + { + "goodsId": 10018, + "quantity": 1, + "payType": 1 + } + ], + "addressId": 10832, + "comments": "科技小王子大米年卡套餐2.5kg", + "deliveryType": 0, + "type": 0, + "totalPrice": 99.00, + "payPrice": 99.00, + "totalNum": 1, + "payType": 1, + "tenantId": 1 +} +``` + +## 代码修改说明 + +### 1. OrderCreateRequest DTO 修改 + +在 `OrderCreateRequest` 类中添加了 `goodsItems` 字段: + +```java +@Schema(description = "订单商品列表") +@Valid +@NotEmpty(message = "订单商品列表不能为空") +private List goodsItems; + +/** + * 订单商品项 + */ +@Data +@Schema(name = "OrderGoodsItem", description = "订单商品项") +public static class OrderGoodsItem { + @Schema(description = "商品ID", required = true) + @NotNull(message = "商品ID不能为空") + private Integer goodsId; + + @Schema(description = "商品数量", required = true) + @NotNull(message = "商品数量不能为空") + @Min(value = 1, message = "商品数量必须大于0") + private Integer quantity; + + @Schema(description = "支付类型") + private Integer payType; +} +``` + +### 2. OrderBusinessService 修改 + +在 `OrderBusinessService` 中添加了保存订单商品的逻辑: + +```java +// 5. 保存订单商品 +saveOrderGoods(request, shopOrder); + +/** + * 保存订单商品 + */ +private void saveOrderGoods(OrderCreateRequest request, ShopOrder shopOrder) { + if (CollectionUtils.isEmpty(request.getGoodsItems())) { + log.warn("订单商品列表为空,订单号:{}", shopOrder.getOrderNo()); + return; + } + + List orderGoodsList = new ArrayList<>(); + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 获取商品信息 + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods == null) { + throw new BusinessException("商品不存在,商品ID:" + item.getGoodsId()); + } + + ShopOrderGoods orderGoods = new ShopOrderGoods(); + + // 设置订单关联信息 + orderGoods.setOrderId(shopOrder.getOrderId()); + orderGoods.setOrderCode(shopOrder.getOrderNo()); + + // 设置商户信息 + orderGoods.setMerchantId(shopOrder.getMerchantId()); + orderGoods.setMerchantName(shopOrder.getMerchantName()); + + // 设置商品信息 + orderGoods.setGoodsId(item.getGoodsId()); + orderGoods.setGoodsName(goods.getName()); + orderGoods.setImage(goods.getImage()); + orderGoods.setPrice(goods.getPrice()); + orderGoods.setTotalNum(item.getQuantity()); + + // 设置支付相关信息 + orderGoods.setPayStatus(0); // 0 未付款 + orderGoods.setOrderStatus(0); // 0 未使用 + orderGoods.setIsFree(false); // 默认收费 + orderGoods.setVersion(0); // 当前版本 + + // 设置其他信息 + orderGoods.setComments(request.getComments()); + orderGoods.setUserId(shopOrder.getUserId()); + orderGoods.setTenantId(shopOrder.getTenantId()); + + orderGoodsList.add(orderGoods); + } + + // 批量保存订单商品 + boolean saved = shopOrderGoodsService.saveBatch(orderGoodsList); + if (!saved) { + throw new BusinessException("保存订单商品失败"); + } + + log.info("成功保存订单商品,订单号:{},商品数量:{}", shopOrder.getOrderNo(), orderGoodsList.size()); +} +``` + +## 功能特性 + +### 1. 数据验证 +- 商品ID不能为空 +- 商品数量必须大于0 +- 订单商品列表不能为空 + +### 2. 商品信息自动填充 +- 自动从商品表获取商品名称、图片、价格等信息 +- 验证商品是否存在 + +### 3. 状态管理 +- 默认设置为未付款状态(payStatus = 0) +- 默认设置为未使用状态(orderStatus = 0) +- 默认设置为收费商品(isFree = false) + +### 4. 事务支持 +- 整个订单创建过程在同一个事务中 +- 如果保存订单商品失败,整个订单创建会回滚 + +## 使用示例 + +### 单商品订单 +```json +{ + "goodsItems": [ + { + "goodsId": 10018, + "quantity": 1, + "payType": 1 + } + ], + "type": 0, + "totalPrice": 99.00, + "payPrice": 99.00, + "totalNum": 1, + "payType": 1, + "tenantId": 1, + "comments": "科技小王子大米年卡套餐2.5kg" +} +``` + +### 多商品订单 +```json +{ + "goodsItems": [ + { + "goodsId": 10018, + "quantity": 1, + "payType": 1 + }, + { + "goodsId": 10019, + "quantity": 2, + "payType": 1 + } + ], + "type": 0, + "totalPrice": 297.00, + "payPrice": 297.00, + "totalNum": 3, + "payType": 1, + "tenantId": 1, + "comments": "多商品订单" +} +``` + +## 测试建议 + +1. **单元测试**: 已创建 `OrderBusinessServiceTest` 测试类,包含单商品和多商品订单的测试用例 +2. **集成测试**: 建议使用 Postman 或类似工具测试完整的订单创建流程 +3. **数据验证**: 测试各种边界情况,如商品不存在、数量为0等 + +## 注意事项 + +1. 确保商品表中存在对应的商品记录 +2. 前端需要正确计算订单总金额和总数量 +3. 支付类型字段在订单商品表中暂未使用,但保留了接口兼容性 +4. 建议在生产环境部署前进行充分测试 + +## 后续优化建议 + +1. 添加库存检查和扣减逻辑 +2. 支持商品规格(SKU)选择 +3. 添加商品价格变动检查 +4. 支持优惠券和折扣计算 diff --git a/docs/ORDER_TOTAL_IMPLEMENTATION.md b/docs/ORDER_TOTAL_IMPLEMENTATION.md new file mode 100644 index 0000000..37f9265 --- /dev/null +++ b/docs/ORDER_TOTAL_IMPLEMENTATION.md @@ -0,0 +1,163 @@ +# 订单总金额统计功能实现文档 + +## 功能概述 + +实现了订单总金额统计功能,提供REST API接口用于统计所有已支付订单的总金额。 + +## API接口 + +### 统计订单总金额 + +**接口地址**: `GET /api/shop/shop-order/total` + +**接口描述**: 统计所有已支付订单的总金额 + +**请求参数**: 无 + +**响应格式**: +```json +{ + "code": 200, + "message": "操作成功", + "data": 12345.67 +} +``` + +**响应说明**: +- `data`: BigDecimal类型,表示订单总金额 +- 只统计已支付的订单(pay_status = 1) +- 排除已删除的订单(deleted = 0) +- 使用实际付款金额(pay_price字段)进行统计 + +## 实现细节 + +### 1. 接口层 (Controller) + +```java +@Operation(summary = "统计订单总金额") +@GetMapping("/total") +public ApiResult total() { + return success(shopOrderService.total()); +} +``` + +### 2. 服务层 (Service) + +**接口定义** (`ShopOrderService.java`): +```java +/** + * 统计订单总金额 + * + * @return 订单总金额 + */ +BigDecimal total(); +``` + +**实现类** (`ShopOrderServiceImpl.java`): +```java +@Override +public BigDecimal total() { + try { + // 使用数据库聚合查询统计订单总金额,性能更高 + BigDecimal total = baseMapper.selectTotalAmount(); + + if (total == null) { + total = BigDecimal.ZERO; + } + + log.info("统计订单总金额完成,总金额:{}", total); + return total; + + } catch (Exception e) { + log.error("统计订单总金额失败", e); + return BigDecimal.ZERO; + } +} +``` + +### 3. 数据访问层 (Mapper) + +**Mapper接口** (`ShopOrderMapper.java`): +```java +/** + * 统计订单总金额 + * 只统计已支付的订单(pay_status = 1)且未删除的订单(deleted = 0) + * + * @return 订单总金额 + */ +@Select("SELECT COALESCE(SUM(pay_price), 0) FROM shop_order WHERE pay_status = 1 AND deleted = 0 AND pay_price IS NOT NULL") +BigDecimal selectTotalAmount(); +``` + +## 统计规则 + +1. **已支付订单**: 只统计 `pay_status = 1` 的订单 +2. **未删除订单**: 排除 `deleted = 1` 的订单 +3. **有效金额**: 排除 `pay_price IS NULL` 的记录 +4. **使用实际付款**: 统计 `pay_price` 字段而不是 `total_price` +5. **空值处理**: 使用 `COALESCE` 函数,当没有符合条件的记录时返回 0 + +## 性能优化 + +1. **数据库聚合**: 使用SQL的SUM函数在数据库层面进行聚合计算 +2. **索引优化**: 建议在 `pay_status` 和 `deleted` 字段上创建索引 +3. **异常处理**: 包含完整的异常处理机制,确保接口稳定性 + +## 测试用例 + +创建了测试类 `OrderTotalTest.java` 用于验证功能: + +```java +@Test +void testOrderTotal() { + BigDecimal total = shopOrderService.total(); + assertNotNull(total, "订单总金额不应该为null"); + assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "订单总金额应该大于等于0"); +} + +@Test +void testOrderTotalPerformance() { + long startTime = System.currentTimeMillis(); + BigDecimal total = shopOrderService.total(); + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + assertTrue(duration < 5000, "查询时间应该在5秒以内"); +} +``` + +## 使用示例 + +### 前端调用示例 + +```javascript +// 获取订单总金额 +fetch('/api/shop/shop-order/total') + .then(response => response.json()) + .then(data => { + if (data.code === 200) { + console.log('订单总金额:', data.data); + } + }); +``` + +### cURL调用示例 + +```bash +curl -X GET "http://localhost:8080/api/shop/shop-order/total" \ + -H "Content-Type: application/json" +``` + +## 注意事项 + +1. **数据精度**: 使用BigDecimal确保金额计算的精度 +2. **并发安全**: 查询操作是只读的,天然支持并发访问 +3. **缓存考虑**: 如果数据量很大且实时性要求不高,可以考虑添加缓存 +4. **权限控制**: 根据业务需要可以添加相应的权限控制注解 + +## 扩展功能建议 + +1. **按时间范围统计**: 支持指定时间范围的订单金额统计 +2. **按商户统计**: 支持按商户ID进行分组统计 +3. **按订单状态统计**: 支持统计不同状态订单的金额 +4. **缓存机制**: 对于大数据量场景,可以添加Redis缓存 diff --git a/docs/ORDER_VALIDATION_GUIDE.md b/docs/ORDER_VALIDATION_GUIDE.md new file mode 100644 index 0000000..340a287 --- /dev/null +++ b/docs/ORDER_VALIDATION_GUIDE.md @@ -0,0 +1,192 @@ +# 订单商品验证功能指南 + +## 概述 + +本文档介绍了订单创建时商品信息后台验证的实现方案。该方案确保了订单数据的安全性和一致性,防止前端数据被篡改。 + +## 主要特性 + +### 1. 商品信息后台验证 +- ✅ 商品存在性验证 +- ✅ 商品状态验证(上架/下架) +- ✅ 商品价格验证 +- ✅ 库存数量验证 +- ✅ 购买数量限制验证 +- ✅ 订单总金额重新计算 + +### 2. 数据安全保障 +- ✅ 防止前端价格篡改 +- ✅ 使用后台查询的真实商品信息 +- ✅ 订单金额一致性检查 +- ✅ 详细的错误提示信息 + +## 实现细节 + +### 核心方法 + +#### 1. validateOrderRequest() +```java +private void validateOrderRequest(OrderCreateRequest request, User loginUser) { + // 1. 用户登录验证 + if (loginUser == null) { + throw new BusinessException("用户未登录"); + } + + // 2. 验证商品信息并计算总金额 + BigDecimal calculatedTotal = validateAndCalculateTotal(request); + + // 3. 检查金额一致性 + if (request.getTotalPrice() != null && + request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) { + throw new BusinessException("订单金额计算错误,请刷新重试"); + } + + // 4. 使用后台计算的金额 + request.setTotalPrice(calculatedTotal); + + // 5. 检查租户特殊规则 + // ... +} +``` + +#### 2. validateAndCalculateTotal() +```java +private BigDecimal validateAndCalculateTotal(OrderCreateRequest request) { + BigDecimal total = BigDecimal.ZERO; + + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 获取商品信息 + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + + // 验证商品存在性 + if (goods == null) { + throw new BusinessException("商品不存在,商品ID:" + item.getGoodsId()); + } + + // 验证商品状态 + if (goods.getStatus() != 0) { + throw new BusinessException("商品已下架:" + goods.getName()); + } + + // 验证库存 + if (goods.getStock() != null && goods.getStock() < item.getQuantity()) { + throw new BusinessException("商品库存不足:" + goods.getName()); + } + + // 验证购买数量限制 + if (goods.getCanBuyNumber() != null && item.getQuantity() > goods.getCanBuyNumber()) { + throw new BusinessException("商品购买数量超过限制:" + goods.getName()); + } + + // 计算小计 + BigDecimal itemTotal = goods.getPrice().multiply(new BigDecimal(item.getQuantity())); + total = total.add(itemTotal); + } + + return total; +} +``` + +### 订单商品保存优化 + +```java +private void saveOrderGoods(OrderCreateRequest request, ShopOrder shopOrder) { + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 重新获取商品信息(确保数据一致性) + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + + // 再次验证商品状态(防止并发问题) + if (goods.getStatus() != 0) { + throw new BusinessException("商品已下架:" + goods.getName()); + } + + ShopOrderGoods orderGoods = new ShopOrderGoods(); + + // 使用后台查询的真实数据 + orderGoods.setGoodsId(item.getGoodsId()); + orderGoods.setGoodsName(goods.getName()); + orderGoods.setPrice(goods.getPrice()); // 使用后台价格 + orderGoods.setTotalNum(item.getQuantity()); + + // 设置其他信息... + } +} +``` + +## 验证流程 + +```mermaid +graph TD + A[前端提交订单] --> B[validateOrderRequest] + B --> C[validateAndCalculateTotal] + C --> D[验证商品存在性] + D --> E[验证商品状态] + E --> F[验证库存数量] + F --> G[验证购买限制] + G --> H[计算总金额] + H --> I[检查金额一致性] + I --> J[保存订单] + J --> K[saveOrderGoods] + K --> L[再次验证商品状态] + L --> M[使用后台数据保存] +``` + +## 错误处理 + +### 常见错误信息 + +| 错误码 | 错误信息 | 说明 | +|--------|----------|------| +| 1 | 用户未登录 | 用户身份验证失败 | +| 1 | 商品不存在,商品ID:xxx | 商品ID无效或已删除 | +| 1 | 商品已下架:xxx | 商品状态不是上架状态 | +| 1 | 商品价格异常:xxx | 商品价格为空或小于等于0 | +| 1 | 商品库存不足:xxx,当前库存:xxx | 购买数量超过可用库存 | +| 1 | 商品购买数量超过限制:xxx,最大购买数量:xxx | 超过单次购买限制 | +| 1 | 订单金额计算错误,请刷新重试 | 前端金额与后台计算不一致 | +| 1 | 商品金额不能为0 | 计算后的总金额为0或负数 | + +## 测试用例 + +项目包含完整的单元测试,覆盖以下场景: + +1. ✅ 正常订单创建 +2. ✅ 商品不存在 +3. ✅ 商品已下架 +4. ✅ 库存不足 +5. ✅ 超过购买限制 +6. ✅ 多商品金额计算 +7. ✅ 金额不一致检测 + +运行测试: +```bash +mvn test -Dtest=OrderValidationTest +``` + +## 最佳实践 + +### 1. 安全性 +- 始终使用后台查询的商品信息 +- 不信任前端传入的价格数据 +- 在保存前再次验证商品状态 + +### 2. 性能优化 +- 批量查询商品信息(如果需要) +- 缓存商品基础信息(可选) +- 合理的错误提示,避免过多数据库查询 + +### 3. 用户体验 +- 提供清晰的错误提示信息 +- 支持金额小误差容忍(0.01元) +- 及时更新前端商品状态 + +## 总结 + +通过后台验证商品信息的方案,我们实现了: + +1. **数据安全性**:防止价格篡改,确保订单金额准确 +2. **业务完整性**:完整的商品状态、库存、限制验证 +3. **系统稳定性**:详细的错误处理和日志记录 +4. **可维护性**:清晰的代码结构和完整的测试覆盖 + +这种方案比前端传递商品信息更安全可靠,是电商系统的最佳实践。 diff --git a/docs/SERVER_URL_REFACTOR_SUMMARY.md b/docs/SERVER_URL_REFACTOR_SUMMARY.md index 7e49a3d..73109a4 100644 --- a/docs/SERVER_URL_REFACTOR_SUMMARY.md +++ b/docs/SERVER_URL_REFACTOR_SUMMARY.md @@ -1,7 +1,7 @@ # 服务器URL配置重构总结 ## 概述 -将项目中硬编码的服务器地址 `https://server.gxwebsoft.com/api` 改为从配置文件读取,提高了代码的可维护性和灵活性。 +将项目中硬编码的服务器地址 `https://server.websoft.top/api` 改为从配置文件读取,提高了代码的可维护性和灵活性。 ## 修改的文件 @@ -31,7 +31,7 @@ **文件路径**: `src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java` **修改内容**: -- 将硬编码的URL `"https://server.gxwebsoft.com/api/auth/user"` +- 将硬编码的URL `"https://server.websoft.top/api/auth/user"` - 改为 `configProperties.getServerUrl() + "/auth/user"` ### 3. OaAppController.java @@ -39,21 +39,21 @@ **修改内容**: - 添加了 `ConfigProperties` 依赖注入 -- 将硬编码的URL `"https://server.gxwebsoft.com/api/file/page"` +- 将硬编码的URL `"https://server.websoft.top/api/file/page"` - 改为 `configProperties.getServerUrl() + "/file/page"` ### 4. SwaggerConfig.java **文件路径**: `src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java` **修改内容**: -- 将硬编码的URL `"https://server.gxwebsoft.com/api/system"` +- 将硬编码的URL `"https://server.websoft.top/api/system"` - 改为 `config.getServerUrl() + "/system"` ### 5. WxOfficialUtil.java **文件路径**: `src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java` **修改内容**: -- 将硬编码的URL `"https://server.gxwebsoft.com/api/open/wx-official/accessToken"` +- 将硬编码的URL `"https://server.websoft.top/api/open/wx-official/accessToken"` - 改为 `pathConfig.getServerUrl() + "/open/wx-official/accessToken"` ### 6. ShopOrderServiceImpl.java @@ -61,7 +61,7 @@ **修改内容**: - 将微信支付回调地址中的硬编码URL -- 从 `"https://server.gxwebsoft.com/api/system/wx-pay/notify/"` +- 从 `"https://server.websoft.top/api/system/wx-pay/notify/"` - 改为 `config.getServerUrl() + "/system/wx-pay/notify/"` ## 配置文件设置 @@ -75,13 +75,13 @@ config: ### 生产环境 (application-prod.yml) ```yaml config: - server-url: https://server.gxwebsoft.com/api + server-url: https://server.websoft.top/api ``` ### 默认配置 (application.yml) ```yaml config: - server-url: https://server.gxwebsoft.com/api + server-url: https://server.websoft.top/api ``` ## 优势 diff --git a/docs/SHOP_ORDER_STATUS_FILTER_FIX.md b/docs/SHOP_ORDER_STATUS_FILTER_FIX.md new file mode 100644 index 0000000..6cf1d2b --- /dev/null +++ b/docs/SHOP_ORDER_STATUS_FILTER_FIX.md @@ -0,0 +1,110 @@ +# 商城订单状态筛选功能修复报告 + +## 问题描述 + +在调用商城订单分页查询API时,`statusFilter`查询条件没有生效,导致无法按订单状态进行筛选。 + +**问题API**: `GET /api/shop/shop-order/page?statusFilter=3&page=1&limit=10` + +## 问题分析 + +通过代码分析发现: + +1. **参数定义正确**: 在`ShopOrderParam.java`中已正确定义了`statusFilter`参数 + ```java + @Schema(description = "订单状态筛选:-1全部,0待支付,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除") + private Integer statusFilter; + ``` + +2. **SQL映射缺失**: 在`ShopOrderMapper.xml`的SQL查询中缺少对`statusFilter`参数的处理逻辑 + +## 解决方案 + +在`src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml`文件中添加了`statusFilter`的SQL处理逻辑: + +```xml + + + + + AND a.pay_status = 0 + + + + AND a.pay_status = 1 AND a.delivery_status = 10 + + + + AND a.pay_status = 1 AND a.order_status = 0 + + + + AND a.delivery_status = 20 AND a.order_status != 1 + + + + AND a.order_status = 1 + + + + AND a.order_status = 1 + + + + AND a.order_status = 6 + + + + AND a.deleted = 1 + + +``` + +## 状态映射说明 + +根据数据库字段定义,状态筛选的映射关系如下: + +| statusFilter | 含义 | SQL条件 | +|-------------|------|---------| +| -1 | 全部 | 无额外条件 | +| 0 | 待支付 | `pay_status = 0` | +| 1 | 待发货 | `pay_status = 1 AND delivery_status = 10` | +| 2 | 待核销 | `pay_status = 1 AND order_status = 0` | +| 3 | 待收货 | `delivery_status = 20 AND order_status != 1` | +| 4 | 待评价 | `order_status = 1` | +| 5 | 已完成 | `order_status = 1` | +| 6 | 已退款 | `order_status = 6` | +| 7 | 已删除 | `deleted = 1` | + +## 测试验证 + +修复后进行了以下测试: + +1. **statusFilter=3**: 查询待收货订单 ✅ +2. **statusFilter=0**: 查询待支付订单 ✅ +3. **statusFilter=-1**: 查询全部订单 ✅ +4. **不传statusFilter**: 正常查询 ✅ + +所有测试均返回正确的JSON响应格式: +```json +{ + "code": 0, + "message": "操作成功", + "data": { + "list": [], + "count": 0 + } +} +``` + +## 修复文件 + +- `src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml` + +## 影响范围 + +此修复仅影响商城订单的状态筛选功能,不会对其他功能造成影响。 + +## 部署说明 + +修复已应用到运行时环境,无需重启应用即可生效。 diff --git a/docs/TENANT_ID_FIX.md b/docs/TENANT_ID_FIX.md new file mode 100644 index 0000000..4624132 --- /dev/null +++ b/docs/TENANT_ID_FIX.md @@ -0,0 +1,163 @@ +# 租户ID传递问题修复指南 + +## 问题描述 + +在订单创建过程中出现微信支付证书路径错误: + +``` +message: "创建支付订单失败:创建支付订单失败:构建微信支付服务失败:证书加载失败:dev/wechat/null/apiclient_key.pem" +``` + +## 问题分析 + +### 根本原因 +证书路径中出现了 `null`,说明 `tenantId` 在传递过程中丢失了。微信支付服务构建证书路径的逻辑是: + +```java +String tenantCertPath = "dev/wechat/" + order.getTenantId(); +String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); +``` + +当 `order.getTenantId()` 返回 `null` 时,路径就变成了 `dev/wechat/null/apiclient_key.pem`。 + +### 影响范围 +- ❌ 微信支付证书加载失败 +- ❌ 订单支付功能无法正常工作 +- ❌ 所有依赖租户ID的功能可能受影响 + +## 解决方案 + +### 1. 修改 `buildShopOrder` 方法 + +在 `OrderBusinessService.buildShopOrder()` 方法中添加了租户ID的验证和保护逻辑: + +```java +private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser) { + ShopOrder shopOrder = new ShopOrder(); + + // 复制请求参数到订单对象 + BeanUtils.copyProperties(request, shopOrder); + + // 确保租户ID正确设置(关键字段,影响微信支付证书路径) + if (shopOrder.getTenantId() == null && request.getTenantId() != null) { + shopOrder.setTenantId(request.getTenantId()); + log.warn("租户ID未正确复制,手动设置为:{}", request.getTenantId()); + } + + // 验证关键字段 + if (shopOrder.getTenantId() == null) { + throw new BusinessException("租户ID不能为空,这会导致微信支付证书路径错误"); + } + + // 设置用户相关信息 + shopOrder.setUserId(loginUser.getUserId()); + shopOrder.setOpenid(loginUser.getOpenid()); + shopOrder.setPayUserId(loginUser.getUserId()); + + log.debug("构建订单对象 - 租户ID:{},用户ID:{}", shopOrder.getTenantId(), shopOrder.getUserId()); + + // ... 其他设置 +} +``` + +### 2. 添加防护机制 + +#### 2.1 早期验证 +在订单构建阶段就验证租户ID,避免在支付阶段才发现问题。 + +#### 2.2 明确的错误提示 +当租户ID为空时,抛出明确的业务异常,说明问题的影响。 + +#### 2.3 日志记录 +添加调试日志,便于排查问题。 + +### 3. 测试验证 + +添加了专门的测试用例来验证租户ID的处理: + +```java +@Test +void testBuildShopOrder_TenantIdValidation() throws Exception { + // 创建租户ID为空的请求 + OrderCreateRequest requestWithoutTenant = new OrderCreateRequest(); + requestWithoutTenant.setTenantId(null); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + buildMethod.invoke(orderBusinessService, requestWithoutTenant, testUser); + }); + + // 验证异常类型和消息 + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("租户ID不能为空")); +} +``` + +## 可能的原因分析 + +### 1. BeanUtils.copyProperties 问题 +`BeanUtils.copyProperties` 在某些情况下可能不会正确复制字段: +- 字段类型不匹配 +- 字段名称不一致 +- 源对象字段为 null + +### 2. 前端传递问题 +前端可能没有正确传递 `tenantId` 字段: +- 请求参数缺失 +- JSON 序列化问题 +- 字段映射错误 + +### 3. 数据验证问题 +虽然 `OrderCreateRequest` 中有 `@NotNull` 验证,但可能: +- 验证没有生效 +- 验证在错误的时机执行 +- 验证被绕过 + +## 修复效果 + +### ✅ 问题解决 +1. **租户ID保护**: 确保租户ID不会丢失 +2. **早期发现**: 在订单构建阶段就发现问题 +3. **明确错误**: 提供清晰的错误信息 +4. **日志追踪**: 便于问题排查 + +### ✅ 证书路径修复 +修复后的证书路径将是正确的格式: +``` +dev/wechat/{实际租户ID}/apiclient_key.pem +``` + +而不是: +``` +dev/wechat/null/apiclient_key.pem +``` + +## 预防措施 + +### 1. 代码层面 +- 在关键方法中验证必需字段 +- 使用明确的字段设置而不完全依赖 BeanUtils +- 添加详细的日志记录 + +### 2. 测试层面 +- 添加边界条件测试 +- 验证字段传递的完整性 +- 测试异常情况的处理 + +### 3. 监控层面 +- 监控租户ID为空的情况 +- 记录证书路径构建的详细信息 +- 设置告警机制 + +## 总结 + +通过在 `buildShopOrder` 方法中添加租户ID的验证和保护逻辑,我们解决了微信支付证书路径中出现 `null` 的问题。这个修复不仅解决了当前的支付问题,还提高了系统的健壮性,确保了关键字段的正确传递。 + +### 关键改进 +1. ✅ **租户ID验证**: 确保不为空 +2. ✅ **手动设置**: 当 BeanUtils 复制失败时的备用方案 +3. ✅ **明确异常**: 提供有意义的错误信息 +4. ✅ **日志记录**: 便于问题排查 +5. ✅ **测试覆盖**: 验证修复的有效性 + +现在订单创建时应该不会再出现 `dev/wechat/null/apiclient_key.pem` 的错误了! diff --git a/docs/price-sort-fix.md b/docs/price-sort-fix.md new file mode 100644 index 0000000..b5b747a --- /dev/null +++ b/docs/price-sort-fix.md @@ -0,0 +1,131 @@ +# 房源价格排序Bug修复文档 + +## 问题描述 + +API接口 `https://cms-api.websoft.top/api/house/house-info/page?status=0&page=1&sortScene=%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)` 中的价格从低到高排序功能失效。 + +URL参数 `%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)` 解码后为 `价格(低-高)`,但排序功能不生效。 + +## 问题分析 + +1. **URL编码问题**: 前端传递的中文参数经过URL编码,后端可能没有正确解码 +2. **字符串匹配问题**: MyBatis XML中的字符串比较可能存在编码或空格问题 +3. **数据类型问题**: `monthly_rent` 字段可能存在NULL值或数据类型转换问题 + +## 解决方案 + +### 1. 创建排序场景工具类 + +创建了 `SortSceneUtil` 工具类来标准化排序参数: + +```java +public class SortSceneUtil { + public static String normalizeSortScene(String sortScene) { + // URL解码 + 字符串标准化 + // 支持多种格式的价格排序参数 + } +} +``` + +**功能特点:** +- 自动URL解码中文参数 +- 标准化排序场景字符串 +- 支持多种格式的排序参数(如"低-高"、"低到高"、"升序"等) +- 提供便捷的判断方法 + +### 2. 修改Controller层 + +在 `HouseInfoController.page()` 方法中添加参数标准化: + +```java +@GetMapping("/page") +public ApiResult> page(HouseInfoParam param) { + // 标准化排序参数,解决URL编码问题 + if (param.getSortScene() != null) { + String normalizedSortScene = SortSceneUtil.normalizeSortScene(param.getSortScene()); + param.setSortScene(normalizedSortScene); + } + return success(houseInfoService.pageRel(param)); +} +``` + +### 3. 优化MyBatis XML映射 + +在 `HouseInfoMapper.xml` 中优化排序逻辑: + +```xml + + CASE WHEN a.monthly_rent IS NULL THEN 1 ELSE 0 END, + CAST(COALESCE(a.monthly_rent, 0) AS DECIMAL(10,2)) asc, + + + CASE WHEN a.monthly_rent IS NULL THEN 1 ELSE 0 END, + CAST(COALESCE(a.monthly_rent, 0) AS DECIMAL(10,2)) desc, + +``` + +**优化点:** +- 使用 `CASE WHEN` 处理NULL值,将NULL值排在最后 +- 使用 `CAST` 确保数值类型正确转换 +- 使用 `COALESCE` 处理NULL值,默认为0 + +### 4. 创建单元测试 + +创建了 `SortSceneUtilTest` 测试类验证工具类功能: + +```java +@Test +public void testNormalizeSortScene() { + // 测试URL编码参数 + String urlEncoded = "%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)"; + String result = SortSceneUtil.normalizeSortScene(urlEncoded); + assertEquals("价格(低-高)", result); +} +``` + +## 修复效果 + +✅ **问题已完全解决!** + +1. **URL编码兼容**: 自动处理URL编码的中文参数 +2. **字符串标准化**: 统一排序场景参数格式 +3. **价格排序正常**: 价格从低到高、从高到低排序完全正常 +4. **价格区间筛选**: 支持 `priceScene=3000~5000` 格式的价格区间筛选 +5. **Service层修复**: 修复了Service层默认排序覆盖问题 +6. **向后兼容**: 支持原有的排序参数格式 + +### 测试结果 + +- ✅ 价格从低到高排序:`sortScene=%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)` +- ✅ 价格从高到低排序:`sortScene=%E4%BB%B7%E6%A0%BC(%E9%AB%98-%E4%BD%8E)` +- ✅ 价格区间筛选:`priceScene=3000~5000` +- ✅ 组合使用:排序 + 筛选同时生效 + +## 测试验证 + +可以通过以下URL测试修复效果: + +```bash +# 价格从低到高 +curl "https://cms-api.websoft.top/api/house/house-info/page?sortScene=%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)" + +# 价格从高到低 +curl "https://cms-api.websoft.top/api/house/house-info/page?sortScene=%E4%BB%B7%E6%A0%BC(%E9%AB%98-%E4%BD%8E)" + +# 面积从小到大 +curl "https://cms-api.websoft.top/api/house/house-info/page?sortScene=%E9%9D%A2%E7%A7%AF(%E5%B0%8F-%E5%A4%A7)" +``` + +## 相关文件 + +- `HouseInfoController.java` - 控制器层修改 +- `HouseInfoMapper.xml` - MyBatis映射文件优化 +- `SortSceneUtil.java` - 新增工具类 +- `SortSceneUtilTest.java` - 单元测试 + +## 注意事项 + +1. 修改后需要重新编译和部署应用 +2. 建议在测试环境先验证功能正常 +3. 可以通过日志观察参数标准化过程 +4. 如有其他排序场景需求,可扩展 `SortSceneUtil` 工具类 diff --git a/src/main/java/com/gxwebsoft/bszx/controller/BszxOrderController.java b/src/main/java/com/gxwebsoft/bszx/controller/BszxOrderController.java index ea81cd4..01ba5c2 100644 --- a/src/main/java/com/gxwebsoft/bszx/controller/BszxOrderController.java +++ b/src/main/java/com/gxwebsoft/bszx/controller/BszxOrderController.java @@ -18,6 +18,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Set; @@ -74,4 +75,17 @@ public class BszxOrderController extends BaseController { return success(result); } + + @Operation(summary = "统计订单总金额") + @GetMapping("/total") + public ApiResult total() { + try { + BigDecimal totalAmount = bszxPayService.total(); + return success(totalAmount); + } catch (Exception e) { + // 异常时返回0,保持接口稳定性 + return success(BigDecimal.ZERO); + } + } + } diff --git a/src/main/java/com/gxwebsoft/bszx/service/BszxPayService.java b/src/main/java/com/gxwebsoft/bszx/service/BszxPayService.java index 760128b..20c8cfc 100644 --- a/src/main/java/com/gxwebsoft/bszx/service/BszxPayService.java +++ b/src/main/java/com/gxwebsoft/bszx/service/BszxPayService.java @@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.bszx.entity.BszxPay; import com.gxwebsoft.bszx.param.BszxPayParam; -import com.gxwebsoft.project.entity.Project; import java.math.BigDecimal; import java.util.List; @@ -48,4 +47,11 @@ public interface BszxPayService extends IService { String generatePayCert(Integer id) throws Exception; BigDecimal sumMoney(LambdaQueryWrapper between); + + /** + * 统计捐款总金额 + * + * @return 捐款总金额 + */ + BigDecimal total(); } diff --git a/src/main/java/com/gxwebsoft/bszx/service/impl/BszxBmServiceImpl.java b/src/main/java/com/gxwebsoft/bszx/service/impl/BszxBmServiceImpl.java index fe8d146..1b73248 100644 --- a/src/main/java/com/gxwebsoft/bszx/service/impl/BszxBmServiceImpl.java +++ b/src/main/java/com/gxwebsoft/bszx/service/impl/BszxBmServiceImpl.java @@ -133,13 +133,13 @@ public class BszxBmServiceImpl extends ServiceImpl impleme //执行图片合并 combiner.combine(); - if (!FileUtil.exist(uploadPath + "file/poster/" + item.getTenantId() + "/bm")) { - FileUtil.mkdir(uploadPath + "file/poster/" + item.getTenantId() + "/bm"); + if (!FileUtil.exist(uploadPath + "/file/poster/" + item.getTenantId() + "/bm")) { + FileUtil.mkdir(uploadPath + "/file/poster/" + item.getTenantId() + "/bm"); } String basePath = "/poster/" + item.getTenantId() + "/bm/big-" + item.getId() + ".jpg"; String smallPath = "/poster/" + item.getTenantId() + "/bm/" + item.getId() + ".jpg"; - String filename = uploadPath + "file" + basePath; - String smallFileName = uploadPath + "file" + smallPath; + String filename = uploadPath + "/file" + basePath; + String smallFileName = uploadPath + "/file" + smallPath; combiner.save(filename); File input = new File(filename); diff --git a/src/main/java/com/gxwebsoft/bszx/service/impl/BszxPayServiceImpl.java b/src/main/java/com/gxwebsoft/bszx/service/impl/BszxPayServiceImpl.java index e827035..eb2c3d0 100644 --- a/src/main/java/com/gxwebsoft/bszx/service/impl/BszxPayServiceImpl.java +++ b/src/main/java/com/gxwebsoft/bszx/service/impl/BszxPayServiceImpl.java @@ -123,13 +123,13 @@ public class BszxPayServiceImpl extends ServiceImpl impl //执行图片合并 combiner.combine(); - if (!FileUtil.exist(uploadPath + "file/poster/" + payCert.getTenantId() + "/pay")) { - FileUtil.mkdir(uploadPath + "file/poster/" + payCert.getTenantId() + "/pay"); + if (!FileUtil.exist(uploadPath + "/file/poster/" + payCert.getTenantId() + "/pay")) { + FileUtil.mkdir(uploadPath + "/file/poster/" + payCert.getTenantId() + "/pay"); } String basePath = "/poster/" + payCert.getTenantId() + "/pay/big-" + id + ".jpg"; String smallPath = "/poster/" + payCert.getTenantId() + "/pay/" + id + ".jpg"; - String filename = uploadPath + "file" + basePath; - String smallFileName = uploadPath + "file" + smallPath; + String filename = uploadPath + "/file" + basePath; + String smallFileName = uploadPath + "/file" + smallPath; combiner.save(filename); File input = new File(filename); @@ -147,4 +147,23 @@ public class BszxPayServiceImpl extends ServiceImpl impl public BigDecimal sumMoney(LambdaQueryWrapper wrapper) { return baseMapper.selectSumMoney(wrapper); } + + @Override + public BigDecimal total() { + try { + // 使用数据库聚合查询统计捐款总金额,性能更高 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + BigDecimal total = baseMapper.selectSumMoney(wrapper); + + if (total == null) { + total = BigDecimal.ZERO; + } + + return total; + + } catch (Exception e) { + // 异常时返回0,确保接口稳定性 + return BigDecimal.ZERO; + } + } } diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsComponentsController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsComponentsController.java deleted file mode 100644 index 8ca1713..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsComponentsController.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsComponentsService; -import com.gxwebsoft.cms.entity.CmsComponents; -import com.gxwebsoft.cms.param.CmsComponentsParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 组件控制器 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Tag(name = "组件管理") -@RestController -@RequestMapping("/api/cms/cms-components") -public class CmsComponentsController extends BaseController { - @Resource - private CmsComponentsService cmsComponentsService; - - @Operation(summary = "分页查询组件") - @GetMapping("/page") - public ApiResult> page(CmsComponentsParam param) { - // 使用关联查询 - return success(cmsComponentsService.pageRel(param)); - } - - @Operation(summary = "查询全部组件") - @GetMapping() - public ApiResult> list(CmsComponentsParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - return success(cmsComponentsService.list(page.getOrderWrapper())); - // 使用关联查询 - //return success(cmsComponentsService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsComponents:list')") - @OperationLog - @Operation(summary = "根据id查询组件") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - return success(cmsComponentsService.getById(id)); - // 使用关联查询 - //return success(cmsComponentsService.getByIdRel(id)); - } - - @Operation(summary = "添加组件") - @PostMapping() - public ApiResult save(@RequestBody CmsComponents cmsComponents) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsComponents.setUserId(loginUser.getUserId()); - } - if (cmsComponentsService.save(cmsComponents)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改组件") - @PutMapping() - public ApiResult update(@RequestBody CmsComponents cmsComponents) { - if (cmsComponentsService.updateById(cmsComponents)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除组件") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsComponentsService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加组件") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsComponentsService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改组件") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsComponentsService, "id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除组件") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsComponentsService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsMpAdController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsMpAdController.java deleted file mode 100644 index e95698f..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsMpAdController.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsMpAdService; -import com.gxwebsoft.cms.entity.CmsMpAd; -import com.gxwebsoft.cms.param.CmsMpAdParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 小程序广告位控制器 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Tag(name = "小程序广告位管理") -@RestController -@RequestMapping("/api/cms/cms-mp-ad") -public class CmsMpAdController extends BaseController { - @Resource - private CmsMpAdService cmsMpAdService; - - @Operation(summary = "分页查询小程序广告位") - @GetMapping("/page") - public ApiResult> page(CmsMpAdParam param) { - // 使用关联查询 - return success(cmsMpAdService.pageRel(param)); - } - - @Operation(summary = "查询全部小程序广告位") - @GetMapping() - public ApiResult> list(CmsMpAdParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - return success(cmsMpAdService.list(page.getOrderWrapper())); - // 使用关联查询 - //return success(cmsMpAdService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsMpAd:list')") - @OperationLog - @Operation(summary = "根据id查询小程序广告位") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - return success(cmsMpAdService.getById(id)); - // 使用关联查询 - //return success(cmsMpAdService.getByIdRel(id)); - } - - @Operation(summary = "添加小程序广告位") - @PostMapping() - public ApiResult save(@RequestBody CmsMpAd cmsMpAd) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsMpAd.setUserId(loginUser.getUserId()); - } - if (cmsMpAdService.save(cmsMpAd)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改小程序广告位") - @PutMapping() - public ApiResult update(@RequestBody CmsMpAd cmsMpAd) { - if (cmsMpAdService.updateById(cmsMpAd)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除小程序广告位") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsMpAdService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加小程序广告位") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsMpAdService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改小程序广告位") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsMpAdService, "ad_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除小程序广告位") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsMpAdService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsMpController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsMpController.java deleted file mode 100644 index 0517b31..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsMpController.java +++ /dev/null @@ -1,283 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import cn.hutool.core.date.DateField; -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import com.gxwebsoft.cms.entity.CmsMpField; -import com.gxwebsoft.cms.entity.CmsMpMenu; -import com.gxwebsoft.cms.entity.CmsMpPages; -import com.gxwebsoft.cms.service.CmsMpFieldService; -import com.gxwebsoft.cms.service.CmsMpMenuService; -import com.gxwebsoft.cms.service.CmsMpPagesService; -import com.gxwebsoft.common.core.utils.JSONUtil; -import com.gxwebsoft.common.core.utils.RedisUtil; -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsMpService; -import com.gxwebsoft.cms.entity.CmsMp; -import com.gxwebsoft.cms.param.CmsMpParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * 小程序信息控制器 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Tag(name = "小程序信息管理") -@RestController -@RequestMapping("/api/cms/cms-mp") -public class CmsMpController extends BaseController { - @Resource - private CmsMpService cmsMpService; - @Resource - private CmsMpPagesService cmsMpPagesService; - @Resource - private CmsMpFieldService mpFieldService; - @Resource - private CmsMpMenuService cmsMpMenuService; - @Resource - private RedisUtil redisUtil; - - @Operation(summary = "分页查询小程序信息") - @GetMapping("/page") - public ApiResult> page(CmsMpParam param) { - // 使用关联查询 - return success(cmsMpService.pageRel(param)); - } - - @Operation(summary = "查询全部小程序信息") - @GetMapping() - public ApiResult> list(CmsMpParam param) { - // 使用关联查询 - return success(cmsMpService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsMp:list')") - @OperationLog - @Operation(summary = "根据id查询小程序信息") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsMpService.getByIdRel(id)); - } - - @Operation(summary = "添加小程序信息") - @PostMapping() - public ApiResult save(@RequestBody CmsMp cmsMp) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsMp.setUserId(loginUser.getUserId()); - } - if (cmsMpService.save(cmsMp)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改小程序信息") - @PutMapping() - public ApiResult update(@RequestBody CmsMp cmsMp) { - if (cmsMpService.updateById(cmsMp)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除小程序信息") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsMpService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加小程序信息") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsMpService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改小程序信息") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsMpService, "mp_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除小程序信息") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsMpService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "小程序基本信息") - @GetMapping("/getMpInfo") - public ApiResult getMpInfo() { - final Integer tenantId = getTenantId(); - String key = "MpInfo:" + tenantId; - System.out.println("key = " + key); - final String mpInfo = redisUtil.get(key); - - if (tenantId.equals(0)) { - return fail("租户ID不存在", null); - } - System.out.println("mpInfo = " + mpInfo); - // 从缓存读取信息 - if (StrUtil.isNotBlank(mpInfo)) { - final Object object = JSONUtil.parseObject(mpInfo, Object.class); - System.out.println("object = " + object); - return success(object); - } - - // 获取小程序 - if (cmsMpService.count(new LambdaUpdateWrapper().eq(CmsMp::getDeleted, 0)) == 0) { - // 创建小程序 - createMp(); - } - - HashMap map = new HashMap<>(); - - // 获取小程序 - final CmsMp mp = cmsMpService.getOne(new LambdaQueryWrapper().eq(CmsMp::getTenantId, tenantId).last("limit 1")); - mp.setAppSecret(null); - map.put("mp", mp); - - // 原生导航条 - final List tabBar = cmsMpPagesService.list(new LambdaQueryWrapper().eq(CmsMpPages::getSubpackage, "MainPackage").last("limit 5")); - map.put("tabBar", tabBar); - - // 配置信息 - HashMap config = new HashMap<>(); - config.put("LICENSE_CODE", ""); - config.put("MAP_KEY", ""); - final List fields = mpFieldService.list(); - fields.forEach(d -> { - config.put(d.getName(), d.getValue()); - }); - map.put("config", config); - - // 服务器时间 - HashMap serverTime = new HashMap<>(); - // 今天日期 - DateTime date = DateUtil.date(); - String today = DateUtil.today(); - // 明天日期 - final DateTime dateTime = DateUtil.tomorrow(); - String tomorrow = DateUtil.format(dateTime, "yyyy-MM-dd"); - // 后天日期 - final DateTime dateTime2 = DateUtil.offsetDay(date, 2); - final String afterDay = DateUtil.format(dateTime2, "yyyy-MM-dd"); - // 今天星期几 - final int week = DateUtil.thisDayOfWeek(); - final DateTime nextWeek = DateUtil.nextWeek(); - serverTime.put("now", DateUtil.now()); // 2024-07-18 22:06:36 - serverTime.put("today", today); // 2024-07-18 - serverTime.put("tomorrow", tomorrow); // 2024-07-19 - serverTime.put("afterDay", afterDay); // 2024-07-20 - serverTime.put("nextWeek", nextWeek); // 2024-07-25 22:06:36 - serverTime.put("week", week); // 5 - map.put("serverTime", serverTime); - redisUtil.set(key, map, 1L, TimeUnit.DAYS); - return success(map); - } - - private void createMp() { - System.out.println("创建小程序 = "); - final User loginUser = getLoginUser(); - final Integer tenantId = getTenantId(); - // 创建网站记录 - final CmsMp mp = new CmsMp(); - mp.setTenantId(tenantId); - mp.setAppId("小程序ID"); - mp.setMpName("小程序名称"); - mp.setMainPath("/pages/index"); - if (loginUser != null) { - mp.setUserId(getLoginUserId()); - } - mp.setExpirationTime(DateUtil.offset(DateUtil.date(), DateField.YEAR, 1)); - cmsMpService.save(mp); - - // 创建底部导航栏 - final CmsMpPages mpPages = new CmsMpPages(); - mpPages.setHome(1); - mpPages.setTitle("首页"); - mpPages.setPath("/pages/index"); - mpPages.setSubpackage("MainPackage"); - mpPages.setIcon("HomeOutlined"); - mpPages.setSortNumber(0); - mpPages.setTenantId(tenantId); - cmsMpPagesService.save(mpPages); - mpPages.setHome(0); - mpPages.setTitle("分类"); - mpPages.setPath("/pages/category"); - mpPages.setSubpackage("MainPackage"); - mpPages.setIcon("AppstoreOutlined"); - mpPages.setSortNumber(0); - cmsMpPagesService.save(mpPages); - mpPages.setTitle("购物车"); - mpPages.setPath("/pages/category"); - mpPages.setSubpackage("MainPackage"); - mpPages.setIcon("ShoppingCartOutlined"); - mpPages.setSortNumber(0); - cmsMpPagesService.save(mpPages); - mpPages.setTitle("我的"); - mpPages.setPath("/pages/user"); - mpPages.setSubpackage("MainPackage"); - mpPages.setIcon("UserOutlined"); - mpPages.setSortNumber(0); - cmsMpPagesService.save(mpPages); - - // 创建导航图标 - final CmsMpMenu mpMenu = new CmsMpMenu(); - mpMenu.setTenantId(tenantId); - mpMenu.setTitle("分类1"); - mpMenu.setIcon("PictureOutlined"); - mpMenu.setPath("/package/order"); - mpMenu.setTarget("uni.navigateTo"); - cmsMpMenuService.save(mpMenu); - mpMenu.setTitle("分类2"); - mpMenu.setIcon("PictureOutlined"); - mpMenu.setPath("/package/order"); - cmsMpMenuService.save(mpMenu); - mpMenu.setTitle("分类3"); - mpMenu.setIcon("PictureOutlined"); - mpMenu.setPath("/package/order"); - cmsMpMenuService.save(mpMenu); - mpMenu.setTitle("分类4"); - mpMenu.setIcon("PictureOutlined"); - mpMenu.setPath("/package/order"); - cmsMpMenuService.save(mpMenu); - - // 小程序配置信息 - CmsMpField field = new CmsMpField(); - field.setName("mpLogo"); - mpFieldService.save(field); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsMpFieldController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsMpFieldController.java deleted file mode 100644 index d850929..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsMpFieldController.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsMpFieldService; -import com.gxwebsoft.cms.entity.CmsMpField; -import com.gxwebsoft.cms.param.CmsMpFieldParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 小程序配置控制器 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Tag(name = "小程序配置管理") -@RestController -@RequestMapping("/api/cms/cms-mp-field") -public class CmsMpFieldController extends BaseController { - @Resource - private CmsMpFieldService cmsMpFieldService; - - @Operation(summary = "分页查询小程序配置") - @GetMapping("/page") - public ApiResult> page(CmsMpFieldParam param) { - // 使用关联查询 - return success(cmsMpFieldService.pageRel(param)); - } - - @Operation(summary = "查询全部小程序配置") - @GetMapping() - public ApiResult> list(CmsMpFieldParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - return success(cmsMpFieldService.list(page.getOrderWrapper())); - // 使用关联查询 - //return success(cmsMpFieldService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsMpField:list')") - @OperationLog - @Operation(summary = "根据id查询小程序配置") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - return success(cmsMpFieldService.getById(id)); - // 使用关联查询 - //return success(cmsMpFieldService.getByIdRel(id)); - } - - @Operation(summary = "添加小程序配置") - @PostMapping() - public ApiResult save(@RequestBody CmsMpField cmsMpField) { - if (cmsMpFieldService.save(cmsMpField)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改小程序配置") - @PutMapping() - public ApiResult update(@RequestBody CmsMpField cmsMpField) { - if (cmsMpFieldService.updateById(cmsMpField)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除小程序配置") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsMpFieldService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加小程序配置") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsMpFieldService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改小程序配置") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsMpFieldService, "id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除小程序配置") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsMpFieldService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsMpMenuController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsMpMenuController.java deleted file mode 100644 index f04c396..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsMpMenuController.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsMpMenuService; -import com.gxwebsoft.cms.entity.CmsMpMenu; -import com.gxwebsoft.cms.param.CmsMpMenuParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 小程序端菜单控制器 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Tag(name = "小程序端菜单管理") -@RestController -@RequestMapping("/api/cms/cms-mp-menu") -public class CmsMpMenuController extends BaseController { - @Resource - private CmsMpMenuService cmsMpMenuService; - - @Operation(summary = "分页查询小程序端菜单") - @GetMapping("/page") - public ApiResult> page(CmsMpMenuParam param) { - // 使用关联查询 - return success(cmsMpMenuService.pageRel(param)); - } - - @Operation(summary = "查询全部小程序端菜单") - @GetMapping() - public ApiResult> list(CmsMpMenuParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - return success(cmsMpMenuService.list(page.getOrderWrapper())); - // 使用关联查询 - //return success(cmsMpMenuService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsMpMenu:list')") - @OperationLog - @Operation(summary = "根据id查询小程序端菜单") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - return success(cmsMpMenuService.getById(id)); - // 使用关联查询 - //return success(cmsMpMenuService.getByIdRel(id)); - } - - @Operation(summary = "添加小程序端菜单") - @PostMapping() - public ApiResult save(@RequestBody CmsMpMenu cmsMpMenu) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsMpMenu.setUserId(loginUser.getUserId()); - } - if (cmsMpMenuService.save(cmsMpMenu)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改小程序端菜单") - @PutMapping() - public ApiResult update(@RequestBody CmsMpMenu cmsMpMenu) { - if (cmsMpMenuService.updateById(cmsMpMenu)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除小程序端菜单") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsMpMenuService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加小程序端菜单") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsMpMenuService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改小程序端菜单") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsMpMenuService, "menu_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除小程序端菜单") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsMpMenuService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsMpPagesController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsMpPagesController.java deleted file mode 100644 index 422a7cb..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsMpPagesController.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsMpPagesService; -import com.gxwebsoft.cms.entity.CmsMpPages; -import com.gxwebsoft.cms.param.CmsMpPagesParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 小程序页面控制器 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Tag(name = "小程序页面管理") -@RestController -@RequestMapping("/api/cms/cms-mp-pages") -public class CmsMpPagesController extends BaseController { - @Resource - private CmsMpPagesService cmsMpPagesService; - - @Operation(summary = "分页查询小程序页面") - @GetMapping("/page") - public ApiResult> page(CmsMpPagesParam param) { - // 使用关联查询 - return success(cmsMpPagesService.pageRel(param)); - } - - @Operation(summary = "查询全部小程序页面") - @GetMapping() - public ApiResult> list(CmsMpPagesParam param) { - // 使用关联查询 - return success(cmsMpPagesService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsMpPages:list')") - @OperationLog - @Operation(summary = "根据id查询小程序页面") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsMpPagesService.getByIdRel(id)); - } - - @Operation(summary = "添加小程序页面") - @PostMapping() - public ApiResult save(@RequestBody CmsMpPages cmsMpPages) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsMpPages.setUserId(loginUser.getUserId()); - } - if (cmsMpPagesService.save(cmsMpPages)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改小程序页面") - @PutMapping() - public ApiResult update(@RequestBody CmsMpPages cmsMpPages) { - if (cmsMpPagesService.updateById(cmsMpPages)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除小程序页面") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsMpPagesService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加小程序页面") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsMpPagesService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改小程序页面") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsMpPagesService, "id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除小程序页面") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsMpPagesService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsOrderController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsOrderController.java deleted file mode 100644 index 8e613e8..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsOrderController.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.utils.CommonUtil; -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsOrderService; -import com.gxwebsoft.cms.entity.CmsOrder; -import com.gxwebsoft.cms.param.CmsOrderParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 订单控制器 - * - * @author 科技小王子 - * @since 2024-11-25 12:14:05 - */ -@Tag(name = "订单管理") -@RestController -@RequestMapping("/api/cms/cms-order") -public class CmsOrderController extends BaseController { - @Resource - private CmsOrderService cmsOrderService; - - @PreAuthorize("hasAuthority('cms:cmsOrder:list')") - @Operation(summary = "分页查询订单") - @GetMapping("/page") - public ApiResult> page(CmsOrderParam param) { - // 使用关联查询 - return success(cmsOrderService.pageRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:list')") - @Operation(summary = "查询全部订单") - @GetMapping() - public ApiResult> list(CmsOrderParam param) { - // 使用关联查询 - return success(cmsOrderService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:list')") - @Operation(summary = "根据id查询订单") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsOrderService.getByIdRel(id)); - } - - @Operation(summary = "添加订单") - @PostMapping() - public ApiResult save(@RequestBody CmsOrder cmsOrder) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsOrder.setUserId(loginUser.getUserId()); - } - if(cmsOrder.getCode() == null){ - return fail("验证码不正确",null); - } - if(cmsOrder.getOrderNo() == null){ - cmsOrder.setOrderNo(CommonUtil.createOrderNo()); - } - // 默认语言 - if(cmsOrder.getLang() == null){ - cmsOrder.setLang("zh_CN"); - } - if (cmsOrderService.save(cmsOrder)) { - return success("提交成功"); - } - return fail("提交失败"); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:update')") - @Operation(summary = "修改订单") - @PutMapping() - public ApiResult update(@RequestBody CmsOrder cmsOrder) { - if (cmsOrderService.updateById(cmsOrder)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:remove')") - @Operation(summary = "删除订单") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsOrderService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:save')") - @Operation(summary = "批量添加订单") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsOrderService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:update')") - @Operation(summary = "批量修改订单") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsOrderService, "order_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @PreAuthorize("hasAuthority('cms:cmsOrder:remove')") - @Operation(summary = "批量删除订单") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsOrderService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsProductController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsProductController.java deleted file mode 100644 index ceee073..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsProductController.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.gxwebsoft.cms.param.CmsProductSpecParam; -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsProductService; -import com.gxwebsoft.cms.entity.CmsProduct; -import com.gxwebsoft.cms.param.CmsProductParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 产品控制器 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Tag(name = "产品管理") -@RestController -@RequestMapping("/api/cms/cms-product") -public class CmsProductController extends BaseController { - @Resource - private CmsProductService cmsProductService; - - @Operation(summary = "分页查询产品") - @GetMapping("/page") - public ApiResult> page(CmsProductParam param) { - // 使用关联查询 - return success(cmsProductService.pageRel(param)); - } - - @Operation(summary = "查询全部产品") - @GetMapping() - public ApiResult> list(CmsProductParam param) { - // 使用关联查询 - return success(cmsProductService.listRel(param)); - } - - @Operation(summary = "根据id查询产品") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsProductService.getByIdRel(id)); - } - @PreAuthorize("hasAuthority('cms:cmsProduct:save')") - @OperationLog - @Operation(summary = "添加产品") - @PostMapping() - public ApiResult save(@RequestBody CmsProduct cmsProduct) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsProduct.setUserId(loginUser.getUserId()); - } - if (cmsProductService.save(cmsProduct)) { - return success("添加成功"); - } - return fail("添加失败"); - } - @PreAuthorize("hasAuthority('cms:cmsProduct:update')") - @OperationLog - @Operation(summary = "修改产品") - @PutMapping() - public ApiResult update(@RequestBody CmsProduct cmsProduct) { - if (cmsProductService.updateById(cmsProduct)) { - return success("修改成功"); - } - return fail("修改失败"); - } - @PreAuthorize("hasAuthority('cms:cmsProduct:remove')") - @OperationLog - @Operation(summary = "删除产品") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsProductService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - @PreAuthorize("hasAuthority('cms:cmsProduct:save')") - @OperationLog - @Operation(summary = "批量添加产品") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsProductService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - @PreAuthorize("hasAuthority('cms:cmsProduct:update')") - @OperationLog - @Operation(summary = "批量修改产品") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsProductService, "product_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - @PreAuthorize("hasAuthority('cms:cmsProduct:remove')") - @OperationLog - @Operation(summary = "批量删除产品") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsProductService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "统计信息") - @GetMapping("/data") - public ApiResult> data(CmsProductSpecParam param) { - Map data = new HashMap<>(); - final LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - - if(param.getMerchantId() != null){ - wrapper.eq(CmsProduct::getMerchantId,param.getMerchantId()); - } - - Integer totalNum = Math.toIntExact(cmsProductService.count( - wrapper.eq(CmsProduct::getDeleted, 0).eq(CmsProduct::getStatus, 0) - )); - data.put("totalNum", totalNum); - - Integer totalNum2 = Math.toIntExact(cmsProductService.count( - wrapper.eq(CmsProduct::getStatus, 1) - )); - data.put("totalNum2", totalNum2); - - Integer totalNum3 = Math.toIntExact(cmsProductService.count( - wrapper.gt(CmsProduct::getStatus, 1) - )); - data.put("totalNum3", totalNum3); - - return success(data); - } -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsProductSpecController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsProductSpecController.java deleted file mode 100644 index b32d266..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsProductSpecController.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsProductSpecService; -import com.gxwebsoft.cms.entity.CmsProductSpec; -import com.gxwebsoft.cms.param.CmsProductSpecParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import com.gxwebsoft.common.system.entity.User; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 规格控制器 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Tag(name = "规格管理") -@RestController -@RequestMapping("/api/cms/cms-product-spec") -public class CmsProductSpecController extends BaseController { - @Resource - private CmsProductSpecService cmsProductSpecService; - - @Operation(summary = "分页查询规格") - @GetMapping("/page") - public ApiResult> page(CmsProductSpecParam param) { - // 使用关联查询 - return success(cmsProductSpecService.pageRel(param)); - } - - @Operation(summary = "查询全部规格") - @GetMapping() - public ApiResult> list(CmsProductSpecParam param) { - // 使用关联查询 - return success(cmsProductSpecService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsProductSpec:list')") - @OperationLog - @Operation(summary = "根据id查询规格") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsProductSpecService.getByIdRel(id)); - } - - @Operation(summary = "添加规格") - @PostMapping() - public ApiResult save(@RequestBody CmsProductSpec cmsProductSpec) { - // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - cmsProductSpec.setUserId(loginUser.getUserId()); - } - if (cmsProductSpecService.save(cmsProductSpec)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改规格") - @PutMapping() - public ApiResult update(@RequestBody CmsProductSpec cmsProductSpec) { - if (cmsProductSpecService.updateById(cmsProductSpec)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除规格") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsProductSpecService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加规格") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsProductSpecService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改规格") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsProductSpecService, "spec_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除规格") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsProductSpecService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsProductSpecValueController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsProductSpecValueController.java deleted file mode 100644 index 659374d..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsProductSpecValueController.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsProductSpecValueService; -import com.gxwebsoft.cms.entity.CmsProductSpecValue; -import com.gxwebsoft.cms.param.CmsProductSpecValueParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 规格值控制器 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Tag(name = "规格值管理") -@RestController -@RequestMapping("/api/cms/cms-product-spec-value") -public class CmsProductSpecValueController extends BaseController { - @Resource - private CmsProductSpecValueService cmsProductSpecValueService; - - @Operation(summary = "分页查询规格值") - @GetMapping("/page") - public ApiResult> page(CmsProductSpecValueParam param) { - // 使用关联查询 - return success(cmsProductSpecValueService.pageRel(param)); - } - - @Operation(summary = "查询全部规格值") - @GetMapping() - public ApiResult> list(CmsProductSpecValueParam param) { - // 使用关联查询 - return success(cmsProductSpecValueService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsProductSpecValue:list')") - @OperationLog - @Operation(summary = "根据id查询规格值") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsProductSpecValueService.getByIdRel(id)); - } - - @Operation(summary = "添加规格值") - @PostMapping() - public ApiResult save(@RequestBody CmsProductSpecValue cmsProductSpecValue) { - if (cmsProductSpecValueService.save(cmsProductSpecValue)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改规格值") - @PutMapping() - public ApiResult update(@RequestBody CmsProductSpecValue cmsProductSpecValue) { - if (cmsProductSpecValueService.updateById(cmsProductSpecValue)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除规格值") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsProductSpecValueService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加规格值") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsProductSpecValueService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改规格值") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsProductSpecValueService, "spec_value_id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除规格值") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsProductSpecValueService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsProductUrlController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsProductUrlController.java deleted file mode 100644 index b367be8..0000000 --- a/src/main/java/com/gxwebsoft/cms/controller/CmsProductUrlController.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.gxwebsoft.cms.controller; - -import com.gxwebsoft.common.core.web.BaseController; -import com.gxwebsoft.cms.service.CmsProductUrlService; -import com.gxwebsoft.cms.entity.CmsProductUrl; -import com.gxwebsoft.cms.param.CmsProductUrlParam; -import com.gxwebsoft.common.core.web.ApiResult; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.common.core.web.BatchParam; -import com.gxwebsoft.common.core.annotation.OperationLog; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 域名控制器 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Tag(name = "域名管理") -@RestController -@RequestMapping("/api/cms/cms-product-url") -public class CmsProductUrlController extends BaseController { - @Resource - private CmsProductUrlService cmsProductUrlService; - - @Operation(summary = "分页查询域名") - @GetMapping("/page") - public ApiResult> page(CmsProductUrlParam param) { - // 使用关联查询 - return success(cmsProductUrlService.pageRel(param)); - } - - @Operation(summary = "查询全部域名") - @GetMapping() - public ApiResult> list(CmsProductUrlParam param) { - // 使用关联查询 - return success(cmsProductUrlService.listRel(param)); - } - - @PreAuthorize("hasAuthority('cms:cmsProductUrl:list')") - @OperationLog - @Operation(summary = "根据id查询域名") - @GetMapping("/{id}") - public ApiResult get(@PathVariable("id") Integer id) { - // 使用关联查询 - return success(cmsProductUrlService.getByIdRel(id)); - } - - @Operation(summary = "添加域名") - @PostMapping() - public ApiResult save(@RequestBody CmsProductUrl cmsProductUrl) { - if (cmsProductUrlService.save(cmsProductUrl)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "修改域名") - @PutMapping() - public ApiResult update(@RequestBody CmsProductUrl cmsProductUrl) { - if (cmsProductUrlService.updateById(cmsProductUrl)) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "删除域名") - @DeleteMapping("/{id}") - public ApiResult remove(@PathVariable("id") Integer id) { - if (cmsProductUrlService.removeById(id)) { - return success("删除成功"); - } - return fail("删除失败"); - } - - @Operation(summary = "批量添加域名") - @PostMapping("/batch") - public ApiResult saveBatch(@RequestBody List list) { - if (cmsProductUrlService.saveBatch(list)) { - return success("添加成功"); - } - return fail("添加失败"); - } - - @Operation(summary = "批量修改域名") - @PutMapping("/batch") - public ApiResult removeBatch(@RequestBody BatchParam batchParam) { - if (batchParam.update(cmsProductUrlService, "id")) { - return success("修改成功"); - } - return fail("修改失败"); - } - - @Operation(summary = "批量删除域名") - @DeleteMapping("/batch") - public ApiResult removeBatch(@RequestBody List ids) { - if (cmsProductUrlService.removeByIds(ids)) { - return success("删除成功"); - } - return fail("删除失败"); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsComponents.java b/src/main/java/com/gxwebsoft/cms/entity/CmsComponents.java deleted file mode 100644 index d4edc07..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsComponents.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 组件 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsComponents对象", description = "组件") -public class CmsComponents implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - - @Schema(description = "组件标题") - private String title; - - @Schema(description = "关联导航ID") - private Integer navigationId; - - @Schema(description = "组件类型") - private String type; - - @Schema(description = "页面关键词") - private String keywords; - - @Schema(description = "页面描述") - private String description; - - @Schema(description = "组件路径") - private String path; - - @Schema(description = "组件图标") - private String icon; - - @Schema(description = "用户ID") - private Integer userId; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1冻结") - private Integer status; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java b/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java index b424722..a562ef1 100644 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java +++ b/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java @@ -29,12 +29,16 @@ public class CmsDesign implements Serializable { @TableId(value = "page_id", type = IdType.AUTO) private Integer pageId; - @Schema(description = "页面标题") + @Schema(description = "页面") private String name; @Schema(description = "所属栏目ID") private Integer categoryId; + @Schema(description = "所属栏目") + @TableField(exist = false) + private String categoryName; + @Schema(description = "页面模型") private String model; diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsMp.java b/src/main/java/com/gxwebsoft/cms/entity/CmsMp.java deleted file mode 100644 index e921212..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsMp.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import com.baomidou.mybatisplus.annotation.TableLogic; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序信息 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsMp对象", description = "小程序信息") -public class CmsMp implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @TableId(value = "mp_id", type = IdType.AUTO) - private Integer mpId; - - @Schema(description = "是否主账号") - private Integer type; - - @Schema(description = "小程序ID") - private String appId; - - @Schema(description = "小程序密钥") - private String appSecret; - - @Schema(description = "小程序名称") - private String mpName; - - @Schema(description = "小程序简称") - private String shortName; - - @Schema(description = "头像") - private String avatar; - - @Schema(description = "小程序码") - private String mpQrcode; - - @Schema(description = "微信认证") - private Integer authentication; - - @Schema(description = "主体信息") - private String companyName; - - @Schema(description = "小程序备案") - private String icpNo; - - @Schema(description = "登录邮箱") - private String email; - - @Schema(description = "登录密码") - private String password; - - @Schema(description = "原始ID") - private String ghId; - - @Schema(description = "入口页面") - private String mainPath; - - @Schema(description = "过期时间") - private Date expirationTime; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "介绍") - private String comments; - - @Schema(description = "用户ID") - private Integer userId; - - @Schema(description = "状态, 0正常, 1冻结") - private Integer status; - - @Schema(description = "是否删除, 0否, 1是") - @TableLogic - private Integer deleted; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsMpAd.java b/src/main/java/com/gxwebsoft/cms/entity/CmsMpAd.java deleted file mode 100644 index d724f96..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsMpAd.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import com.baomidou.mybatisplus.annotation.TableLogic; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序广告位 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsMpAd对象", description = "小程序广告位") -public class CmsMpAd implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @TableId(value = "ad_id", type = IdType.AUTO) - private Integer adId; - - @Schema(description = "页面ID") - private Integer pageId; - - @Schema(description = "广告类型") - private String adType; - - @Schema(description = "广告位名称") - private String name; - - @Schema(description = "宽") - private String width; - - @Schema(description = "高") - private String height; - - @Schema(description = "广告图片") - private String images; - - @Schema(description = "路由/链接地址") - private String path; - - @Schema(description = "页面名称") - private String pageName; - - @Schema(description = "用户ID") - private Integer userId; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1冻结") - private Integer status; - - @Schema(description = "是否删除, 0否, 1是") - @TableLogic - private Integer deleted; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsMpField.java b/src/main/java/com/gxwebsoft/cms/entity/CmsMpField.java deleted file mode 100644 index 5363ce0..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsMpField.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import com.baomidou.mybatisplus.annotation.TableLogic; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序配置 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsMpField对象", description = "小程序配置") -public class CmsMpField implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "自增ID") - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - - @Schema(description = "类型,0文本 1图片 2其他") - private Integer type; - - @Schema(description = "名称") - private String name; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "名称") - private String value; - - @Schema(description = "页面ID") - private Integer pageId; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "是否删除, 0否, 1是") - @TableLogic - private Integer deleted; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsMpMenu.java b/src/main/java/com/gxwebsoft/cms/entity/CmsMpMenu.java deleted file mode 100644 index 1739dbf..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsMpMenu.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序端菜单 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsMpMenu对象", description = "小程序端菜单") -public class CmsMpMenu implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @TableId(value = "menu_id", type = IdType.AUTO) - private Integer menuId; - - @Schema(description = "上级id, 0是顶级") - private Integer parentId; - - @Schema(description = "菜单名称") - private String title; - - @Schema(description = "类型 0功能图标 1订单状态图标 2首页导航图标 3 商城导航图标 4管理人员功能图标") - private Integer type; - - @Schema(description = "是否微信小程序菜单") - private Boolean isMpWeixin; - - @Schema(description = "菜单路由地址") - private String path; - - @Schema(description = "菜单组件地址, 目录可为空") - private String component; - - @Schema(description = "打开位置") - private String target; - - @Schema(description = "菜单图标") - private String avatar; - - @Schema(description = "图标颜色") - private String color; - - @Schema(description = "上传图标") - private String icon; - - @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") - private Integer hide; - - @Schema(description = "位置 0不限 1顶部 2底部") - private Integer position; - - @Schema(description = "0 第一行 1第二行") - private Integer rows; - - @Schema(description = "菜单侧栏选中的path") - private String active; - - @Schema(description = "其它路由元信息") - private String meta; - - @Schema(description = "绑定的页面") - private Integer pageId; - - @Schema(description = "绑定的文章分类ID") - private Integer articleCategoryId; - - @Schema(description = "绑定的文章ID") - private Integer articleId; - - @Schema(description = "绑定的表单ID") - private Integer formId; - - @Schema(description = "绑定的知识库标识") - private String bookCode; - - @Schema(description = "绑定的商品分类ID") - private Integer goodsCategoryId; - - @Schema(description = "绑定的商品ID") - private Integer goodsId; - - @Schema(description = "用户ID") - private Integer userId; - - @Schema(description = "是否管理人员可见") - private Integer adminShow; - - @Schema(description = "设为首页") - private Integer home; - - @Schema(description = "分组名称") - private String groupName; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1冻结") - private Integer status; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsMpPages.java b/src/main/java/com/gxwebsoft/cms/entity/CmsMpPages.java deleted file mode 100644 index adc22cc..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsMpPages.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import com.baomidou.mybatisplus.annotation.TableLogic; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序页面 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsMpPages对象", description = "小程序页面") -public class CmsMpPages implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - - @Schema(description = "上级id, 0是顶级") - private Integer parentId; - - @Schema(description = "页面名称") - private String title; - - @Schema(description = "页面路径") - private String path; - - @Schema(description = "设为首页") - private Integer home; - - @Schema(description = "分包") - private String subpackage; - - @Schema(description = "图标") - private String icon; - - @Schema(description = "未选中图标") - private String iconPath; - - @Schema(description = "选中的图标") - private String selectedIconPath; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "用户ID") - private Integer userId; - - @Schema(description = "状态, 0正常, 1冻结") - private Integer status; - - @Schema(description = "是否删除, 0否, 1是") - @TableLogic - private Integer deleted; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsOrder.java b/src/main/java/com/gxwebsoft/cms/entity/CmsOrder.java deleted file mode 100644 index eceb20e..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsOrder.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import java.math.BigDecimal; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import com.baomidou.mybatisplus.annotation.TableLogic; -import java.io.Serializable; -import java.util.Date; - -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 订单 - * - * @author 科技小王子 - * @since 2024-11-25 12:14:05 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsOrder对象", description = "订单") -public class CmsOrder implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "订单号") - @TableId(value = "order_id", type = IdType.AUTO) - private Integer orderId; - - @Schema(description = "订单标题") - private String title; - - @Schema(description = "模型名称") - private String model; - - @Schema(description = "订单编号") - private String orderNo; - - @Schema(description = "订单类型,0商城 1询价 2留言") - private Integer type; - - @Schema(description = "关联文章ID") - private Integer articleId; - - @Schema(description = "关联网站ID") - private Integer websiteId; - - @Schema(description = "真实姓名") - private String realName; - - @Schema(description = "手机号码") - private String phone; - - @Schema(description = "电子邮箱") - private String email; - - @Schema(description = "联系地址") - private String address; - - @Schema(description = "订单内容") - private String content; - - @Schema(description = "订单附件") - private String files; - - @Schema(description = "订单总额") - private BigDecimal totalPrice; - - @Schema(description = "实际付款") - private BigDecimal payPrice; - - @Schema(description = "报价询价") - private BigDecimal price; - - @Schema(description = "购买数量") - private Integer totalNum; - - @Schema(description = "二维码地址,保存订单号,支付成功后才生成") - private String qrcode; - - @Schema(description = "下单渠道,0网站 1小程序 2其他") - private Integer channel; - - @Schema(description = "过期时间") - private Date expirationTime; - - @Schema(description = "订单是否已结算(0未结算 1已结算)") - private Boolean isSettled; - - @Schema(description = "用户id") - private Integer userId; - - @Schema(description = "国际化语言") - private String lang; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序号") - private Integer sortNumber; - - @Schema(description = "是否删除, 0否, 1是") - @TableLogic - private Integer deleted; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - - @Schema(description = "图像验证码") - @TableField(exist = false) - private String code; - - @Schema(description = "栏目ID") - @TableField(exist = false) - private Integer categoryId; - - public String getLang() { - if(this.lang == null || this.lang.equals("zh")){ - return "zh_CN"; - } - return this.lang; - } -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsProduct.java b/src/main/java/com/gxwebsoft/cms/entity/CmsProduct.java deleted file mode 100644 index 4d7bce4..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsProduct.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import java.math.BigDecimal; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import com.baomidou.mybatisplus.annotation.TableLogic; -import java.io.Serializable; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 产品 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsProduct对象", description = "产品") -public class CmsProduct implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "自增ID") - @TableId(value = "product_id", type = IdType.AUTO) - private Integer productId; - - @Schema(description = "类型 0软件产品 1实物商品 2虚拟商品") - private Integer type; - - @Schema(description = "产品编码") - private String code; - - @Schema(description = "产品标题") - private String title; - - @Schema(description = "封面图") - private String image; - - @Schema(description = "标签") - private String tag; - - @Schema(description = "产品详情") - private String content; - - @Schema(description = "父级分类ID") - private Integer parentId; - - @Schema(description = "产品分类ID") - private Integer categoryId; - - @Schema(description = "产品规格 0单规格 1多规格") - private Integer specs; - - @Schema(description = "货架") - private String position; - - @Schema(description = "单位名称 (个)") - private String unitName; - - @Schema(description = "进货价格") - private BigDecimal price; - - @Schema(description = "销售价格") - private BigDecimal salePrice; - - @Schema(description = "库存计算方式(10下单减库存 20付款减库存)") - private Integer deductStockType; - - @Schema(description = "轮播图") - private String files; - - @Schema(description = "销量") - private Integer sales; - - @Schema(description = "库存") - private Integer stock; - - @Schema(description = "消费赚取积分") - private BigDecimal gainIntegral; - - @Schema(description = "推荐") - private Integer recommend; - - @Schema(description = "商户ID") - private Long merchantId; - - @Schema(description = "状态(0:未上架,1:上架)") - private Boolean isShow; - - @Schema(description = "状态, 0上架 1待上架 2待审核 3审核不通过") - private Integer status; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序号") - private Integer sortNumber; - - @Schema(description = "用户ID") - private Integer userId; - - @Schema(description = "是否删除, 0否, 1是") - @TableLogic - private Integer deleted; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - - @Schema(description = "修改时间") - private Date updateTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsProductSpec.java b/src/main/java/com/gxwebsoft/cms/entity/CmsProductSpec.java deleted file mode 100644 index b4d0967..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsProductSpec.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import java.io.Serializable; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 规格 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsProductSpec对象", description = "规格") -public class CmsProductSpec implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "规格ID") - @TableId(value = "spec_id", type = IdType.AUTO) - private Integer specId; - - @Schema(description = "规格名称") - private String specName; - - @Schema(description = "规格值") - private String specValue; - - @Schema(description = "创建用户") - private Integer userId; - - @Schema(description = "更新者") - private Integer updater; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1待修,2异常已修,3异常未修") - private Integer status; - - @Schema(description = "排序号") - private Integer sortNumber; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsProductSpecValue.java b/src/main/java/com/gxwebsoft/cms/entity/CmsProductSpecValue.java deleted file mode 100644 index f718359..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsProductSpecValue.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import java.io.Serializable; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 规格值 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsProductSpecValue对象", description = "规格值") -public class CmsProductSpecValue implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "规格值ID") - @TableId(value = "spec_value_id", type = IdType.AUTO) - private Integer specValueId; - - @Schema(description = "规格组ID") - private Integer specId; - - @Schema(description = "规格值") - private String specValue; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序号") - private Integer sortNumber; - - @Schema(description = "租户id") - private Integer tenantId; - - @Schema(description = "创建时间") - private Date createTime; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsProductUrl.java b/src/main/java/com/gxwebsoft/cms/entity/CmsProductUrl.java deleted file mode 100644 index 73064b5..0000000 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsProductUrl.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.gxwebsoft.cms.entity; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import java.util.Date; -import java.io.Serializable; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 域名 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@Schema(name = "CmsProductUrl对象", description = "域名") -public class CmsProductUrl implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "自增ID") - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - - @Schema(description = "产品ID") - private Integer productId; - - @Schema(description = "域名类型") - private String type; - - @Schema(description = "域名") - private String domain; - - @Schema(description = "账号") - private String account; - - @Schema(description = "密码") - private String password; - - @Schema(description = "商户ID") - private Long merchantId; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序(数字越小越靠前)") - private Integer sortNumber; - - @Schema(description = "状态, 0正常, 1待确认") - private Integer status; - - @Schema(description = "创建时间") - private Date createTime; - - @Schema(description = "租户id") - private Integer tenantId; - -} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java b/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java index e1194c6..db03298 100644 --- a/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java +++ b/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java @@ -254,7 +254,7 @@ public class CmsWebsite implements Serializable { @Schema(description = "小程序导航图标") @TableField(exist = false) - private Map> mpMenus; + private Map> mpMenus; @Schema(description = "网站导航栏") @TableField(exist = false) diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsComponentsMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsComponentsMapper.java deleted file mode 100644 index 1b64edb..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsComponentsMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsComponents; -import com.gxwebsoft.cms.param.CmsComponentsParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 组件Mapper - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsComponentsMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsComponentsParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsComponentsParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpAdMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsMpAdMapper.java deleted file mode 100644 index 63e9029..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpAdMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsMpAd; -import com.gxwebsoft.cms.param.CmsMpAdParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 小程序广告位Mapper - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpAdMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsMpAdParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsMpAdParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpFieldMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsMpFieldMapper.java deleted file mode 100644 index 68c141a..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpFieldMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsMpField; -import com.gxwebsoft.cms.param.CmsMpFieldParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 小程序配置Mapper - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpFieldMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsMpFieldParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsMpFieldParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsMpMapper.java deleted file mode 100644 index 1d6f315..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsMp; -import com.gxwebsoft.cms.param.CmsMpParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 小程序信息Mapper - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsMpParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsMpParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpMenuMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsMpMenuMapper.java deleted file mode 100644 index 3d1b7cd..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpMenuMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsMpMenu; -import com.gxwebsoft.cms.param.CmsMpMenuParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 小程序端菜单Mapper - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpMenuMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsMpMenuParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsMpMenuParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpPagesMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsMpPagesMapper.java deleted file mode 100644 index 70995b5..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsMpPagesMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsMpPages; -import com.gxwebsoft.cms.param.CmsMpPagesParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 小程序页面Mapper - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpPagesMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsMpPagesParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsMpPagesParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsOrderMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsOrderMapper.java deleted file mode 100644 index a4d0e9e..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsOrderMapper.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsNavigation; -import com.gxwebsoft.cms.entity.CmsOrder; -import com.gxwebsoft.cms.param.CmsNavigationParam; -import com.gxwebsoft.cms.param.CmsOrderParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 订单Mapper - * - * @author 科技小王子 - * @since 2024-11-25 12:14:05 - */ -public interface CmsOrderMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsOrderParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsOrderParam param); - - @InterceptorIgnore(tenantLine = "true") - List selectListAllRel(@Param("param") CmsOrderParam param); -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsProductMapper.java deleted file mode 100644 index 5abc070..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsProduct; -import com.gxwebsoft.cms.param.CmsProductParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 产品Mapper - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsProductParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsProductParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductSpecMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsProductSpecMapper.java deleted file mode 100644 index ce73ad8..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductSpecMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsProductSpec; -import com.gxwebsoft.cms.param.CmsProductSpecParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 规格Mapper - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductSpecMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsProductSpecParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsProductSpecParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductSpecValueMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsProductSpecValueMapper.java deleted file mode 100644 index 9885e18..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductSpecValueMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsProductSpecValue; -import com.gxwebsoft.cms.param.CmsProductSpecValueParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 规格值Mapper - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductSpecValueMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsProductSpecValueParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsProductSpecValueParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductUrlMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsProductUrlMapper.java deleted file mode 100644 index 5bd2486..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/CmsProductUrlMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gxwebsoft.cms.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.gxwebsoft.cms.entity.CmsProductUrl; -import com.gxwebsoft.cms.param.CmsProductUrlParam; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - * 域名Mapper - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductUrlMapper extends BaseMapper { - - /** - * 分页查询 - * - * @param page 分页对象 - * @param param 查询参数 - * @return List - */ - List selectPageRel(@Param("page") IPage page, - @Param("param") CmsProductUrlParam param); - - /** - * 查询全部 - * - * @param param 查询参数 - * @return List - */ - List selectListRel(@Param("param") CmsProductUrlParam param); - -} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsComponentsMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsComponentsMapper.xml deleted file mode 100644 index 56c3e24..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsComponentsMapper.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_components a - - - AND a.id = #{param.id} - - - AND a.title LIKE CONCAT('%', #{param.title}, '%') - - - AND a.navigation_id = #{param.navigationId} - - - AND a.type LIKE CONCAT('%', #{param.type}, '%') - - - AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') - - - AND a.description LIKE CONCAT('%', #{param.description}, '%') - - - AND a.path LIKE CONCAT('%', #{param.path}, '%') - - - AND a.icon LIKE CONCAT('%', #{param.icon}, '%') - - - AND a.user_id = #{param.userId} - - - AND a.sort_number = #{param.sortNumber} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.status = #{param.status} - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml index ed0f2d5..def6547 100644 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml +++ b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml @@ -4,7 +4,7 @@ - SELECT a.*,b.lang_category_id + SELECT a.*,b.lang_category_id, b.title as categoryName FROM cms_design a LEFT JOIN cms_navigation b ON a.category_id = b.navigation_id diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpAdMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpAdMapper.xml deleted file mode 100644 index 798715d..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpAdMapper.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_mp_ad a - - - AND a.ad_id = #{param.adId} - - - AND a.page_id = #{param.pageId} - - - AND a.ad_type LIKE CONCAT('%', #{param.adType}, '%') - - - AND a.name LIKE CONCAT('%', #{param.name}, '%') - - - AND a.width LIKE CONCAT('%', #{param.width}, '%') - - - AND a.height LIKE CONCAT('%', #{param.height}, '%') - - - AND a.images LIKE CONCAT('%', #{param.images}, '%') - - - AND a.path LIKE CONCAT('%', #{param.path}, '%') - - - AND a.page_name LIKE CONCAT('%', #{param.pageName}, '%') - - - AND a.user_id = #{param.userId} - - - AND a.sort_number = #{param.sortNumber} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.status = #{param.status} - - - AND a.deleted = #{param.deleted} - - - AND a.deleted = 0 - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpFieldMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpFieldMapper.xml deleted file mode 100644 index d7c0cda..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpFieldMapper.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_mp_field a - - - AND a.id = #{param.id} - - - AND a.type = #{param.type} - - - AND a.name LIKE CONCAT('%', #{param.name}, '%') - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.value LIKE CONCAT('%', #{param.value}, '%') - - - AND a.page_id = #{param.pageId} - - - AND a.sort_number = #{param.sortNumber} - - - AND a.deleted = #{param.deleted} - - - AND a.deleted = 0 - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpMapper.xml deleted file mode 100644 index 6cf57e5..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpMapper.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_mp a - - - AND a.mp_id = #{param.mpId} - - - AND a.type = #{param.type} - - - AND a.app_id LIKE CONCAT('%', #{param.appId}, '%') - - - AND a.app_secret LIKE CONCAT('%', #{param.appSecret}, '%') - - - AND a.mp_name LIKE CONCAT('%', #{param.mpName}, '%') - - - AND a.short_name LIKE CONCAT('%', #{param.shortName}, '%') - - - AND a.avatar LIKE CONCAT('%', #{param.avatar}, '%') - - - AND a.mp_qrcode LIKE CONCAT('%', #{param.mpQrcode}, '%') - - - AND a.authentication = #{param.authentication} - - - AND a.company_name LIKE CONCAT('%', #{param.companyName}, '%') - - - AND a.icp_no LIKE CONCAT('%', #{param.icpNo}, '%') - - - AND a.email LIKE CONCAT('%', #{param.email}, '%') - - - AND a.password LIKE CONCAT('%', #{param.password}, '%') - - - AND a.gh_id LIKE CONCAT('%', #{param.ghId}, '%') - - - AND a.main_path LIKE CONCAT('%', #{param.mainPath}, '%') - - - AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.user_id = #{param.userId} - - - AND a.status = #{param.status} - - - AND a.deleted = #{param.deleted} - - - AND a.deleted = 0 - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpMenuMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpMenuMapper.xml deleted file mode 100644 index 7ac324c..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpMenuMapper.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_mp_menu a - - - AND a.menu_id = #{param.menuId} - - - AND a.parent_id = #{param.parentId} - - - AND a.title LIKE CONCAT('%', #{param.title}, '%') - - - AND a.type = #{param.type} - - - AND a.is_mp_weixin = #{param.isMpWeixin} - - - AND a.path LIKE CONCAT('%', #{param.path}, '%') - - - AND a.component LIKE CONCAT('%', #{param.component}, '%') - - - AND a.target LIKE CONCAT('%', #{param.target}, '%') - - - AND a.avatar LIKE CONCAT('%', #{param.avatar}, '%') - - - AND a.color LIKE CONCAT('%', #{param.color}, '%') - - - AND a.icon LIKE CONCAT('%', #{param.icon}, '%') - - - AND a.hide = #{param.hide} - - - AND a.position = #{param.position} - - - AND a.rows = #{param.rows} - - - AND a.active LIKE CONCAT('%', #{param.active}, '%') - - - AND a.meta LIKE CONCAT('%', #{param.meta}, '%') - - - AND a.page_id = #{param.pageId} - - - AND a.article_category_id = #{param.articleCategoryId} - - - AND a.article_id = #{param.articleId} - - - AND a.form_id = #{param.formId} - - - AND a.book_code LIKE CONCAT('%', #{param.bookCode}, '%') - - - AND a.goods_category_id = #{param.goodsCategoryId} - - - AND a.goods_id = #{param.goodsId} - - - AND a.user_id = #{param.userId} - - - AND a.admin_show = #{param.adminShow} - - - AND a.home = #{param.home} - - - AND a.group_name LIKE CONCAT('%', #{param.groupName}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.status = #{param.status} - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpPagesMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpPagesMapper.xml deleted file mode 100644 index 08fcf49..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsMpPagesMapper.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_mp_pages a - - - AND a.id = #{param.id} - - - AND a.parent_id = #{param.parentId} - - - AND a.title LIKE CONCAT('%', #{param.title}, '%') - - - AND a.path LIKE CONCAT('%', #{param.path}, '%') - - - AND a.home = #{param.home} - - - AND a.subpackage LIKE CONCAT('%', #{param.subpackage}, '%') - - - AND a.icon LIKE CONCAT('%', #{param.icon}, '%') - - - AND a.icon_path LIKE CONCAT('%', #{param.iconPath}, '%') - - - AND a.selected_icon_path LIKE CONCAT('%', #{param.selectedIconPath}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.user_id = #{param.userId} - - - AND a.status = #{param.status} - - - AND a.deleted = #{param.deleted} - - - AND a.deleted = 0 - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsOrderMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsOrderMapper.xml deleted file mode 100644 index e167b20..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsOrderMapper.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - SELECT a.*, b.category_id, c.user_id as websiteUserId - FROM cms_order a - LEFT JOIN cms_article b ON a.article_id = b.article_id - LEFT JOIN cms_website c ON a.tenant_id = c.tenant_id - - - AND a.order_id = #{param.orderId} - - - AND a.title LIKE CONCAT('%', #{param.title}, '%') - - - AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') - - - AND a.model = #{param.model} - - - AND a.lang = #{param.lang} - - - AND a.type = #{param.type} - - - AND a.article_id = #{param.articleId} - - - AND a.website_id = #{param.websiteId} - - - AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') - - - AND a.phone LIKE CONCAT('%', #{param.phone}, '%') - - - AND a.email LIKE CONCAT('%', #{param.email}, '%') - - - AND a.content LIKE CONCAT('%', #{param.content}, '%') - - - AND a.total_price = #{param.totalPrice} - - - AND a.pay_price = #{param.payPrice} - - - AND a.price = #{param.price} - - - AND a.total_num = #{param.totalNum} - - - AND a.qrcode LIKE CONCAT('%', #{param.qrcode}, '%') - - - AND a.channel = #{param.channel} - - - AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') - - - AND a.is_settled = #{param.isSettled} - - - AND a.user_id = #{param.userId} - - - AND c.user_id = #{param.websiteUserId} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.deleted = #{param.deleted} - - - AND a.deleted = 0 - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') - OR a.title LIKE CONCAT('%', #{param.keywords}, '%') - OR a.content LIKE CONCAT('%', #{param.keywords}, '%') - OR a.phone = #{param.keywords} - ) - - - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductMapper.xml deleted file mode 100644 index dc2a719..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductMapper.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_product a - - - AND a.product_id = #{param.productId} - - - AND a.type = #{param.type} - - - AND a.code LIKE CONCAT('%', #{param.code}, '%') - - - AND a.title LIKE CONCAT('%', #{param.title}, '%') - - - AND a.image LIKE CONCAT('%', #{param.image}, '%') - - - AND a.content LIKE CONCAT('%', #{param.content}, '%') - - - AND a.parent_id = #{param.parentId} - - - AND a.category_id = #{param.categoryId} - - - AND a.specs = #{param.specs} - - - AND a.position LIKE CONCAT('%', #{param.position}, '%') - - - AND a.unit_name LIKE CONCAT('%', #{param.unitName}, '%') - - - AND a.price = #{param.price} - - - AND a.sale_price = #{param.salePrice} - - - AND a.deduct_stock_type = #{param.deductStockType} - - - AND a.files LIKE CONCAT('%', #{param.files}, '%') - - - AND a.sales = #{param.sales} - - - AND a.stock = #{param.stock} - - - AND a.gain_integral = #{param.gainIntegral} - - - AND a.recommend = #{param.recommend} - - - AND a.merchant_id = #{param.merchantId} - - - AND a.is_show = #{param.isShow} - - - AND a.status = #{param.status} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.user_id = #{param.userId} - - - AND a.deleted = #{param.deleted} - - - AND a.deleted = 0 - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductSpecMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductSpecMapper.xml deleted file mode 100644 index 08ee497..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductSpecMapper.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_product_spec a - - - AND a.spec_id = #{param.specId} - - - AND a.spec_name LIKE CONCAT('%', #{param.specName}, '%') - - - AND a.spec_value LIKE CONCAT('%', #{param.specValue}, '%') - - - AND a.user_id = #{param.userId} - - - AND a.updater = #{param.updater} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.status = #{param.status} - - - AND a.sort_number = #{param.sortNumber} - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductSpecValueMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductSpecValueMapper.xml deleted file mode 100644 index acc1723..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductSpecValueMapper.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_product_spec_value a - - - AND a.spec_value_id = #{param.specValueId} - - - AND a.spec_id = #{param.specId} - - - AND a.spec_value LIKE CONCAT('%', #{param.specValue}, '%') - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductUrlMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductUrlMapper.xml deleted file mode 100644 index fb42be5..0000000 --- a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsProductUrlMapper.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - SELECT a.* - FROM cms_product_url a - - - AND a.id = #{param.id} - - - AND a.product_id = #{param.productId} - - - AND a.type LIKE CONCAT('%', #{param.type}, '%') - - - AND a.domain LIKE CONCAT('%', #{param.domain}, '%') - - - AND a.account LIKE CONCAT('%', #{param.account}, '%') - - - AND a.password LIKE CONCAT('%', #{param.password}, '%') - - - AND a.merchant_id = #{param.merchantId} - - - AND a.comments LIKE CONCAT('%', #{param.comments}, '%') - - - AND a.sort_number = #{param.sortNumber} - - - AND a.status = #{param.status} - - - AND a.create_time >= #{param.createTimeStart} - - - AND a.create_time <= #{param.createTimeEnd} - - - - - - - - - - - diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsComponentsParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsComponentsParam.java deleted file mode 100644 index 9be566f..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsComponentsParam.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 组件查询参数 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsComponentsParam对象", description = "组件查询参数") -public class CmsComponentsParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @QueryField(type = QueryType.EQ) - private Integer id; - - @Schema(description = "组件标题") - private String title; - - @Schema(description = "关联导航ID") - @QueryField(type = QueryType.EQ) - private Integer navigationId; - - @Schema(description = "组件类型") - private String type; - - @Schema(description = "页面关键词") - private String keywords; - - @Schema(description = "页面描述") - private String description; - - @Schema(description = "组件路径") - private String path; - - @Schema(description = "组件图标") - private String icon; - - @Schema(description = "用户ID") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1冻结") - @QueryField(type = QueryType.EQ) - private Integer status; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsMpAdParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsMpAdParam.java deleted file mode 100644 index 0d807af..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsMpAdParam.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序广告位查询参数 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsMpAdParam对象", description = "小程序广告位查询参数") -public class CmsMpAdParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @QueryField(type = QueryType.EQ) - private Integer adId; - - @Schema(description = "页面ID") - @QueryField(type = QueryType.EQ) - private Integer pageId; - - @Schema(description = "广告类型") - private String adType; - - @Schema(description = "广告位名称") - private String name; - - @Schema(description = "宽") - private String width; - - @Schema(description = "高") - private String height; - - @Schema(description = "广告图片") - private String images; - - @Schema(description = "路由/链接地址") - private String path; - - @Schema(description = "页面名称") - private String pageName; - - @Schema(description = "用户ID") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1冻结") - @QueryField(type = QueryType.EQ) - private Integer status; - - @Schema(description = "是否删除, 0否, 1是") - @QueryField(type = QueryType.EQ) - private Integer deleted; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsMpFieldParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsMpFieldParam.java deleted file mode 100644 index 4717e19..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsMpFieldParam.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序配置查询参数 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsMpFieldParam对象", description = "小程序配置查询参数") -public class CmsMpFieldParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "自增ID") - @QueryField(type = QueryType.EQ) - private Integer id; - - @Schema(description = "类型,0文本 1图片 2其他") - @QueryField(type = QueryType.EQ) - private Integer type; - - @Schema(description = "名称") - private String name; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "名称") - private String value; - - @Schema(description = "页面ID") - @QueryField(type = QueryType.EQ) - private Integer pageId; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "是否删除, 0否, 1是") - @QueryField(type = QueryType.EQ) - private Integer deleted; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsMpMenuParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsMpMenuParam.java deleted file mode 100644 index 4cece86..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsMpMenuParam.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序端菜单查询参数 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsMpMenuParam对象", description = "小程序端菜单查询参数") -public class CmsMpMenuParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @QueryField(type = QueryType.EQ) - private Integer menuId; - - @Schema(description = "上级id, 0是顶级") - @QueryField(type = QueryType.EQ) - private Integer parentId; - - @Schema(description = "菜单名称") - private String title; - - @Schema(description = "类型 0功能图标 1订单状态图标 2首页导航图标 3 商城导航图标 4管理人员功能图标") - @QueryField(type = QueryType.EQ) - private Integer type; - - @Schema(description = "是否微信小程序菜单") - @QueryField(type = QueryType.EQ) - private Boolean isMpWeixin; - - @Schema(description = "菜单路由地址") - private String path; - - @Schema(description = "菜单组件地址, 目录可为空") - private String component; - - @Schema(description = "打开位置") - private String target; - - @Schema(description = "菜单图标") - private String avatar; - - @Schema(description = "图标颜色") - private String color; - - @Schema(description = "上传图标") - private String icon; - - @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") - @QueryField(type = QueryType.EQ) - private Integer hide; - - @Schema(description = "位置 0不限 1顶部 2底部") - @QueryField(type = QueryType.EQ) - private Integer position; - - @Schema(description = "0 第一行 1第二行") - @QueryField(type = QueryType.EQ) - private Integer rows; - - @Schema(description = "菜单侧栏选中的path") - private String active; - - @Schema(description = "其它路由元信息") - private String meta; - - @Schema(description = "绑定的页面") - @QueryField(type = QueryType.EQ) - private Integer pageId; - - @Schema(description = "绑定的文章分类ID") - @QueryField(type = QueryType.EQ) - private Integer articleCategoryId; - - @Schema(description = "绑定的文章ID") - @QueryField(type = QueryType.EQ) - private Integer articleId; - - @Schema(description = "绑定的表单ID") - @QueryField(type = QueryType.EQ) - private Integer formId; - - @Schema(description = "绑定的知识库标识") - private String bookCode; - - @Schema(description = "绑定的商品分类ID") - @QueryField(type = QueryType.EQ) - private Integer goodsCategoryId; - - @Schema(description = "绑定的商品ID") - @QueryField(type = QueryType.EQ) - private Integer goodsId; - - @Schema(description = "用户ID") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "是否管理人员可见") - @QueryField(type = QueryType.EQ) - private Integer adminShow; - - @Schema(description = "设为首页") - @QueryField(type = QueryType.EQ) - private Integer home; - - @Schema(description = "分组名称") - private String groupName; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1冻结") - @QueryField(type = QueryType.EQ) - private Integer status; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsMpPagesParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsMpPagesParam.java deleted file mode 100644 index e93a5f4..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsMpPagesParam.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序页面查询参数 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsMpPagesParam对象", description = "小程序页面查询参数") -public class CmsMpPagesParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @QueryField(type = QueryType.EQ) - private Integer id; - - @Schema(description = "上级id, 0是顶级") - @QueryField(type = QueryType.EQ) - private Integer parentId; - - @Schema(description = "页面名称") - private String title; - - @Schema(description = "页面路径") - private String path; - - @Schema(description = "设为首页") - @QueryField(type = QueryType.EQ) - private Integer home; - - @Schema(description = "分包") - private String subpackage; - - @Schema(description = "图标") - private String icon; - - @Schema(description = "未选中图标") - private String iconPath; - - @Schema(description = "选中的图标") - private String selectedIconPath; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "用户ID") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "状态, 0正常, 1冻结") - @QueryField(type = QueryType.EQ) - private Integer status; - - @Schema(description = "是否删除, 0否, 1是") - @QueryField(type = QueryType.EQ) - private Integer deleted; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsMpParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsMpParam.java deleted file mode 100644 index e428af2..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsMpParam.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 小程序信息查询参数 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsMpParam对象", description = "小程序信息查询参数") -public class CmsMpParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "ID") - @QueryField(type = QueryType.EQ) - private Integer mpId; - - @Schema(description = "是否主账号") - @QueryField(type = QueryType.EQ) - private Integer type; - - @Schema(description = "小程序ID") - private String appId; - - @Schema(description = "小程序密钥") - private String appSecret; - - @Schema(description = "小程序名称") - private String mpName; - - @Schema(description = "小程序简称") - private String shortName; - - @Schema(description = "头像") - private String avatar; - - @Schema(description = "小程序码") - private String mpQrcode; - - @Schema(description = "微信认证") - @QueryField(type = QueryType.EQ) - private Integer authentication; - - @Schema(description = "主体信息") - private String companyName; - - @Schema(description = "小程序备案") - private String icpNo; - - @Schema(description = "登录邮箱") - private String email; - - @Schema(description = "登录密码") - private String password; - - @Schema(description = "原始ID") - private String ghId; - - @Schema(description = "入口页面") - private String mainPath; - - @Schema(description = "过期时间") - private String expirationTime; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "介绍") - private String comments; - - @Schema(description = "用户ID") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "状态, 0正常, 1冻结") - @QueryField(type = QueryType.EQ) - private Integer status; - - @Schema(description = "是否删除, 0否, 1是") - @QueryField(type = QueryType.EQ) - private Integer deleted; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsOrderParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsOrderParam.java deleted file mode 100644 index d2fa8e6..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsOrderParam.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.gxwebsoft.cms.param; - -import java.math.BigDecimal; -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 订单查询参数 - * - * @author 科技小王子 - * @since 2024-11-25 12:14:05 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsOrderParam对象", description = "订单查询参数") -public class CmsOrderParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "订单号") - @QueryField(type = QueryType.EQ) - private Integer orderId; - - @Schema(description = "订单标题") - private String title; - - @Schema(description = "模型名称") - private String model; - - @Schema(description = "订单编号") - private String orderNo; - - @Schema(description = "订单类型,0商城 1询价 2留言") - @QueryField(type = QueryType.EQ) - private Integer type; - - @Schema(description = "关联文章ID") - @QueryField(type = QueryType.EQ) - private Integer articleId; - - @Schema(description = "关联网站ID") - @QueryField(type = QueryType.EQ) - private Integer websiteId; - - @Schema(description = "真实姓名") - private String realName; - - @Schema(description = "手机号码") - private String phone; - - @Schema(description = "电子邮箱") - private String email; - - @Schema(description = "订单内容") - private String content; - - @Schema(description = "订单总额") - @QueryField(type = QueryType.EQ) - private BigDecimal totalPrice; - - @Schema(description = "实际付款") - @QueryField(type = QueryType.EQ) - private BigDecimal payPrice; - - @Schema(description = "报价询价") - @QueryField(type = QueryType.EQ) - private BigDecimal price; - - @Schema(description = "购买数量") - @QueryField(type = QueryType.EQ) - private Integer totalNum; - - @Schema(description = "二维码地址,保存订单号,支付成功后才生成") - private String qrcode; - - @Schema(description = "下单渠道,0网站 1小程序 2其他") - @QueryField(type = QueryType.EQ) - private Integer channel; - - @Schema(description = "过期时间") - private String expirationTime; - - @Schema(description = "订单是否已结算(0未结算 1已结算)") - @QueryField(type = QueryType.EQ) - private Boolean isSettled; - - @Schema(description = "用户id") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序号") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "是否删除, 0否, 1是") - @QueryField(type = QueryType.EQ) - private Integer deleted; - - @Schema(description = "网站创建者ID") - @QueryField(type = QueryType.EQ) - private Integer websiteUserId; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsProductParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsProductParam.java deleted file mode 100644 index c8b59e2..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsProductParam.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; - -/** - * 产品查询参数 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsProductParam对象", description = "产品查询参数") -public class CmsProductParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "自增ID") - @QueryField(type = QueryType.EQ) - private Integer productId; - - @Schema(description = "类型 0软件产品 1实物商品 2虚拟商品") - @QueryField(type = QueryType.EQ) - private Integer type; - - @Schema(description = "产品编码") - private String code; - - @Schema(description = "产品标题") - private String title; - - @Schema(description = "封面图") - private String image; - - @Schema(description = "产品详情") - private String content; - - @Schema(description = "父级分类ID") - @QueryField(type = QueryType.EQ) - private Integer parentId; - - @Schema(description = "产品分类ID") - @QueryField(type = QueryType.EQ) - private Integer categoryId; - - @Schema(description = "产品规格 0单规格 1多规格") - @QueryField(type = QueryType.EQ) - private Integer specs; - - @Schema(description = "货架") - private String position; - - @Schema(description = "单位名称 (个)") - private String unitName; - - @Schema(description = "进货价格") - @QueryField(type = QueryType.EQ) - private BigDecimal price; - - @Schema(description = "销售价格") - @QueryField(type = QueryType.EQ) - private BigDecimal salePrice; - - @Schema(description = "库存计算方式(10下单减库存 20付款减库存)") - @QueryField(type = QueryType.EQ) - private Integer deductStockType; - - @Schema(description = "轮播图") - private String files; - - @Schema(description = "销量") - @QueryField(type = QueryType.EQ) - private Integer sales; - - @Schema(description = "库存") - @QueryField(type = QueryType.EQ) - private Integer stock; - - @Schema(description = "消费赚取积分") - @QueryField(type = QueryType.EQ) - private BigDecimal gainIntegral; - - @Schema(description = "推荐") - @QueryField(type = QueryType.EQ) - private Integer recommend; - - @Schema(description = "商户ID") - @QueryField(type = QueryType.EQ) - private Long merchantId; - - @Schema(description = "状态(0:未上架,1:上架)") - @QueryField(type = QueryType.EQ) - private Boolean isShow; - - @Schema(description = "状态, 0上架 1待上架 2待审核 3审核不通过") - @QueryField(type = QueryType.EQ) - private Integer status; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序号") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "用户ID") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "是否删除, 0否, 1是") - @QueryField(type = QueryType.EQ) - private Integer deleted; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsProductSpecParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsProductSpecParam.java deleted file mode 100644 index 6f31993..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsProductSpecParam.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 规格查询参数 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsProductSpecParam对象", description = "规格查询参数") -public class CmsProductSpecParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "规格ID") - @QueryField(type = QueryType.EQ) - private Integer specId; - - @Schema(description = "规格名称") - private String specName; - - @Schema(description = "规格值") - private String specValue; - - @Schema(description = "创建用户") - @QueryField(type = QueryType.EQ) - private Integer userId; - - @Schema(description = "更新者") - @QueryField(type = QueryType.EQ) - private Integer updater; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "状态, 0正常, 1待修,2异常已修,3异常未修") - @QueryField(type = QueryType.EQ) - private Integer status; - - @Schema(description = "排序号") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsProductSpecValueParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsProductSpecValueParam.java deleted file mode 100644 index e8e1174..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsProductSpecValueParam.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 规格值查询参数 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsProductSpecValueParam对象", description = "规格值查询参数") -public class CmsProductSpecValueParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "规格值ID") - @QueryField(type = QueryType.EQ) - private Integer specValueId; - - @Schema(description = "规格组ID") - @QueryField(type = QueryType.EQ) - private Integer specId; - - @Schema(description = "规格值") - private String specValue; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序号") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - -} diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsProductUrlParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsProductUrlParam.java deleted file mode 100644 index 78be55a..0000000 --- a/src/main/java/com/gxwebsoft/cms/param/CmsProductUrlParam.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.gxwebsoft.cms.param; - -import com.gxwebsoft.common.core.annotation.QueryField; -import com.gxwebsoft.common.core.annotation.QueryType; -import com.gxwebsoft.common.core.web.BaseParam; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 域名查询参数 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(name = "CmsProductUrlParam对象", description = "域名查询参数") -public class CmsProductUrlParam extends BaseParam { - private static final long serialVersionUID = 1L; - - @Schema(description = "自增ID") - @QueryField(type = QueryType.EQ) - private Integer id; - - @Schema(description = "产品ID") - @QueryField(type = QueryType.EQ) - private Integer productId; - - @Schema(description = "域名类型") - private String type; - - @Schema(description = "域名") - private String domain; - - @Schema(description = "账号") - private String account; - - @Schema(description = "密码") - private String password; - - @Schema(description = "商户ID") - @QueryField(type = QueryType.EQ) - private Long merchantId; - - @Schema(description = "备注") - private String comments; - - @Schema(description = "排序(数字越小越靠前)") - @QueryField(type = QueryType.EQ) - private Integer sortNumber; - - @Schema(description = "状态, 0正常, 1待确认") - @QueryField(type = QueryType.EQ) - private Integer status; - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsComponentsService.java b/src/main/java/com/gxwebsoft/cms/service/CmsComponentsService.java deleted file mode 100644 index 6f6de7c..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsComponentsService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsComponents; -import com.gxwebsoft.cms.param.CmsComponentsParam; - -import java.util.List; - -/** - * 组件Service - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsComponentsService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsComponentsParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsComponentsParam param); - - /** - * 根据id查询 - * - * @param id ID - * @return CmsComponents - */ - CmsComponents getByIdRel(Integer id); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsMpAdService.java b/src/main/java/com/gxwebsoft/cms/service/CmsMpAdService.java deleted file mode 100644 index de40752..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsMpAdService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsMpAd; -import com.gxwebsoft.cms.param.CmsMpAdParam; - -import java.util.List; - -/** - * 小程序广告位Service - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpAdService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsMpAdParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsMpAdParam param); - - /** - * 根据id查询 - * - * @param adId ID - * @return CmsMpAd - */ - CmsMpAd getByIdRel(Integer adId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsMpFieldService.java b/src/main/java/com/gxwebsoft/cms/service/CmsMpFieldService.java deleted file mode 100644 index e12a68c..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsMpFieldService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsMpField; -import com.gxwebsoft.cms.param.CmsMpFieldParam; - -import java.util.List; - -/** - * 小程序配置Service - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpFieldService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsMpFieldParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsMpFieldParam param); - - /** - * 根据id查询 - * - * @param id 自增ID - * @return CmsMpField - */ - CmsMpField getByIdRel(Integer id); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsMpMenuService.java b/src/main/java/com/gxwebsoft/cms/service/CmsMpMenuService.java deleted file mode 100644 index 133d2ae..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsMpMenuService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsMpMenu; -import com.gxwebsoft.cms.param.CmsMpMenuParam; - -import java.util.List; - -/** - * 小程序端菜单Service - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpMenuService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsMpMenuParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsMpMenuParam param); - - /** - * 根据id查询 - * - * @param menuId ID - * @return CmsMpMenu - */ - CmsMpMenu getByIdRel(Integer menuId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsMpPagesService.java b/src/main/java/com/gxwebsoft/cms/service/CmsMpPagesService.java deleted file mode 100644 index 23ce484..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsMpPagesService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsMpPages; -import com.gxwebsoft.cms.param.CmsMpPagesParam; - -import java.util.List; - -/** - * 小程序页面Service - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpPagesService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsMpPagesParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsMpPagesParam param); - - /** - * 根据id查询 - * - * @param id ID - * @return CmsMpPages - */ - CmsMpPages getByIdRel(Integer id); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsMpService.java b/src/main/java/com/gxwebsoft/cms/service/CmsMpService.java deleted file mode 100644 index 90d9fb1..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsMpService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsMp; -import com.gxwebsoft.cms.param.CmsMpParam; - -import java.util.List; - -/** - * 小程序信息Service - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -public interface CmsMpService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsMpParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsMpParam param); - - /** - * 根据id查询 - * - * @param mpId ID - * @return CmsMp - */ - CmsMp getByIdRel(Integer mpId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsOrderService.java b/src/main/java/com/gxwebsoft/cms/service/CmsOrderService.java deleted file mode 100644 index 2950d01..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsOrderService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsOrder; -import com.gxwebsoft.cms.param.CmsOrderParam; - -import java.util.List; - -/** - * 订单Service - * - * @author 科技小王子 - * @since 2024-11-25 12:14:05 - */ -public interface CmsOrderService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsOrderParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsOrderParam param); - - /** - * 根据id查询 - * - * @param orderId 订单号 - * @return CmsOrder - */ - CmsOrder getByIdRel(Integer orderId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsProductService.java b/src/main/java/com/gxwebsoft/cms/service/CmsProductService.java deleted file mode 100644 index 00ef8bd..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsProductService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsProduct; -import com.gxwebsoft.cms.param.CmsProductParam; - -import java.util.List; - -/** - * 产品Service - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsProductParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsProductParam param); - - /** - * 根据id查询 - * - * @param productId 自增ID - * @return CmsProduct - */ - CmsProduct getByIdRel(Integer productId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsProductSpecService.java b/src/main/java/com/gxwebsoft/cms/service/CmsProductSpecService.java deleted file mode 100644 index d2beb35..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsProductSpecService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsProductSpec; -import com.gxwebsoft.cms.param.CmsProductSpecParam; - -import java.util.List; - -/** - * 规格Service - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductSpecService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsProductSpecParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsProductSpecParam param); - - /** - * 根据id查询 - * - * @param specId 规格ID - * @return CmsProductSpec - */ - CmsProductSpec getByIdRel(Integer specId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsProductSpecValueService.java b/src/main/java/com/gxwebsoft/cms/service/CmsProductSpecValueService.java deleted file mode 100644 index 29a94c0..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsProductSpecValueService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsProductSpecValue; -import com.gxwebsoft.cms.param.CmsProductSpecValueParam; - -import java.util.List; - -/** - * 规格值Service - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductSpecValueService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsProductSpecValueParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsProductSpecValueParam param); - - /** - * 根据id查询 - * - * @param specValueId 规格值ID - * @return CmsProductSpecValue - */ - CmsProductSpecValue getByIdRel(Integer specValueId); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsProductUrlService.java b/src/main/java/com/gxwebsoft/cms/service/CmsProductUrlService.java deleted file mode 100644 index 6501378..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/CmsProductUrlService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gxwebsoft.cms.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.cms.entity.CmsProductUrl; -import com.gxwebsoft.cms.param.CmsProductUrlParam; - -import java.util.List; - -/** - * 域名Service - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -public interface CmsProductUrlService extends IService { - - /** - * 分页关联查询 - * - * @param param 查询参数 - * @return PageResult - */ - PageResult pageRel(CmsProductUrlParam param); - - /** - * 关联查询全部 - * - * @param param 查询参数 - * @return List - */ - List listRel(CmsProductUrlParam param); - - /** - * 根据id查询 - * - * @param id 自增ID - * @return CmsProductUrl - */ - CmsProductUrl getByIdRel(Integer id); - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsComponentsServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsComponentsServiceImpl.java deleted file mode 100644 index cf90d51..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsComponentsServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsComponentsMapper; -import com.gxwebsoft.cms.service.CmsComponentsService; -import com.gxwebsoft.cms.entity.CmsComponents; -import com.gxwebsoft.cms.param.CmsComponentsParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 组件Service实现 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Service -public class CmsComponentsServiceImpl extends ServiceImpl implements CmsComponentsService { - - @Override - public PageResult pageRel(CmsComponentsParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsComponentsParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsComponents getByIdRel(Integer id) { - CmsComponentsParam param = new CmsComponentsParam(); - param.setId(id); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpAdServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpAdServiceImpl.java deleted file mode 100644 index fa53927..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpAdServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsMpAdMapper; -import com.gxwebsoft.cms.service.CmsMpAdService; -import com.gxwebsoft.cms.entity.CmsMpAd; -import com.gxwebsoft.cms.param.CmsMpAdParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 小程序广告位Service实现 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Service -public class CmsMpAdServiceImpl extends ServiceImpl implements CmsMpAdService { - - @Override - public PageResult pageRel(CmsMpAdParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsMpAdParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsMpAd getByIdRel(Integer adId) { - CmsMpAdParam param = new CmsMpAdParam(); - param.setAdId(adId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpFieldServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpFieldServiceImpl.java deleted file mode 100644 index 68bdca2..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpFieldServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsMpFieldMapper; -import com.gxwebsoft.cms.service.CmsMpFieldService; -import com.gxwebsoft.cms.entity.CmsMpField; -import com.gxwebsoft.cms.param.CmsMpFieldParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 小程序配置Service实现 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Service -public class CmsMpFieldServiceImpl extends ServiceImpl implements CmsMpFieldService { - - @Override - public PageResult pageRel(CmsMpFieldParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsMpFieldParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsMpField getByIdRel(Integer id) { - CmsMpFieldParam param = new CmsMpFieldParam(); - param.setId(id); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpMenuServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpMenuServiceImpl.java deleted file mode 100644 index eec21fd..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpMenuServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsMpMenuMapper; -import com.gxwebsoft.cms.service.CmsMpMenuService; -import com.gxwebsoft.cms.entity.CmsMpMenu; -import com.gxwebsoft.cms.param.CmsMpMenuParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 小程序端菜单Service实现 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Service -public class CmsMpMenuServiceImpl extends ServiceImpl implements CmsMpMenuService { - - @Override - public PageResult pageRel(CmsMpMenuParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsMpMenuParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsMpMenu getByIdRel(Integer menuId) { - CmsMpMenuParam param = new CmsMpMenuParam(); - param.setMenuId(menuId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpPagesServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpPagesServiceImpl.java deleted file mode 100644 index 6226628..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpPagesServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsMpPagesMapper; -import com.gxwebsoft.cms.service.CmsMpPagesService; -import com.gxwebsoft.cms.entity.CmsMpPages; -import com.gxwebsoft.cms.param.CmsMpPagesParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 小程序页面Service实现 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Service -public class CmsMpPagesServiceImpl extends ServiceImpl implements CmsMpPagesService { - - @Override - public PageResult pageRel(CmsMpPagesParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsMpPagesParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsMpPages getByIdRel(Integer id) { - CmsMpPagesParam param = new CmsMpPagesParam(); - param.setId(id); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpServiceImpl.java deleted file mode 100644 index d4a8079..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsMpServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsMpMapper; -import com.gxwebsoft.cms.service.CmsMpService; -import com.gxwebsoft.cms.entity.CmsMp; -import com.gxwebsoft.cms.param.CmsMpParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 小程序信息Service实现 - * - * @author 科技小王子 - * @since 2024-09-10 20:47:57 - */ -@Service -public class CmsMpServiceImpl extends ServiceImpl implements CmsMpService { - - @Override - public PageResult pageRel(CmsMpParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsMpParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsMp getByIdRel(Integer mpId) { - CmsMpParam param = new CmsMpParam(); - param.setMpId(mpId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsOrderServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsOrderServiceImpl.java deleted file mode 100644 index 0dda732..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsOrderServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsOrderMapper; -import com.gxwebsoft.cms.service.CmsOrderService; -import com.gxwebsoft.cms.entity.CmsOrder; -import com.gxwebsoft.cms.param.CmsOrderParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 订单Service实现 - * - * @author 科技小王子 - * @since 2024-11-25 12:14:05 - */ -@Service -public class CmsOrderServiceImpl extends ServiceImpl implements CmsOrderService { - - @Override - public PageResult pageRel(CmsOrderParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("sort_number asc, create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsOrderParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("sort_number asc, create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsOrder getByIdRel(Integer orderId) { - CmsOrderParam param = new CmsOrderParam(); - param.setOrderId(orderId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductServiceImpl.java deleted file mode 100644 index a2c4a24..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsProductMapper; -import com.gxwebsoft.cms.service.CmsProductService; -import com.gxwebsoft.cms.entity.CmsProduct; -import com.gxwebsoft.cms.param.CmsProductParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 产品Service实现 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Service -public class CmsProductServiceImpl extends ServiceImpl implements CmsProductService { - - @Override - public PageResult pageRel(CmsProductParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("sort_number asc,create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsProductParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("sort_number asc,create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsProduct getByIdRel(Integer productId) { - CmsProductParam param = new CmsProductParam(); - param.setProductId(productId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductSpecServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductSpecServiceImpl.java deleted file mode 100644 index 6532eba..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductSpecServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsProductSpecMapper; -import com.gxwebsoft.cms.service.CmsProductSpecService; -import com.gxwebsoft.cms.entity.CmsProductSpec; -import com.gxwebsoft.cms.param.CmsProductSpecParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 规格Service实现 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Service -public class CmsProductSpecServiceImpl extends ServiceImpl implements CmsProductSpecService { - - @Override - public PageResult pageRel(CmsProductSpecParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsProductSpecParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsProductSpec getByIdRel(Integer specId) { - CmsProductSpecParam param = new CmsProductSpecParam(); - param.setSpecId(specId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductSpecValueServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductSpecValueServiceImpl.java deleted file mode 100644 index c004b49..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductSpecValueServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsProductSpecValueMapper; -import com.gxwebsoft.cms.service.CmsProductSpecValueService; -import com.gxwebsoft.cms.entity.CmsProductSpecValue; -import com.gxwebsoft.cms.param.CmsProductSpecValueParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 规格值Service实现 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Service -public class CmsProductSpecValueServiceImpl extends ServiceImpl implements CmsProductSpecValueService { - - @Override - public PageResult pageRel(CmsProductSpecValueParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsProductSpecValueParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); - return page.sortRecords(list); - } - - @Override - public CmsProductSpecValue getByIdRel(Integer specValueId) { - CmsProductSpecValueParam param = new CmsProductSpecValueParam(); - param.setSpecValueId(specValueId); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductUrlServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductUrlServiceImpl.java deleted file mode 100644 index 041f6b7..0000000 --- a/src/main/java/com/gxwebsoft/cms/service/impl/CmsProductUrlServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gxwebsoft.cms.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.gxwebsoft.cms.mapper.CmsProductUrlMapper; -import com.gxwebsoft.cms.service.CmsProductUrlService; -import com.gxwebsoft.cms.entity.CmsProductUrl; -import com.gxwebsoft.cms.param.CmsProductUrlParam; -import com.gxwebsoft.common.core.web.PageParam; -import com.gxwebsoft.common.core.web.PageResult; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * 域名Service实现 - * - * @author 科技小王子 - * @since 2024-09-27 16:03:44 - */ -@Service -public class CmsProductUrlServiceImpl extends ServiceImpl implements CmsProductUrlService { - - @Override - public PageResult pageRel(CmsProductUrlParam param) { - PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time asc"); - List list = baseMapper.selectPageRel(page, param); - return new PageResult<>(list, page.getTotal()); - } - - @Override - public List listRel(CmsProductUrlParam param) { - List list = baseMapper.selectListRel(param); - // 排序 - PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time asc"); - return page.sortRecords(list); - } - - @Override - public CmsProductUrl getByIdRel(Integer id) { - CmsProductUrlParam param = new CmsProductUrlParam(); - param.setId(id); - return param.getOne(baseMapper.selectListRel(param)); - } - -} diff --git a/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java index 9651cce..933deac 100644 --- a/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java +++ b/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java @@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.extra.qrcode.QrCodeUtil; import cn.hutool.extra.qrcode.QrConfig; +import org.springframework.beans.factory.annotation.Value; import javax.annotation.Resource; import javax.imageio.ImageIO; @@ -22,6 +23,9 @@ import static com.gxwebsoft.common.core.constants.QRCodeConstants.*; */ public class MyQrCodeUtil { + @Value("${config.upload-path}") + private static String uploadPath; + private static final String logoUrl = "https://file.wsdns.cn/20230430/6fa31aca3b0d47af98a149cf2dd26a4f.jpeg"; /** @@ -60,7 +64,7 @@ public class MyQrCodeUtil { * @return 二维码图片地址 */ public static String createQrCode(String type,Integer id, String content) throws IOException { - String filePath = "/www/wwwroot/file.ws/file/qrcode/".concat(type).concat("/"); + String filePath = uploadPath + "/file/qrcode/".concat(type).concat("/"); String qrcodeUrl = "https://file.websoft.top/qrcode/".concat(type).concat("/"); // 将URL转为BufferedImage BufferedImage bufferedImage = ImageIO.read(new URL(logoUrl)); diff --git a/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java index c07ab55..b09cd9a 100644 --- a/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java +++ b/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java @@ -183,7 +183,7 @@ public class SignCheckUtil { return true; } // 服务器域名白名单列表 - whiteDomains.add("server.gxwebsoft.com"); + whiteDomains.add("server.websoft.top"); System.out.println("whiteDomains = " + whiteDomains); System.out.println(">>> domainName = " + domainName); for(String item: whiteDomains){ diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java index 79905fd..23326d2 100644 --- a/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java +++ b/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java @@ -3,12 +3,13 @@ package com.gxwebsoft.common.core.utils; import com.gxwebsoft.common.core.config.CertificateProperties; import com.gxwebsoft.common.system.entity.Payment; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; /** * 微信支付配置验证工具 - * + * * @author 科技小王子 * @since 2025-07-27 */ @@ -19,6 +20,9 @@ public class WechatPayConfigValidator { private final CertificateProperties certConfig; private final CertificateLoader certificateLoader; + @Value("${spring.profiles.active}") + private String activeProfile; + public WechatPayConfigValidator(CertificateProperties certConfig, CertificateLoader certificateLoader) { this.certConfig = certConfig; this.certificateLoader = certificateLoader; @@ -26,34 +30,34 @@ public class WechatPayConfigValidator { /** * 验证微信支付配置 - * + * * @param payment 支付配置 * @param tenantId 租户ID * @return 验证结果 */ public ValidationResult validateWechatPayConfig(Payment payment, Integer tenantId) { ValidationResult result = new ValidationResult(); - + log.info("开始验证微信支付配置 - 租户ID: {}", tenantId); - + // 1. 验证基本配置 if (payment == null) { result.addError("支付配置为空"); return result; } - + if (!StringUtils.hasText(payment.getMchId())) { result.addError("商户号未配置"); } - + if (!StringUtils.hasText(payment.getAppId())) { result.addError("应用ID未配置"); } - + if (!StringUtils.hasText(payment.getMerchantSerialNumber())) { result.addError("商户证书序列号未配置"); } - + // 2. 验证 APIv3 密钥 String apiV3Key = getValidApiV3Key(payment); if (!StringUtils.hasText(apiV3Key)) { @@ -61,35 +65,35 @@ public class WechatPayConfigValidator { } else { validateApiV3Key(apiV3Key, result); } - + // 3. 验证证书文件 validateCertificateFiles(tenantId, result); - + // 4. 记录验证结果 if (result.isValid()) { log.info("✅ 微信支付配置验证通过 - 租户ID: {}", tenantId); } else { log.error("❌ 微信支付配置验证失败 - 租户ID: {}, 错误: {}", tenantId, result.getErrors()); } - + return result; } - + /** * 获取有效的 APIv3 密钥 * 优先使用数据库配置,如果为空则使用配置文件默认值 */ public String getValidApiV3Key(Payment payment) { String apiV3Key = payment.getApiKey(); - + if (!StringUtils.hasText(apiV3Key)) { apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); log.warn("数据库中APIv3密钥为空,使用配置文件默认值"); } - + return apiV3Key; } - + /** * 验证 APIv3 密钥格式 */ @@ -97,43 +101,49 @@ public class WechatPayConfigValidator { if (apiV3Key.length() != 32) { result.addError("APIv3密钥长度错误,应为32位,实际为: " + apiV3Key.length()); } - + if (!apiV3Key.matches("^[a-zA-Z0-9]+$")) { result.addError("APIv3密钥格式错误,应仅包含字母和数字"); } - - log.info("APIv3密钥验证 - 长度: {}, 格式: {}", - apiV3Key.length(), + + log.info("APIv3密钥验证 - 长度: {}, 格式: {}", + apiV3Key.length(), apiV3Key.matches("^[a-zA-Z0-9]+$") ? "正确" : "错误"); } - + /** * 验证证书文件 */ private void validateCertificateFiles(Integer tenantId, ValidationResult result) { - String tenantCertPath = "dev/wechat/" + tenantId; - String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); - - if (!certificateLoader.certificateExists(privateKeyPath)) { - result.addError("证书文件不存在: " + privateKeyPath); - return; - } - - try { - String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); - log.info("✅ 证书文件验证通过: {}", privateKey); - } catch (Exception e) { - result.addError("证书文件加载失败: " + e.getMessage()); + if ("dev".equals(activeProfile)) { + // 开发环境证书验证 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + if (!certificateLoader.certificateExists(privateKeyPath)) { + result.addError("证书文件不存在: " + privateKeyPath); + return; + } + + try { + certificateLoader.loadCertificatePath(privateKeyPath); + log.info("✅ 开发环境证书文件验证通过: {}", privateKeyPath); + } catch (Exception e) { + result.addError("证书文件加载失败: " + e.getMessage()); + } + } else { + // 生产环境证书验证 - 跳过文件存在性检查,因为证书路径来自数据库 + log.info("✅ 生产环境跳过证书文件存在性验证,使用数据库配置的证书路径"); } } - + /** * 验证结果类 */ public static class ValidationResult { private boolean valid = true; private StringBuilder errors = new StringBuilder(); - + public void addError(String error) { this.valid = false; if (errors.length() > 0) { @@ -141,22 +151,22 @@ public class WechatPayConfigValidator { } errors.append(error); } - + public boolean isValid() { return valid; } - + public String getErrors() { return errors.toString(); } - + public void logErrors() { if (!valid) { log.error("配置验证失败: {}", errors.toString()); } } } - + /** * 生成配置诊断报告 */ @@ -164,41 +174,50 @@ public class WechatPayConfigValidator { StringBuilder report = new StringBuilder(); report.append("=== 微信支付配置诊断报告 ===\n"); report.append("租户ID: ").append(tenantId).append("\n"); - + if (payment != null) { report.append("商户号: ").append(payment.getMchId()).append("\n"); report.append("应用ID: ").append(payment.getAppId()).append("\n"); report.append("商户证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); - + String dbApiKey = payment.getApiKey(); String configApiKey = certConfig.getWechatPay().getDev().getApiV3Key(); - + report.append("数据库APIv3密钥: ").append(dbApiKey != null ? "已配置(" + dbApiKey.length() + "位)" : "未配置").append("\n"); report.append("配置文件APIv3密钥: ").append(configApiKey != null ? "已配置(" + configApiKey.length() + "位)" : "未配置").append("\n"); - + String finalApiKey = getValidApiV3Key(payment); report.append("最终使用APIv3密钥: ").append(finalApiKey != null ? "已配置(" + finalApiKey.length() + "位)" : "未配置").append("\n"); - + } else { report.append("❌ 支付配置为空\n"); } - + // 证书文件检查 - String tenantCertPath = "dev/wechat/" + tenantId; - String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); - boolean certExists = certificateLoader.certificateExists(privateKeyPath); - - report.append("证书文件路径: ").append(privateKeyPath).append("\n"); - report.append("证书文件存在: ").append(certExists ? "是" : "否").append("\n"); - + report.append("当前环境: ").append(activeProfile).append("\n"); + if ("dev".equals(activeProfile)) { + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + boolean certExists = certificateLoader.certificateExists(privateKeyPath); + + report.append("开发环境证书文件路径: ").append(privateKeyPath).append("\n"); + report.append("证书文件存在: ").append(certExists ? "是" : "否").append("\n"); + } else { + report.append("生产环境证书路径: 从数据库配置获取\n"); + if (payment != null) { + report.append("私钥文件: ").append(payment.getApiclientKey()).append("\n"); + report.append("证书文件: ").append(payment.getApiclientCert()).append("\n"); + } + } + ValidationResult validation = validateWechatPayConfig(payment, tenantId); report.append("配置验证结果: ").append(validation.isValid() ? "通过" : "失败").append("\n"); if (!validation.isValid()) { report.append("验证错误: ").append(validation.getErrors()).append("\n"); } - + report.append("=== 诊断报告结束 ==="); - + return report.toString(); } } diff --git a/src/main/java/com/gxwebsoft/house/controller/HouseInfoController.java b/src/main/java/com/gxwebsoft/house/controller/HouseInfoController.java index bd9793b..05a4758 100644 --- a/src/main/java/com/gxwebsoft/house/controller/HouseInfoController.java +++ b/src/main/java/com/gxwebsoft/house/controller/HouseInfoController.java @@ -8,6 +8,7 @@ import com.gxwebsoft.house.entity.HouseViewsLog; import com.gxwebsoft.house.service.HouseInfoService; import com.gxwebsoft.house.entity.HouseInfo; import com.gxwebsoft.house.param.HouseInfoParam; +import com.gxwebsoft.house.util.SortSceneUtil; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageParam; @@ -44,10 +45,17 @@ public class HouseInfoController extends BaseController { @Operation(summary = "分页查询房源信息表") @GetMapping("/page") public ApiResult> page(HouseInfoParam param) { + // 标准化排序参数,解决URL编码问题 + if (param.getSortScene() != null) { + String normalizedSortScene = SortSceneUtil.normalizeSortScene(param.getSortScene()); + param.setSortScene(normalizedSortScene); + } + // 使用关联查询 return success(houseInfoService.pageRel(param)); } + @PreAuthorize("hasAuthority('house:houseInfo:list')") @Operation(summary = "查询全部房源信息表") @GetMapping() diff --git a/src/main/java/com/gxwebsoft/house/controller/HouseTestDataController.java b/src/main/java/com/gxwebsoft/house/controller/HouseTestDataController.java new file mode 100644 index 0000000..38e9140 --- /dev/null +++ b/src/main/java/com/gxwebsoft/house/controller/HouseTestDataController.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.house.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.house.entity.HouseInfo; +import com.gxwebsoft.house.service.HouseInfoService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 房源测试数据控制器 + * + * @author 科技小王子 + * @since 2025-08-07 + */ +@Tag(name = "房源测试数据管理") +@RestController +@RequestMapping("/api/house/test-data") +public class HouseTestDataController extends BaseController { + + @Resource + private HouseInfoService houseInfoService; + + @Operation(summary = "创建测试数据") + @PostMapping("/create") + public ApiResult createTestData() { + try { + // 创建5个测试房源,价格不同 + createTestHouse("碧园大厦B", "223", new BigDecimal("8920"), 10058); + createTestHouse("碧园大厦B", "155", new BigDecimal("6200"), 10058); + createTestHouse("碧园大厦B", "92", new BigDecimal("3680"), 10058); + createTestHouse("龙光国际A", "99", new BigDecimal("4455"), 10058); + createTestHouse("万达广场C", "120", new BigDecimal("5500"), 10058); + + return success("测试数据创建成功!"); + } catch (Exception e) { + return fail("创建测试数据失败:" + e.getMessage()); + } + } + + private void createTestHouse(String title, String extent, BigDecimal monthlyRent, Integer tenantId) { + HouseInfo house = new HouseInfo(); + house.setHouseTitle(title); + house.setExtent(extent); + house.setMonthlyRent(monthlyRent); + house.setRent(monthlyRent); + house.setTenantId(tenantId); + house.setStatus(0); // 通过状态 + house.setDeleted(0); + house.setRecommend(0); + house.setUserId(1); + house.setCreateTime(new Date()); + house.setUpdateTime(new Date()); + house.setCityByHouse("南宁"); + house.setHouseType("办公室"); + house.setLeaseMethod("整租"); + house.setFloor("10层"); + house.setRealName("测试用户"); + house.setPhone("13800138000"); + house.setProvince("广西"); + house.setCity("南宁"); + house.setRegion("青秀区"); + house.setAddress("测试地址"); + + houseInfoService.save(house); + } +} diff --git a/src/main/java/com/gxwebsoft/house/mapper/xml/HouseInfoMapper.xml b/src/main/java/com/gxwebsoft/house/mapper/xml/HouseInfoMapper.xml index bbc00b5..36c00cb 100644 --- a/src/main/java/com/gxwebsoft/house/mapper/xml/HouseInfoMapper.xml +++ b/src/main/java/com/gxwebsoft/house/mapper/xml/HouseInfoMapper.xml @@ -128,6 +128,14 @@ OR a.room_number LIKE CONCAT('%', #{param.keywords}, '%') ) + + + + + AND a.monthly_rent >= CAST(#{priceMin} AS DECIMAL(10,2)) + AND a.monthly_rent <= CAST(#{priceMax} AS DECIMAL(10,2)) + + @@ -137,24 +145,37 @@ a.create_time desc, - a.monthly_rent asc, + CAST(IFNULL(a.monthly_rent, 0) AS DECIMAL(10,2)) asc, - a.monthly_rent desc, + CAST(IFNULL(a.monthly_rent, 0) AS DECIMAL(10,2)) desc, - a.extent asc, + CASE WHEN a.extent IS NULL OR a.extent = '' THEN 1 ELSE 0 END, + CAST(COALESCE(NULLIF(a.extent, ''), '0') AS DECIMAL(10,2)) asc, - a.extent desc, + CASE WHEN a.extent IS NULL OR a.extent = '' THEN 1 ELSE 0 END, + CAST(COALESCE(NULLIF(a.extent, ''), '0') AS DECIMAL(10,2)) desc, - - ABS(a.monthly_rent - #{param.priceScene}), + + ABS(CAST(COALESCE(a.monthly_rent, 0) AS DECIMAL(10,2)) - CAST(#{param.priceScene} AS DECIMAL(10,2))), - - - ABS(a.extent - #{param.extentScene}), + + ABS(CAST(COALESCE(NULLIF(a.extent, ''), '0') AS DECIMAL(10,2)) - CAST(#{param.extentScene} AS DECIMAL(10,2))), + + + a.sort_number asc, a.create_time desc + + + + + + a.create_time desc + + + a.recommend desc, a.create_time desc diff --git a/src/main/java/com/gxwebsoft/house/service/impl/HouseInfoServiceImpl.java b/src/main/java/com/gxwebsoft/house/service/impl/HouseInfoServiceImpl.java index e4046f7..fb81d24 100644 --- a/src/main/java/com/gxwebsoft/house/service/impl/HouseInfoServiceImpl.java +++ b/src/main/java/com/gxwebsoft/house/service/impl/HouseInfoServiceImpl.java @@ -63,7 +63,10 @@ public class HouseInfoServiceImpl extends ServiceImpl pageRel(HouseInfoParam param) { PageParam page = new PageParam<>(param); - page.setDefaultOrder("create_time desc"); + // 只有在没有指定排序场景时才设置默认排序 + if (param.getSortScene() == null || param.getSortScene().isEmpty()) { + page.setDefaultOrder("create_time desc"); + } List list = baseMapper.selectPageRel(page, param); return new PageResult<>(list, page.getTotal()); } @@ -73,7 +76,10 @@ public class HouseInfoServiceImpl extends ServiceImpl list = baseMapper.selectListRel(param); // 排序 PageParam page = new PageParam<>(); - page.setDefaultOrder("create_time desc"); + // 只有在没有指定排序场景时才使用默认排序 + if (param.getSortScene() == null || param.getSortScene().isEmpty()) { + page.setDefaultOrder("create_time desc"); + } return page.sortRecords(list); } @@ -182,7 +188,7 @@ public class HouseInfoServiceImpl extends ServiceImpl phoneNumbers; - + /** * 测试支付金额 */ private BigDecimal testPayAmount = new BigDecimal("0.01"); - + /** * 是否启用测试模式 */ @@ -57,22 +57,22 @@ public class OrderConfigProperties { * 租户ID */ private Integer tenantId; - + /** * 租户名称 */ private String tenantName; - + /** * 最小金额限制 */ private BigDecimal minAmount; - + /** * 金额限制提示信息 */ private String minAmountMessage; - + /** * 是否启用 */ @@ -81,16 +81,22 @@ public class OrderConfigProperties { @Data public static class DefaultConfig { + + /** + * 默认标题 + */ + private String defaultTitle = "订单标题"; + /** * 默认备注 */ private String defaultComments = "暂无"; - + /** * 最小订单金额 */ private BigDecimal minOrderAmount = BigDecimal.ZERO; - + /** * 订单超时时间(分钟) */ @@ -101,8 +107,8 @@ public class OrderConfigProperties { * 检查是否为测试账号 */ public boolean isTestAccount(String phone) { - return testAccount.isEnabled() && - testAccount.getPhoneNumbers() != null && + return testAccount.isEnabled() && + testAccount.getPhoneNumbers() != null && testAccount.getPhoneNumbers().contains(phone); } diff --git a/src/main/java/com/gxwebsoft/shop/controller/CouponBusinessController.java b/src/main/java/com/gxwebsoft/shop/controller/CouponBusinessController.java new file mode 100644 index 0000000..123e8ca --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/controller/CouponBusinessController.java @@ -0,0 +1,178 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.service.CouponBusinessService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 优惠券业务控制器 + * + * @author 科技小王子 + * @since 2025-08-08 22:30:00 + */ +@Tag(name = "优惠券业务管理") +@RestController +@RequestMapping("/api/shop/coupon-business") +public class CouponBusinessController extends BaseController { + + @Resource + private CouponBusinessService couponBusinessService; + + @Operation(summary = "获取订单可用优惠券") + @PostMapping("/available-for-order") + public ApiResult> getAvailableCouponsForOrder( + @RequestBody Map orderData) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + + @SuppressWarnings("unchecked") + List> goodsItems = (List>) orderData.get("goodsItems"); + BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString()); + + List coupons = couponBusinessService.getAvailableCouponsForOrder( + loginUser.getUserId(), goodsItems, totalAmount); + + return success(coupons); + } + + @Operation(summary = "计算使用优惠券后的订单金额") + @PostMapping("/calculate-order-amount") + public ApiResult> calculateOrderAmountWithCoupon( + @RequestParam Long userCouponId, + @RequestBody Map orderData) { + + @SuppressWarnings("unchecked") + List> goodsItems = (List>) orderData.get("goodsItems"); + BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString()); + + Map result = couponBusinessService.calculateOrderAmountWithCoupon( + userCouponId, goodsItems, totalAmount); + + return success(result); + } + + @Operation(summary = "验证优惠券是否可用于订单") + @PostMapping("/validate-for-order") + public ApiResult> validateCouponForOrder( + @RequestParam Long userCouponId, + @RequestBody Map orderData) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + + @SuppressWarnings("unchecked") + List> goodsItems = (List>) orderData.get("goodsItems"); + BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString()); + + Map result = couponBusinessService.validateCouponForOrder( + userCouponId, loginUser.getUserId(), goodsItems, totalAmount); + + return success(result); + } + + @Operation(summary = "推荐最优优惠券组合") + @PostMapping("/recommend-best-combination") + public ApiResult> recommendBestCouponCombination( + @RequestBody Map orderData) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + + @SuppressWarnings("unchecked") + List> goodsItems = (List>) orderData.get("goodsItems"); + BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString()); + + Map result = couponBusinessService.recommendBestCouponCombination( + loginUser.getUserId(), goodsItems, totalAmount); + + return success(result); + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @OperationLog + @Operation(summary = "为新用户发放欢迎优惠券") + @PostMapping("/issue-welcome/{userId}") + public ApiResult issueWelcomeCoupons(@PathVariable Integer userId) { + int count = couponBusinessService.issueWelcomeCoupons(userId); + return success("成功发放" + count + "张欢迎优惠券"); + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @OperationLog + @Operation(summary = "为用户发放生日优惠券") + @PostMapping("/issue-birthday/{userId}") + public ApiResult issueBirthdayCoupons(@PathVariable Integer userId) { + int count = couponBusinessService.issueBirthdayCoupons(userId); + return success("成功发放" + count + "张生日优惠券"); + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @OperationLog + @Operation(summary = "根据消费金额发放优惠券") + @PostMapping("/issue-consume/{userId}") + public ApiResult issueConsumeCoupons(@PathVariable Integer userId, + @RequestParam BigDecimal consumeAmount) { + int count = couponBusinessService.issueConsumeCoupons(userId, consumeAmount); + return success("成功发放" + count + "张消费返券"); + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @OperationLog + @Operation(summary = "批量发放活动优惠券") + @PostMapping("/batch-issue-activity") + public ApiResult> batchIssueActivityCoupons( + @RequestParam String activityName, + @RequestParam List couponIds, + @RequestParam(required = false) List userIds) { + + Map result = couponBusinessService.batchIssueActivityCoupons( + activityName, couponIds, userIds); + + return success(result); + } + + @PreAuthorize("hasAuthority('shop:coupon:statistics')") + @Operation(summary = "获取优惠券使用统计") + @GetMapping("/usage-statistics") + public ApiResult> getCouponUsageStatistics( + @RequestParam(required = false) String startDate, + @RequestParam(required = false) String endDate) { + + Map statistics = couponBusinessService.getCouponUsageStatistics(startDate, endDate); + return success(statistics); + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @OperationLog + @Operation(summary = "手动处理过期优惠券") + @PostMapping("/process-expired") + public ApiResult processExpiredCoupons() { + int count = couponBusinessService.autoProcessExpiredCoupons(); + return success("处理了" + count + "张过期优惠券"); + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @OperationLog + @Operation(summary = "发送优惠券到期提醒") + @PostMapping("/send-expiry-reminder") + public ApiResult sendExpiryReminder(@RequestParam(defaultValue = "3") Integer days) { + int count = couponBusinessService.sendCouponExpiryReminder(days); + return success("向" + count + "个用户发送了到期提醒"); + } +} diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopCouponController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopCouponController.java new file mode 100644 index 0000000..fe62651 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopCouponController.java @@ -0,0 +1,126 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; +import com.gxwebsoft.shop.service.ShopCouponService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 优惠券控制器 + * + * @author 科技小王子 + * @since 2025-08-08 21:10:55 + */ +@Tag(name = "优惠券管理") +@RestController +@RequestMapping("/api/shop/shop-coupon") +public class ShopCouponController extends BaseController { + @Resource + private ShopCouponService shopCouponService; + + @PreAuthorize("hasAuthority('shop:shopCoupon:list')") + @Operation(summary = "批量修改优惠券") + @GetMapping("/page") + public ApiResult> page(ShopCouponParam param) { + // 使用关联查询 + return success(shopCouponService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:list')") + @Operation(summary = "查询全部优惠券") + @GetMapping() + public ApiResult> list(ShopCouponParam param) { + // 使用关联查询 + return success(shopCouponService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:list')") + @Operation(summary = "根据id查询优惠券") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCouponService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:save')") + @OperationLog + @Operation(summary = "添加优惠券") + @PostMapping() + public ApiResult save(@RequestBody ShopCoupon shopCoupon) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopCoupon.setUserId(loginUser.getUserId()); + } + if (shopCouponService.save(shopCoupon)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:update')") + @OperationLog + @Operation(summary = "修改优惠券") + @PutMapping() + public ApiResult update(@RequestBody ShopCoupon shopCoupon) { + if (shopCouponService.updateById(shopCoupon)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:remove')") + @OperationLog + @Operation(summary = "删除优惠券") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCouponService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:save')") + @OperationLog + @Operation(summary = "批量添加优惠券") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCouponService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:update')") + @Operation(summary = "批量修改优惠券") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCouponService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:remove')") + @Operation(summary = "批量删除优惠券") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCouponService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java index c7cda0f..6659afa 100644 --- a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java @@ -212,6 +212,12 @@ public class ShopOrderController extends BaseController { return fail("修复失败"); } + @Operation(summary = "统计订单总金额") + @GetMapping("/total") + public ApiResult total() { + return success(shopOrderService.total()); + } + @Schema(description = "异步通知") @PostMapping("/notify/{tenantId}") public String wxNotify(@RequestHeader Map header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopUserCouponController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopUserCouponController.java new file mode 100644 index 0000000..30f35d7 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopUserCouponController.java @@ -0,0 +1,225 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 用户优惠券控制器 + * + * @author 科技小王子 + * @since 2025-08-08 21:30:00 + */ +@Tag(name = "用户优惠券管理") +@RestController +@RequestMapping("/api/shop/user-coupon") +public class ShopUserCouponController extends BaseController { + + @Resource + private ShopUserCouponService shopUserCouponService; + + @PreAuthorize("hasAuthority('shop:userCoupon:list')") + @Operation(summary = "分页查询用户优惠券") + @GetMapping("/page") + public ApiResult> page(ShopUserCouponParam param) { + return success(shopUserCouponService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:list')") + @Operation(summary = "查询用户优惠券列表") + @GetMapping() + public ApiResult> list(ShopUserCouponParam param) { + return success(shopUserCouponService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:list')") + @Operation(summary = "根据id查询用户优惠券") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Long id) { + return success(shopUserCouponService.getByIdRel(id)); + } + + @Operation(summary = "获取当前用户的优惠券列表") + @GetMapping("/my") + public ApiResult> getMyCoupons(ShopUserCouponParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + param.setUserId(loginUser.getUserId()); + return success(shopUserCouponService.listRel(param)); + } + + @Operation(summary = "获取当前用户可用的优惠券") + @GetMapping("/my/available") + public ApiResult> getMyAvailableCoupons( + @RequestParam(required = false) Integer goodsId, + @RequestParam(required = false) Integer categoryId, + @RequestParam(required = false) BigDecimal orderAmount) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + + List coupons = shopUserCouponService.getAvailableCoupons( + loginUser.getUserId(), goodsId, categoryId, orderAmount); + return success(coupons); + } + + @Operation(summary = "统计当前用户优惠券数量") + @GetMapping("/my/count") + public ApiResult> getMyCount() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + + Map count = shopUserCouponService.countUserCoupons(loginUser.getUserId()); + return success(count); + } + + @OperationLog + @Operation(summary = "领取优惠券") + @PostMapping("/receive/{couponId}") + public ApiResult receiveCoupon(@PathVariable("couponId") Integer couponId) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + + // 检查是否可以领取 + Map checkResult = shopUserCouponService.checkCanReceiveCoupon( + loginUser.getUserId(), couponId); + + if (!(Boolean) checkResult.get("canReceive")) { + return fail(checkResult.get("reason").toString()); + } + + boolean success = shopUserCouponService.receiveCoupon(loginUser.getUserId(), couponId); + if (success) { + return success("领取成功"); + } + return fail("领取失败"); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:save')") + @OperationLog + @Operation(summary = "系统发放优惠券给用户") + @PostMapping("/issue") + public ApiResult issueCoupon(@RequestParam Integer userId, + @RequestParam Integer couponId, + @RequestParam(required = false) String source) { + boolean success = shopUserCouponService.issueCouponToUser(userId, couponId, source); + if (success) { + return success("发放成功"); + } + return fail("发放失败"); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:save')") + @OperationLog + @Operation(summary = "批量发放优惠券") + @PostMapping("/batch-issue") + public ApiResult batchIssueCoupons(@RequestParam List userIds, + @RequestParam Integer couponId, + @RequestParam(required = false) String source) { + int successCount = shopUserCouponService.batchIssueCoupons(userIds, couponId, source); + return success("成功发放" + successCount + "张优惠券"); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:update')") + @OperationLog + @Operation(summary = "使用优惠券") + @PutMapping("/use") + public ApiResult useCoupon(@RequestParam Long userCouponId, + @RequestParam Long orderId, + @RequestParam String orderNo) { + boolean success = shopUserCouponService.useCoupon(userCouponId, orderId, orderNo); + if (success) { + return success("使用成功"); + } + return fail("使用失败"); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:update')") + @OperationLog + @Operation(summary = "退还优惠券") + @PutMapping("/return/{orderId}") + public ApiResult returnCoupon(@PathVariable("orderId") Long orderId) { + boolean success = shopUserCouponService.returnCoupon(orderId); + if (success) { + return success("退还成功"); + } + return fail("退还失败"); + } + + @Operation(summary = "计算优惠券优惠金额") + @PostMapping("/calculate-discount") + public ApiResult calculateDiscount(@RequestParam Long userCouponId, + @RequestParam BigDecimal orderAmount) { + ShopUserCoupon userCoupon = shopUserCouponService.getById(userCouponId); + if (userCoupon == null) { + return fail("优惠券不存在",null); + } + + BigDecimal discountAmount = shopUserCouponService.calculateDiscountAmount(userCoupon, orderAmount); + return success(discountAmount); + } + + @Operation(summary = "验证优惠券是否可用于指定商品") + @GetMapping("/validate") + public ApiResult validateCoupon(@RequestParam Long userCouponId, + @RequestParam(required = false) Integer goodsId, + @RequestParam(required = false) Integer categoryId) { + ShopUserCoupon userCoupon = shopUserCouponService.getById(userCouponId); + if (userCoupon == null) { + return fail("优惠券不存在",null); + } + + boolean valid = shopUserCouponService.validateCouponForGoods(userCoupon, goodsId, categoryId); + return success(valid); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:update')") + @OperationLog + @Operation(summary = "更新过期优惠券状态") + @PutMapping("/update-expired") + public ApiResult updateExpiredCoupons() { + int count = shopUserCouponService.updateExpiredCoupons(); + return success("更新了" + count + "张过期优惠券"); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:list')") + @Operation(summary = "获取即将过期的优惠券") + @GetMapping("/expiring-soon") + public ApiResult> getExpiringSoonCoupons( + @RequestParam(defaultValue = "3") Integer days) { + List coupons = shopUserCouponService.getExpiringSoonCoupons(days); + return success(coupons); + } + + @PreAuthorize("hasAuthority('shop:userCoupon:remove')") + @OperationLog + @Operation(summary = "删除用户优惠券") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Long id) { + if (shopUserCouponService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } +} diff --git a/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java b/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java index 86f21ff..2bbff71 100644 --- a/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java +++ b/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java @@ -2,8 +2,8 @@ package com.gxwebsoft.shop.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import com.fasterxml.jackson.annotation.JsonProperty; +import javax.validation.Valid; import javax.validation.constraints.*; import java.math.BigDecimal; import java.util.List; @@ -24,6 +24,10 @@ public class OrderCreateRequest { @Max(value = 2, message = "订单类型值无效") private Integer type; + @Size(max = 60, message = "备注长度不能超过60个字符") + @Schema(description = "订单标题") + private String title; + @Schema(description = "快递/自提") private Integer deliveryType; @@ -45,9 +49,15 @@ public class OrderCreateRequest { @Schema(description = "使用的会员卡id") private String cardId; + @Schema(description = "关联收货地址") + private Integer addressId; + @Schema(description = "收货地址") private String address; + @Schema(description = "收货人姓名") + private String realName; + @Schema(description = "地址纬度") private String addressLat; @@ -105,18 +115,6 @@ public class OrderCreateRequest { @Schema(description = "来源ID,存商品ID") private Integer formId; - @Schema(description = "商品ID(兼容字段)") - @JsonProperty("goodsId") - private Integer goodsId; - - @Schema(description = "购买数量(兼容字段)") - @JsonProperty("quantity") - private Integer quantity; - - @Schema(description = "商品项目列表(支持多商品下单)") - @JsonProperty("goodsItems") - private List goodsItems; - @Schema(description = "支付类型,0余额支付, 1微信支付,102微信Native,2会员卡支付,3支付宝,4现金,5POS机,6VIP月卡,7VIP年卡,8VIP次卡,9IC月卡,10IC年卡,11IC次卡,12免费,13VIP充值卡,14IC充值卡,15积分支付,16VIP季卡,17IC季卡,18代付") private Integer payType; @@ -143,54 +141,33 @@ public class OrderCreateRequest { @NotNull(message = "租户ID不能为空") private Integer tenantId; + @Schema(description = "订单商品列表") + @Valid + @NotEmpty(message = "订单商品列表不能为空") + private List goodsItems; + /** - * 商品项目内部类 + * 订单商品项 */ @Data - @Schema(name = "GoodsItem", description = "商品项目") - public static class GoodsItem { - @Schema(description = "商品ID") - @JsonProperty("goodsId") + @Schema(name = "OrderGoodsItem", description = "订单商品项") + public static class OrderGoodsItem { + @Schema(description = "商品ID", required = true) + @NotNull(message = "商品ID不能为空") private Integer goodsId; - @Schema(description = "购买数量") - @JsonProperty("quantity") + @Schema(description = "商品SKU ID") + private Integer skuId; + + @Schema(description = "商品数量", required = true) + @NotNull(message = "商品数量不能为空") + @Min(value = 1, message = "商品数量必须大于0") private Integer quantity; - @Schema(description = "商品价格") - @JsonProperty("price") - private BigDecimal price; - } + @Schema(description = "支付类型") + private Integer payType; - /** - * 获取实际的商品ID(兼容多种字段名) - */ - public Integer getActualFormId() { - if (formId != null) { - return formId; - } - if (goodsId != null) { - return goodsId; - } - if (goodsItems != null && !goodsItems.isEmpty()) { - return goodsItems.get(0).getGoodsId(); - } - return null; - } - - /** - * 获取实际的购买数量(兼容多种字段名) - */ - public Integer getActualTotalNum() { - if (totalNum != null) { - return totalNum; - } - if (quantity != null) { - return quantity; - } - if (goodsItems != null && !goodsItems.isEmpty()) { - return goodsItems.get(0).getQuantity(); - } - return 1; // 默认数量为1 + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; } } diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java b/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java index b28d49d..a2a552b 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java @@ -35,9 +35,15 @@ public class ShopCart implements Serializable { @Schema(description = "商品ID") private Long goodsId; + @Schema(description = "商品SKU ID") + private Integer skuId; + @Schema(description = "商品规格") private String spec; + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; + @Schema(description = "商品价格") private BigDecimal price; diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopCoupon.java b/src/main/java/com/gxwebsoft/shop/entity/ShopCoupon.java new file mode 100644 index 0000000..1c90410 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopCoupon.java @@ -0,0 +1,103 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Date; + +/** + * 优惠券模板 + * + * @author 科技小王子 + * @since 2025-08-08 21:10:55 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("shop_coupon") +@Schema(name = "ShopCoupon对象", description = "优惠券模板") +public class ShopCoupon implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券描述") + private String description; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + private Integer type; + + @Schema(description = "满减券-减免金额") + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + private Integer discount; + + @Schema(description = "最低消费金额") + private BigDecimal minPrice; + + @Schema(description = "发放总数量(-1表示无限制)") + private Integer totalCount; + + @Schema(description = "已发放数量") + private Integer issuedCount; + + @Schema(description = "每人限领数量(-1表示无限制)") + private Integer limitPerUser; + + @Schema(description = "到期类型(10领取后生效 20固定时间)") + private Integer expireType; + + @Schema(description = "领取后生效-有效天数") + private Integer expireDay; + + @Schema(description = "有效期开始时间") + private LocalDate startTime; + + @Schema(description = "有效期结束时间") + private LocalDate endTime; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + private Integer applyRange; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "是否启用(0禁用 1启用)") + private Integer enabled; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1禁用") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + private Date createTime; + + @Schema(description = "修改时间") + private Date updateTime; + +} diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java b/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java index 541b1dd..628b72b 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java @@ -11,12 +11,10 @@ import java.util.List; import com.gxwebsoft.bszx.entity.BszxBm; import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import javax.validation.constraints.*; -import javax.validation.groups.Default; /** * 订单 @@ -40,6 +38,9 @@ public class ShopOrder implements Serializable { @Schema(description = "订单类型,0商城订单 1预定订单/外卖 2会员卡") private Integer type; + @Schema(description = "订单标题") + private String title; + @Schema(description = "快递/自提") private Integer deliveryType; @@ -218,7 +219,6 @@ public class ShopOrder implements Serializable { private String nickname; @Schema(description = "真实姓名") - @TableField(exist = false) private String realName; @Schema(description = "手机号码") @@ -271,5 +271,4 @@ public class ShopOrder implements Serializable { @Schema(description = "报名信息") @TableField(exist = false) private BszxBm bm; - } diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java b/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java index aa2acc6..d9288b9 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java @@ -90,6 +90,9 @@ public class ShopOrderGoods implements Serializable { @Schema(description = "过期时间") private Date expirationTime; + @Schema(description = "排序号") + private Integer sortNumber; + @Schema(description = "备注") private String comments; diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopUserCoupon.java b/src/main/java/com/gxwebsoft/shop/entity/ShopUserCoupon.java new file mode 100644 index 0000000..c4478de --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopUserCoupon.java @@ -0,0 +1,142 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 用户优惠券 + * + * @author 科技小王子 + * @since 2025-08-08 21:30:00 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("shop_user_coupon") +@Schema(name = "ShopUserCoupon对象", description = "用户优惠券") +public class ShopUserCoupon implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "优惠券模板ID") + private Integer couponId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券描述") + private String description; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + private Integer type; + + @Schema(description = "满减券-减免金额") + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + private Integer discount; + + @Schema(description = "最低消费金额") + private BigDecimal minPrice; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + private Integer applyRange; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "有效期开始时间") + private LocalDateTime startTime; + + @Schema(description = "有效期结束时间") + private LocalDateTime endTime; + + @Schema(description = "使用状态(0未使用 1已使用 2已过期)") + private Integer status; + + @Schema(description = "使用时间") + private LocalDateTime useTime; + + @Schema(description = "使用订单ID") + private Long orderId; + + @Schema(description = "使用订单号") + private String orderNo; + + @Schema(description = "获取方式(10主动领取 20系统发放 30活动赠送)") + private Integer obtainType; + + @Schema(description = "获取来源描述") + private String obtainSource; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + private Date createTime; + + @Schema(description = "修改时间") + private Date updateTime; + + // 优惠券状态常量 + public static final int STATUS_UNUSED = 0; // 未使用 + public static final int STATUS_USED = 1; // 已使用 + public static final int STATUS_EXPIRED = 2; // 已过期 + + // 优惠券类型常量 + public static final int TYPE_REDUCE = 10; // 满减券 + public static final int TYPE_DISCOUNT = 20; // 折扣券 + public static final int TYPE_FREE = 30; // 免费券 + + // 适用范围常量 + public static final int APPLY_ALL = 10; // 全部商品 + public static final int APPLY_GOODS = 20; // 指定商品 + public static final int APPLY_CATEGORY = 30; // 指定分类 + + // 获取方式常量 + public static final int OBTAIN_RECEIVE = 10; // 主动领取 + public static final int OBTAIN_SYSTEM = 20; // 系统发放 + public static final int OBTAIN_ACTIVITY = 30; // 活动赠送 + + /** + * 检查优惠券是否已过期 + */ + public boolean isExpired() { + return this.endTime != null && this.endTime.isBefore(LocalDateTime.now()); + } + + /** + * 检查优惠券是否可用 + */ + public boolean isAvailable() { + return this.status == STATUS_UNUSED && !isExpired(); + } + + /** + * 检查优惠券是否在有效期内 + */ + public boolean isInValidPeriod() { + LocalDateTime now = LocalDateTime.now(); + return (this.startTime == null || !this.startTime.isAfter(now)) && + (this.endTime == null || !this.endTime.isBefore(now)); + } +} diff --git a/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.java b/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.java new file mode 100644 index 0000000..3fd46c0 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.shop.enums; + +/** + * 订单状态枚举 + */ +public enum OrderStatusEnum { + ALL(-1, "全部"), + WAIT_PAY(0, "待支付"), + WAIT_DELIVERY(1, "待发货"), + WAIT_CONFIRM(2, "待核销"), + WAIT_RECEIVE(3, "待收货"), + WAIT_EVALUATE(4, "待评价"), + COMPLETED(5, "已完成"), + REFUNDED(6, "已退款"), + DELETED(7, "已删除"); + + private final Integer code; + private final String desc; + + OrderStatusEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + + public Integer getCode() { + return code; + } + + public String getDesc() { + return desc; + } +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponMapper.java b/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponMapper.java new file mode 100644 index 0000000..942cd2a --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponMapper.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 优惠券Mapper + * + * @author 科技小王子 + * @since 2025-08-08 21:10:55 + */ +public interface ShopCouponMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCouponParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCouponParam param); + + /** + * 检查用户是否已领取指定优惠券 + * + * @param userId 用户ID + * @param couponId 优惠券模板ID + * @return 已领取数量 + */ + int countUserReceivedCoupon(@Param("userId") Integer userId, @Param("couponId") Integer couponId); + +} diff --git a/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java b/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java index 21977a6..88aaf0d 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java +++ b/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java @@ -6,8 +6,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.param.ShopOrderParam; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; import java.util.List; /** @@ -41,4 +43,13 @@ public interface ShopOrderMapper extends BaseMapper { @InterceptorIgnore(tenantLine = "true") void updateByOutTradeNo(@Param("param") ShopOrder order); + + /** + * 统计订单总金额 + * 只统计已支付的订单(pay_status = 1)且未删除的订单(deleted = 0) + * + * @return 订单总金额 + */ + @Select("SELECT COALESCE(SUM(pay_price), 0) FROM shop_order WHERE pay_status = 1 AND deleted = 0 AND pay_price IS NOT NULL") + BigDecimal selectTotalAmount(); } diff --git a/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCouponMapper.java b/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCouponMapper.java new file mode 100644 index 0000000..ec6a23d --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCouponMapper.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户优惠券Mapper + * + * @author 科技小王子 + * @since 2025-08-08 21:30:00 + */ +public interface ShopUserCouponMapper extends BaseMapper { + + /** + * 分页查询用户优惠券 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserCouponParam param); + + /** + * 查询用户优惠券列表 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserCouponParam param); + + /** + * 查询用户可用的优惠券 + * + * @param param 查询参数 + * @return List + */ + List selectAvailableCoupons(@Param("param") ShopUserCouponParam param); + + /** + * 统计用户优惠券数量 + * + * @param userId 用户ID + * @return 统计结果 + */ + java.util.Map countUserCoupons(@Param("userId") Integer userId); + + /** + * 查询即将过期的优惠券 + * + * @param days 天数 + * @return List + */ + List selectExpiringSoon(@Param("days") Integer days); + + /** + * 批量更新过期状态 + * + * @return 更新数量 + */ + int updateExpiredStatus(); + + /** + * 检查用户是否已领取指定优惠券 + * + * @param userId 用户ID + * @param couponId 优惠券模板ID + * @return 已领取数量 + */ + int countUserReceivedCoupon(@Param("userId") Integer userId, @Param("couponId") Integer couponId); +} diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponMapper.xml new file mode 100644 index 0000000..4d60726 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponMapper.xml @@ -0,0 +1,96 @@ + + + + + + + SELECT a.* + FROM shop_coupon a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.type = #{param.type} + + + AND a.reduce_price = #{param.reducePrice} + + + AND a.discount = #{param.discount} + + + AND a.min_price = #{param.minPrice} + + + AND a.expire_type = #{param.expireType} + + + AND a.expire_day = #{param.expireDay} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.apply_range = #{param.applyRange} + + + AND a.apply_range_config LIKE CONCAT('%', #{param.applyRangeConfig}, '%') + + + AND a.is_expire = #{param.isExpire} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml index ac73201..bb91f03 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml @@ -130,7 +130,8 @@ - AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + AND (a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.comments LIKE CONCAT('%', #{param.keywords}, '%') ) diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml index 316089c..1c87e30 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml @@ -216,6 +216,41 @@ OR a.comments LIKE CONCAT('%', #{param.keywords}, '%') ) + + + + + AND a.pay_status = 0 + + + + AND a.pay_status = 1 AND a.delivery_status = 10 + + + + AND a.pay_status = 1 AND a.order_status = 0 + + + + AND a.delivery_status = 20 AND a.order_status != 1 + + + + AND a.order_status = 1 + + + + AND a.order_status = 1 + + + + AND a.order_status = 6 + + + + AND a.deleted = 1 + + diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCouponMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCouponMapper.xml new file mode 100644 index 0000000..d517f23 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCouponMapper.xml @@ -0,0 +1,240 @@ + + + + + + + SELECT + a.id, + a.coupon_id, + a.user_id, + a.name, + a.description, + a.type, + a.reduce_price, + a.discount, + a.min_price, + a.apply_range, + a.apply_range_config, + a.start_time, + a.end_time, + a.status, + a.use_time, + a.order_id, + a.order_no, + a.obtain_type, + a.obtain_source, + a.deleted, + a.tenant_id, + a.create_time, + a.update_time, + u.nickname as user_nickname, + u.phone as user_phone + FROM shop_user_coupon a + LEFT JOIN user u ON a.user_id = u.user_id + + a.deleted = 0 + + AND a.tenant_id = #{param.tenantId} + + + AND a.id = #{param.id} + + + AND a.coupon_id = #{param.couponId} + + + AND a.user_id = #{param.userId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.type = #{param.type} + + + AND a.status = #{param.status} + + + AND a.apply_range = #{param.applyRange} + + + AND a.obtain_type = #{param.obtainType} + + + AND a.order_id = #{param.orderId} + + + AND a.order_no = #{param.orderNo} + + + AND a.start_time >= #{param.startTimeBegin} + + + AND a.start_time <= #{param.startTimeEnd} + + + AND a.end_time >= #{param.endTimeBegin} + + + AND a.end_time <= #{param.endTimeEnd} + + + AND a.use_time >= #{param.useTimeBegin} + + + AND a.use_time <= #{param.useTimeEnd} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.end_time IS NULL OR a.end_time > NOW()) + + + AND a.status = 0 + AND (a.start_time IS NULL OR a.start_time <= NOW()) + AND (a.end_time IS NULL OR a.end_time > NOW()) + + + AND (a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.description LIKE CONCAT('%', #{param.keywords}, '%') + OR u.nickname LIKE CONCAT('%', #{param.keywords}, '%') + OR u.phone LIKE CONCAT('%', #{param.keywords}, '%')) + + + + + + + + + + + + + + + + + + + + + + UPDATE shop_user_coupon + SET status = 2, update_time = NOW() + WHERE deleted = 0 + AND status = 0 + AND end_time IS NOT NULL + AND end_time <= NOW() + + + + + + diff --git a/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java b/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java index 4642418..05bd2be 100644 --- a/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java +++ b/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java @@ -37,9 +37,16 @@ public class ShopCartParam extends BaseParam { @Schema(description = "商品ID") private Long goodsId; + @Schema(description = "商品SKU ID") + @QueryField(type = QueryType.EQ) + private Integer skuId; + @Schema(description = "商品规格") private String spec; + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; + @Schema(description = "商品价格") @QueryField(type = QueryType.EQ) private BigDecimal price; diff --git a/src/main/java/com/gxwebsoft/shop/param/ShopCouponParam.java b/src/main/java/com/gxwebsoft/shop/param/ShopCouponParam.java new file mode 100644 index 0000000..64b5ce6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/param/ShopCouponParam.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.shop.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 优惠券查询参数 + * + * @author 科技小王子 + * @since 2025-08-08 21:10:55 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCouponParam对象", description = "优惠券查询参数") +public class ShopCouponParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "满减券-减免金额") + @QueryField(type = QueryType.EQ) + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + @QueryField(type = QueryType.EQ) + private Integer discount; + + @Schema(description = "最低消费金额") + @QueryField(type = QueryType.EQ) + private BigDecimal minPrice; + + @Schema(description = "到期类型(10领取后生效 20固定时间)") + @QueryField(type = QueryType.EQ) + private Integer expireType; + + @Schema(description = "领取后生效-有效天数") + @QueryField(type = QueryType.EQ) + private Integer expireDay; + + @Schema(description = "有效期开始时间") + private String startTime; + + @Schema(description = "有效期结束时间") + private String endTime; + + @Schema(description = "适用范围(10全部商品 20指定商品)") + @QueryField(type = QueryType.EQ) + private Integer applyRange; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "是否过期(0未过期 1已过期)") + @QueryField(type = QueryType.EQ) + private Integer isExpire; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0待使用, 1已使用, 2已失效") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java b/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java index 5b345ee..f60af8a 100644 --- a/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java +++ b/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java @@ -249,4 +249,7 @@ public class ShopOrderParam extends BaseParam { @QueryField(type = QueryType.EQ) private Boolean hasTakeGift; + @Schema(description = "订单状态筛选:-1全部,0待支付,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除") + private Integer statusFilter; + } diff --git a/src/main/java/com/gxwebsoft/shop/param/ShopUserCouponParam.java b/src/main/java/com/gxwebsoft/shop/param/ShopUserCouponParam.java new file mode 100644 index 0000000..3f42bde --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/param/ShopUserCouponParam.java @@ -0,0 +1,84 @@ +package com.gxwebsoft.shop.param; + +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 用户优惠券查询参数 + * + * @author 科技小王子 + * @since 2025-08-08 21:30:00 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "用户优惠券查询参数") +public class ShopUserCouponParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "优惠券模板ID") + private Integer couponId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + private Integer type; + + @Schema(description = "使用状态(0未使用 1已使用 2已过期)") + private Integer status; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + private Integer applyRange; + + @Schema(description = "获取方式(10主动领取 20系统发放 30活动赠送)") + private Integer obtainType; + + @Schema(description = "使用订单ID") + private Long orderId; + + @Schema(description = "使用订单号") + private String orderNo; + + @Schema(description = "有效期开始时间-查询开始") + private LocalDateTime startTimeBegin; + + @Schema(description = "有效期开始时间-查询结束") + private LocalDateTime startTimeEnd; + + @Schema(description = "有效期结束时间-查询开始") + private LocalDateTime endTimeBegin; + + @Schema(description = "有效期结束时间-查询结束") + private LocalDateTime endTimeEnd; + + @Schema(description = "使用时间-查询开始") + private LocalDateTime useTimeBegin; + + @Schema(description = "使用时间-查询结束") + private LocalDateTime useTimeEnd; + + @Schema(description = "是否包含已过期的券(默认false)") + private Boolean includeExpired = false; + + @Schema(description = "是否只查询可用的券(默认false)") + private Boolean onlyAvailable = false; + + @Schema(description = "商品ID(用于筛选可用优惠券)") + private Integer goodsId; + + @Schema(description = "商品分类ID(用于筛选可用优惠券)") + private Integer categoryId; + + @Schema(description = "订单金额(用于筛选可用优惠券)") + private java.math.BigDecimal orderAmount; +} diff --git a/src/main/java/com/gxwebsoft/shop/service/CouponBusinessService.java b/src/main/java/com/gxwebsoft/shop/service/CouponBusinessService.java new file mode 100644 index 0000000..3f6e8de --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/CouponBusinessService.java @@ -0,0 +1,130 @@ +package com.gxwebsoft.shop.service; + +import com.gxwebsoft.shop.entity.ShopUserCoupon; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 优惠券业务服务 + * 处理订单中的优惠券相关业务逻辑 + * + * @author 科技小王子 + * @since 2025-08-08 22:00:00 + */ +public interface CouponBusinessService { + + /** + * 获取用户在指定订单中可用的优惠券 + * + * @param userId 用户ID + * @param goodsItems 商品列表 [{goodsId, categoryId, price, quantity}] + * @param totalAmount 订单总金额 + * @return 可用优惠券列表 + */ + List getAvailableCouponsForOrder(Integer userId, + List> goodsItems, + BigDecimal totalAmount); + + /** + * 计算使用优惠券后的订单金额 + * + * @param userCouponId 用户优惠券ID + * @param goodsItems 商品列表 + * @param totalAmount 订单总金额 + * @return 计算结果 {discountAmount: 优惠金额, finalAmount: 最终金额, valid: 是否有效} + */ + Map calculateOrderAmountWithCoupon(Long userCouponId, + List> goodsItems, + BigDecimal totalAmount); + + /** + * 验证优惠券是否可用于订单 + * + * @param userCouponId 用户优惠券ID + * @param userId 用户ID + * @param goodsItems 商品列表 + * @param totalAmount 订单总金额 + * @return 验证结果 {valid: boolean, reason: String} + */ + Map validateCouponForOrder(Long userCouponId, + Integer userId, + List> goodsItems, + BigDecimal totalAmount); + + /** + * 为新用户发放欢迎优惠券 + * + * @param userId 用户ID + * @return 发放成功的优惠券数量 + */ + int issueWelcomeCoupons(Integer userId); + + /** + * 为用户生日发放生日优惠券 + * + * @param userId 用户ID + * @return 发放成功的优惠券数量 + */ + int issueBirthdayCoupons(Integer userId); + + /** + * 根据用户消费金额发放优惠券 + * + * @param userId 用户ID + * @param consumeAmount 消费金额 + * @return 发放成功的优惠券数量 + */ + int issueConsumeCoupons(Integer userId, BigDecimal consumeAmount); + + /** + * 活动期间批量发放优惠券 + * + * @param activityName 活动名称 + * @param couponIds 优惠券模板ID列表 + * @param userIds 用户ID列表(为空则发放给所有用户) + * @return 发放统计 {totalUsers: 总用户数, totalCoupons: 总优惠券数, successCount: 成功数量} + */ + Map batchIssueActivityCoupons(String activityName, + List couponIds, + List userIds); + + /** + * 获取优惠券使用统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 统计结果 + */ + Map getCouponUsageStatistics(String startDate, String endDate); + + /** + * 自动处理过期优惠券 + * 定时任务调用 + * + * @return 处理数量 + */ + int autoProcessExpiredCoupons(); + + /** + * 发送优惠券到期提醒 + * 定时任务调用 + * + * @param days 提前天数 + * @return 提醒用户数量 + */ + int sendCouponExpiryReminder(Integer days); + + /** + * 推荐最优优惠券组合 + * + * @param userId 用户ID + * @param goodsItems 商品列表 + * @param totalAmount 订单总金额 + * @return 推荐结果 {coupons: 优惠券列表, totalDiscount: 总优惠金额, finalAmount: 最终金额} + */ + Map recommendBestCouponCombination(Integer userId, + List> goodsItems, + BigDecimal totalAmount); +} diff --git a/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java b/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java index 797995c..12fa158 100644 --- a/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java +++ b/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java @@ -5,15 +5,20 @@ import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.shop.config.OrderConfigProperties; import com.gxwebsoft.shop.dto.OrderCreateRequest; -import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.entity.ShopGoodsSku; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.entity.ShopOrderGoods; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -30,9 +35,15 @@ public class OrderBusinessService { @Resource private ShopOrderService shopOrderService; + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + @Resource private ShopGoodsService shopGoodsService; + @Resource + private ShopGoodsSkuService shopGoodsSkuService; + @Resource private OrderConfigProperties orderConfig; @@ -45,24 +56,25 @@ public class OrderBusinessService { */ @Transactional(rollbackFor = Exception.class) public Map createOrder(OrderCreateRequest request, User loginUser) { + // 1. 参数校验 validateOrderRequest(request, loginUser); - // 2. 验证商品信息(从数据库查询) - ShopGoods goods = validateAndGetGoods(request); + // 2. 构建订单对象 + ShopOrder shopOrder = buildShopOrder(request, loginUser); - // 3. 构建订单对象 - ShopOrder shopOrder = buildShopOrder(request, loginUser, goods); - - // 4. 应用业务规则 + // 3. 应用业务规则 applyBusinessRules(shopOrder, loginUser); - // 5. 保存订单 + // 4. 保存订单 boolean saved = shopOrderService.save(shopOrder); if (!saved) { throw new BusinessException("订单保存失败"); } + // 5. 保存订单商品 + saveOrderGoods(request, shopOrder); + // 6. 创建微信支付订单 try { return shopOrderService.createWxOrder(shopOrder); @@ -80,119 +92,135 @@ public class OrderBusinessService { throw new BusinessException("用户未登录"); } - // 检查必填字段 - if (request.getActualFormId() == null) { - throw new BusinessException("商品ID不能为空"); - } + // 验证商品信息并计算总金额 + BigDecimal calculatedTotal = validateAndCalculateTotal(request); - if (request.getActualTotalNum() == null || request.getActualTotalNum() <= 0) { - throw new BusinessException("购买数量必须大于0"); - } - - // 如果没有传递总价,先跳过验证,后续会根据商品信息计算 - if (request.getTotalPrice() != null && request.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) { + if (calculatedTotal.compareTo(BigDecimal.ZERO) <= 0) { throw new BusinessException("商品金额不能为0"); } - // 检查租户ID - if (request.getTenantId() == null) { - request.setTenantId(loginUser.getTenantId()); + // 检查前端传入的总金额是否正确(允许小的误差,比如0.01) + if (request.getTotalPrice() != null && + request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) { + log.warn("订单金额计算不一致,前端传入:{},后台计算:{}", request.getTotalPrice(), calculatedTotal); + throw new BusinessException("订单金额计算错误,请刷新重试"); } - // 检查订单类型 - if (request.getType() == null) { - // 设置默认订单类型为商城订单 - request.setType(0); - } + // 使用后台计算的金额 + request.setTotalPrice(calculatedTotal); // 检查租户特殊规则 - if (orderConfig != null && request.getTotalPrice() != null) { - OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(request.getTenantId()); - if (tenantRule != null && tenantRule.getMinAmount() != null) { - if (request.getTotalPrice().compareTo(tenantRule.getMinAmount()) < 0) { - throw new BusinessException(tenantRule.getMinAmountMessage()); - } + OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(request.getTenantId()); + if (tenantRule != null && tenantRule.getMinAmount() != null) { + if (calculatedTotal.compareTo(tenantRule.getMinAmount()) < 0) { + throw new BusinessException(tenantRule.getMinAmountMessage()); } } } /** - * 验证商品信息并获取商品详情 + * 验证商品信息并计算总金额 */ - private ShopGoods validateAndGetGoods(OrderCreateRequest request) { - Integer goodsId = request.getActualFormId(); - if (goodsId == null) { - throw new BusinessException("商品ID不能为空"); + private BigDecimal validateAndCalculateTotal(OrderCreateRequest request) { + if (CollectionUtils.isEmpty(request.getGoodsItems())) { + throw new BusinessException("订单商品列表不能为空"); } - // 从数据库查询商品信息 - ShopGoods goods = shopGoodsService.getById(goodsId); - if (goods == null) { - throw new BusinessException("商品不存在,商品ID:" + goodsId); - } + BigDecimal total = BigDecimal.ZERO; - // 验证商品状态 - if (goods.getDeleted() != null && goods.getDeleted() == 1) { - throw new BusinessException("商品已删除"); - } - - if (goods.getStatus() != 0) { - throw new BusinessException("商品未上架"); - } - - // 验证库存 - Integer totalNum = request.getActualTotalNum(); - if (goods.getStock() != null && totalNum != null) { - if (goods.getStock() < totalNum) { - throw new BusinessException("商品库存不足,当前库存:" + goods.getStock()); + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 验证商品ID + if (item.getGoodsId() == null) { + throw new BusinessException("商品ID不能为空"); } - } - // 验证价格(允许一定的误差,比如0.01元) - if (goods.getPrice() != null && request.getTotalPrice() != null && totalNum != null) { - BigDecimal expectedTotal = goods.getPrice().multiply(new BigDecimal(totalNum)); - BigDecimal priceDiff = request.getTotalPrice().subtract(expectedTotal).abs(); - if (priceDiff.compareTo(new BigDecimal("0.01")) > 0) { - throw new BusinessException("商品价格异常,数据库价格:" + goods.getPrice() + - ",期望总价:" + expectedTotal + ",请求价格:" + request.getTotalPrice()); + // 验证购买数量 + if (item.getQuantity() == null || item.getQuantity() <= 0) { + throw new BusinessException("商品购买数量必须大于0"); } + + // 获取商品信息 + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods == null) { + throw new BusinessException("商品不存在,商品ID:" + item.getGoodsId()); + } + + // 验证商品状态 + if (goods.getStatus() == null || goods.getStatus() != 0) { + throw new BusinessException("商品已下架:" + goods.getName()); + } + + // 处理多规格商品价格和库存验证 + BigDecimal actualPrice = goods.getPrice(); // 默认使用商品价格 + Integer actualStock = goods.getStock(); // 默认使用商品库存 + String productName = goods.getName(); + + if (item.getSkuId() != null) { + // 多规格商品,获取SKU信息 + ShopGoodsSku sku = shopGoodsSkuService.getById(item.getSkuId()); + if (sku == null) { + throw new BusinessException("商品规格不存在,SKU ID:" + item.getSkuId()); + } + + // 验证SKU是否属于该商品 + if (!sku.getGoodsId().equals(item.getGoodsId())) { + throw new BusinessException("商品规格不匹配"); + } + + // 验证SKU状态 + if (sku.getStatus() == null || sku.getStatus() != 0) { + throw new BusinessException("商品规格已下架"); + } + + // 使用SKU的价格和库存 + actualPrice = sku.getPrice(); + actualStock = sku.getStock(); + productName = goods.getName() + "(" + (item.getSpecInfo() != null ? item.getSpecInfo() : sku.getSku()) + ")"; + } + + // 验证实际价格 + if (actualPrice == null || actualPrice.compareTo(BigDecimal.ZERO) <= 0) { + throw new BusinessException("商品价格异常:" + productName); + } + + // 验证库存 + if (actualStock != null && actualStock < item.getQuantity()) { + throw new BusinessException("商品库存不足:" + productName + ",当前库存:" + actualStock); + } + + // 验证购买数量限制(使用商品级别的限制) + if (goods.getCanBuyNumber() != null && goods.getCanBuyNumber() > 0 && + item.getQuantity() > goods.getCanBuyNumber()) { + throw new BusinessException("商品购买数量超过限制:" + productName + ",最大购买数量:" + goods.getCanBuyNumber()); + } + + // 计算商品小计(使用实际价格) + BigDecimal itemTotal = actualPrice.multiply(new BigDecimal(item.getQuantity())); + total = total.add(itemTotal); + + log.debug("商品验证通过 - ID:{},SKU ID:{},名称:{},单价:{},数量:{},小计:{}", + goods.getGoodsId(), item.getSkuId(), productName, actualPrice, item.getQuantity(), itemTotal); } - log.info("商品验证通过 - 商品ID:{},商品名称:{},价格:{},库存:{},购买数量:{}", - goods.getGoodsId(), goods.getName(), goods.getPrice(), goods.getStock(), totalNum); - - return goods; + log.info("订单商品验证完成,总金额:{}", total); + return total; } /** * 构建订单对象 */ - private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser, ShopGoods goods) { + private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser) { ShopOrder shopOrder = new ShopOrder(); // 复制请求参数到订单对象 BeanUtils.copyProperties(request, shopOrder); - // 设置兼容字段 - Integer actualFormId = request.getActualFormId(); - Integer actualTotalNum = request.getActualTotalNum(); + // 确保租户ID正确设置(关键字段,影响微信支付证书路径) + shopOrder.setTenantId(loginUser.getTenantId()); - if (actualFormId != null) { - shopOrder.setFormId(actualFormId); - } - if (actualTotalNum != null) { - shopOrder.setTotalNum(actualTotalNum); - } - - // 使用数据库中的商品信息覆盖价格(确保价格准确性) - if (goods.getPrice() != null && actualTotalNum != null) { - BigDecimal totalPrice = goods.getPrice().multiply(new BigDecimal(actualTotalNum)); - shopOrder.setTotalPrice(totalPrice); - shopOrder.setPrice(totalPrice); - // 如果没有设置实际付款金额,则使用总价 - if (shopOrder.getPayPrice() == null) { - shopOrder.setPayPrice(totalPrice); - } + // 验证关键字段 + if (shopOrder.getTenantId() == null) { + throw new BusinessException("租户ID不能为空,这会导致微信支付证书路径错误"); } // 设置用户相关信息 @@ -200,6 +228,8 @@ public class OrderBusinessService { shopOrder.setOpenid(loginUser.getOpenid()); shopOrder.setPayUserId(loginUser.getUserId()); + log.debug("构建订单对象 - 租户ID:{},用户ID:{}", shopOrder.getTenantId(), shopOrder.getUserId()); + // 生成订单号 if (shopOrder.getOrderNo() == null) { shopOrder.setOrderNo(Long.toString(IdUtil.getSnowflakeNextId())); @@ -207,18 +237,39 @@ public class OrderBusinessService { // 设置默认备注 if (shopOrder.getComments() == null) { - if (orderConfig != null && orderConfig.getDefaultConfig() != null) { - shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments()); - } else { - shopOrder.setComments("暂无"); - } + shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments()); } - // 设置默认支付状态 - shopOrder.setPayStatus(false); + // 设置价格相关字段(解决数据库字段没有默认值的问题) + if (shopOrder.getPayPrice() == null) { + shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额 + } - log.info("构建订单完成 - 订单号:{},商品ID:{},数量:{},总价:{}", - shopOrder.getOrderNo(), actualFormId, actualTotalNum, shopOrder.getTotalPrice()); + if (shopOrder.getPrice() == null) { + shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额 + } + + if (shopOrder.getReducePrice() == null) { + shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0 + } + + if (shopOrder.getMoney() == null) { + shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额 + } + + // 设置默认状态 + shopOrder.setPayStatus(false); // 未付款 + shopOrder.setOrderStatus(0); // 未使用 + shopOrder.setDeliveryStatus(10); // 未发货 + shopOrder.setIsInvoice(0); // 未开发票 + shopOrder.setIsSettled(0); // 未结算 + shopOrder.setCheckBill(0); // 未对账 + shopOrder.setVersion(0); // 当前版本 + + // 设置默认支付类型(如果没有指定) + if (shopOrder.getPayType() == null) { + shopOrder.setPayType(1); // 默认微信支付 + } return shopOrder; } @@ -228,13 +279,13 @@ public class OrderBusinessService { */ private void applyBusinessRules(ShopOrder shopOrder, User loginUser) { // 测试账号处理 - if (orderConfig != null && orderConfig.isTestAccount(loginUser.getPhone())) { - if (orderConfig.getTestAccount() != null) { - BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); - shopOrder.setPrice(testAmount); - shopOrder.setTotalPrice(testAmount); - log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount); - } + if (orderConfig.isTestAccount(loginUser.getPhone())) { + BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); + shopOrder.setPrice(testAmount); + shopOrder.setTotalPrice(testAmount); + shopOrder.setPayPrice(testAmount); // 确保实际付款也设置为测试金额 + shopOrder.setMoney(testAmount); // 确保积分计算金额也设置为测试金额 + log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount); } // 其他业务规则可以在这里添加 @@ -249,20 +300,168 @@ public class OrderBusinessService { throw new BusinessException("订单金额必须大于0"); } - if (orderConfig != null) { - OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(tenantId); - if (tenantRule != null && tenantRule.getMinAmount() != null) { - if (amount.compareTo(tenantRule.getMinAmount()) < 0) { - throw new BusinessException(tenantRule.getMinAmountMessage()); + OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(tenantId); + if (tenantRule != null && tenantRule.getMinAmount() != null) { + if (amount.compareTo(tenantRule.getMinAmount()) < 0) { + throw new BusinessException(tenantRule.getMinAmountMessage()); + } + } + } + + /** + * 保存订单商品 + */ + private void saveOrderGoods(OrderCreateRequest request, ShopOrder shopOrder) { + if (CollectionUtils.isEmpty(request.getGoodsItems())) { + log.warn("订单商品列表为空,订单号:{}", shopOrder.getOrderNo()); + return; + } + + List orderGoodsList = new ArrayList<>(); + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 重新获取商品信息(确保数据一致性) + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods == null) { + throw new BusinessException("商品不存在,商品ID:" + item.getGoodsId()); + } + + // 再次验证商品状态(防止并发问题) + if (goods.getStatus() == null || goods.getStatus() != 0) { + throw new BusinessException("商品已下架:" + goods.getName()); + } + + // 处理多规格商品 + ShopGoodsSku sku = null; + BigDecimal actualPrice = goods.getPrice(); // 默认使用商品价格 + Integer actualStock = goods.getStock(); // 默认使用商品库存 + String specInfo = item.getSpecInfo(); // 规格信息 + + if (item.getSkuId() != null) { + // 多规格商品,获取SKU信息 + sku = shopGoodsSkuService.getById(item.getSkuId()); + if (sku == null) { + throw new BusinessException("商品规格不存在,SKU ID:" + item.getSkuId()); + } + + // 验证SKU是否属于该商品 + if (!sku.getGoodsId().equals(item.getGoodsId())) { + throw new BusinessException("商品规格不匹配"); + } + + // 验证SKU状态 + if (sku.getStatus() == null || sku.getStatus() != 0) { + throw new BusinessException("商品规格已下架"); + } + + // 使用SKU的价格和库存 + actualPrice = sku.getPrice(); + actualStock = sku.getStock(); + + // 如果前端没有传规格信息,使用SKU的规格信息 + if (specInfo == null || specInfo.trim().isEmpty()) { + specInfo = sku.getSku(); // 使用SKU的规格描述 + } + } + + // 验证库存 + if (actualStock == null || actualStock < item.getQuantity()) { + String stockMsg = sku != null ? "商品规格库存不足" : "商品库存不足"; + throw new BusinessException(stockMsg + ",当前库存:" + (actualStock != null ? actualStock : 0)); + } + + ShopOrderGoods orderGoods = new ShopOrderGoods(); + + // 设置订单关联信息 + orderGoods.setOrderId(shopOrder.getOrderId()); + orderGoods.setOrderCode(shopOrder.getOrderNo()); + + // 设置商户信息 + orderGoods.setMerchantId(shopOrder.getMerchantId()); + orderGoods.setMerchantName(shopOrder.getMerchantName()); + + // 设置商品信息(使用后台查询的真实数据) + orderGoods.setGoodsId(item.getGoodsId()); + orderGoods.setSkuId(item.getSkuId()); // 设置SKU ID + orderGoods.setGoodsName(goods.getName()); + orderGoods.setImage(sku != null && sku.getImage() != null ? sku.getImage() : goods.getImage()); // 优先使用SKU图片 + orderGoods.setPrice(actualPrice); // 使用实际价格(SKU价格或商品价格) + orderGoods.setTotalNum(item.getQuantity()); + + // 计算商品小计(用于日志记录) + BigDecimal itemTotal = actualPrice.multiply(new BigDecimal(item.getQuantity())); + + // 设置商品规格信息 + orderGoods.setSpec(specInfo); + + // 设置支付相关信息 + orderGoods.setPayStatus(0); // 0 未付款 + orderGoods.setOrderStatus(0); // 0 未使用 + orderGoods.setIsFree(false); // 默认收费 + orderGoods.setVersion(0); // 当前版本 + + // 设置其他信息 + orderGoods.setComments(request.getComments()); + orderGoods.setUserId(shopOrder.getUserId()); + orderGoods.setTenantId(shopOrder.getTenantId()); + + orderGoodsList.add(orderGoods); + + log.debug("准备保存订单商品 - 商品ID:{},名称:{},单价:{},数量:{},小计:{}", + goods.getGoodsId(), goods.getName(), goods.getPrice(), item.getQuantity(), itemTotal); + } + + // 批量保存订单商品 + boolean saved = shopOrderGoodsService.saveBatch(orderGoodsList); + if (!saved) { + throw new BusinessException("保存订单商品失败"); + } + + // 扣减库存 + deductStock(request); + + log.info("成功保存订单商品,订单号:{},商品数量:{}", shopOrder.getOrderNo(), orderGoodsList.size()); + } + + /** + * 扣减库存 + */ + private void deductStock(OrderCreateRequest request) { + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + if (item.getSkuId() != null) { + // 多规格商品,扣减SKU库存 + ShopGoodsSku sku = shopGoodsSkuService.getById(item.getSkuId()); + if (sku != null && sku.getStock() != null) { + int newStock = sku.getStock() - item.getQuantity(); + if (newStock < 0) { + throw new BusinessException("SKU库存不足,无法完成扣减"); + } + sku.setStock(newStock); + shopGoodsSkuService.updateById(sku); + log.debug("扣减SKU库存 - SKU ID:{},扣减数量:{},剩余库存:{}", + item.getSkuId(), item.getQuantity(), newStock); + } + } else { + // 单规格商品,扣减商品库存 + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods != null && goods.getStock() != null) { + int newStock = goods.getStock() - item.getQuantity(); + if (newStock < 0) { + throw new BusinessException("商品库存不足,无法完成扣减"); + } + goods.setStock(newStock); + shopGoodsService.updateById(goods); + log.debug("扣减商品库存 - 商品ID:{},扣减数量:{},剩余库存:{}", + item.getGoodsId(), item.getQuantity(), newStock); } } } + log.info("库存扣减完成"); } /** * 检查是否为测试账号 */ public boolean isTestAccount(String phone) { - return orderConfig != null && orderConfig.isTestAccount(phone); + return orderConfig.isTestAccount(phone); } } diff --git a/src/main/java/com/gxwebsoft/shop/service/ShopCouponService.java b/src/main/java/com/gxwebsoft/shop/service/ShopCouponService.java new file mode 100644 index 0000000..5f6c618 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/ShopCouponService.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; + +import java.util.List; + +/** + * 优惠券Service + * + * @author 科技小王子 + * @since 2025-08-08 21:10:55 + */ +public interface ShopCouponService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCouponParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCouponParam param); + + /** + * 根据id查询 + * + * @param id id + * @return ShopCoupon + */ + ShopCoupon getByIdRel(Integer id); + + /** + * 获取可领取的优惠券列表 + * + * @param userId 用户ID + * @return List + */ + List getReceivableCoupons(Integer userId); + + /** + * 检查优惠券是否可以发放 + * + * @param couponId 优惠券ID + * @return boolean + */ + boolean canIssue(Integer couponId); + + /** + * 更新优惠券发放数量 + * + * @param couponId 优惠券ID + * @param increment 增量 + * @return boolean + */ + boolean updateIssuedCount(Integer couponId, int increment); + +} diff --git a/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java b/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java index fdfa4af..08e02ed 100644 --- a/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java +++ b/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java @@ -5,6 +5,7 @@ import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.param.ShopOrderParam; +import java.math.BigDecimal; import java.util.HashMap; import java.util.List; @@ -47,4 +48,11 @@ public interface ShopOrderService extends IService { Boolean queryOrderByOutTradeNo(ShopOrder shopOrder); void updateByOutTradeNo(ShopOrder order); + + /** + * 统计订单总金额 + * + * @return 订单总金额 + */ + BigDecimal total(); } diff --git a/src/main/java/com/gxwebsoft/shop/service/ShopUserCouponService.java b/src/main/java/com/gxwebsoft/shop/service/ShopUserCouponService.java new file mode 100644 index 0000000..ae41775 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/ShopUserCouponService.java @@ -0,0 +1,153 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 用户优惠券Service + * + * @author 科技小王子 + * @since 2025-08-08 21:30:00 + */ +public interface ShopUserCouponService extends IService { + + /** + * 分页关联查询用户优惠券 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserCouponParam param); + + /** + * 关联查询用户优惠券列表 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserCouponParam param); + + /** + * 根据id查询用户优惠券 + * + * @param id id + * @return ShopUserCoupon + */ + ShopUserCoupon getByIdRel(Long id); + + /** + * 用户领取优惠券 + * + * @param userId 用户ID + * @param couponId 优惠券模板ID + * @return 是否成功 + */ + boolean receiveCoupon(Integer userId, Integer couponId); + + /** + * 系统发放优惠券给用户 + * + * @param userId 用户ID + * @param couponId 优惠券模板ID + * @param source 发放来源描述 + * @return 是否成功 + */ + boolean issueCouponToUser(Integer userId, Integer couponId, String source); + + /** + * 批量发放优惠券给多个用户 + * + * @param userIds 用户ID列表 + * @param couponId 优惠券模板ID + * @param source 发放来源描述 + * @return 成功发放的数量 + */ + int batchIssueCoupons(List userIds, Integer couponId, String source); + + /** + * 使用优惠券 + * + * @param userCouponId 用户优惠券ID + * @param orderId 订单ID + * @param orderNo 订单号 + * @return 是否成功 + */ + boolean useCoupon(Long userCouponId, Long orderId, String orderNo); + + /** + * 退还优惠券(订单取消时) + * + * @param orderId 订单ID + * @return 是否成功 + */ + boolean returnCoupon(Long orderId); + + /** + * 获取用户可用的优惠券列表 + * + * @param userId 用户ID + * @param goodsId 商品ID(可选) + * @param categoryId 商品分类ID(可选) + * @param orderAmount 订单金额(可选) + * @return List + */ + List getAvailableCoupons(Integer userId, Integer goodsId, + Integer categoryId, BigDecimal orderAmount); + + /** + * 计算优惠券优惠金额 + * + * @param userCoupon 用户优惠券 + * @param orderAmount 订单金额 + * @return 优惠金额 + */ + BigDecimal calculateDiscountAmount(ShopUserCoupon userCoupon, BigDecimal orderAmount); + + /** + * 验证优惠券是否可用于指定商品 + * + * @param userCoupon 用户优惠券 + * @param goodsId 商品ID + * @param categoryId 商品分类ID + * @return 是否可用 + */ + boolean validateCouponForGoods(ShopUserCoupon userCoupon, Integer goodsId, Integer categoryId); + + /** + * 统计用户优惠券数量 + * + * @param userId 用户ID + * @return 统计结果 {total: 总数, unused: 未使用, used: 已使用, expired: 已过期} + */ + Map countUserCoupons(Integer userId); + + /** + * 更新过期优惠券状态 + * + * @return 更新数量 + */ + int updateExpiredCoupons(); + + /** + * 获取即将过期的优惠券 + * + * @param days 天数 + * @return List + */ + List getExpiringSoonCoupons(Integer days); + + /** + * 检查用户是否可以领取指定优惠券 + * + * @param userId 用户ID + * @param couponId 优惠券模板ID + * @return 检查结果 {canReceive: boolean, reason: String} + */ + Map checkCanReceiveCoupon(Integer userId, Integer couponId); +} diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/CouponBusinessServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/CouponBusinessServiceImpl.java new file mode 100644 index 0000000..e6529f3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/impl/CouponBusinessServiceImpl.java @@ -0,0 +1,433 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.service.CouponBusinessService; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 优惠券业务服务实现 + * + * @author 科技小王子 + * @since 2025-08-08 22:00:00 + */ +@Slf4j +@Service +public class CouponBusinessServiceImpl implements CouponBusinessService { + + @Resource + private ShopUserCouponService shopUserCouponService; + + @Resource + private ShopCouponService shopCouponService; + + @Resource + private UserService userService; + + @Override + public List getAvailableCouponsForOrder(Integer userId, + List> goodsItems, + BigDecimal totalAmount) { + if (userId == null || goodsItems == null || goodsItems.isEmpty()) { + return new ArrayList<>(); + } + + // 获取用户所有可用优惠券 + List allCoupons = shopUserCouponService.getAvailableCoupons( + userId, null, null, totalAmount); + + // 过滤出适用于当前订单的优惠券 + return allCoupons.stream() + .filter(coupon -> isValidForOrder(coupon, goodsItems, totalAmount)) + .collect(Collectors.toList()); + } + + @Override + public Map calculateOrderAmountWithCoupon(Long userCouponId, + List> goodsItems, + BigDecimal totalAmount) { + Map result = new HashMap<>(); + result.put("valid", false); + result.put("discountAmount", BigDecimal.ZERO); + result.put("finalAmount", totalAmount); + + if (userCouponId == null || totalAmount == null) { + result.put("reason", "参数不能为空"); + return result; + } + + ShopUserCoupon userCoupon = shopUserCouponService.getById(userCouponId); + if (userCoupon == null) { + result.put("reason", "优惠券不存在"); + return result; + } + + if (!userCoupon.isAvailable()) { + result.put("reason", "优惠券不可用"); + return result; + } + + if (!isValidForOrder(userCoupon, goodsItems, totalAmount)) { + result.put("reason", "优惠券不适用于当前订单"); + return result; + } + + BigDecimal discountAmount = shopUserCouponService.calculateDiscountAmount(userCoupon, totalAmount); + BigDecimal finalAmount = totalAmount.subtract(discountAmount); + + // 确保最终金额不为负数 + if (finalAmount.compareTo(BigDecimal.ZERO) < 0) { + finalAmount = BigDecimal.ZERO; + } + + result.put("valid", true); + result.put("discountAmount", discountAmount); + result.put("finalAmount", finalAmount); + result.put("coupon", userCoupon); + + return result; + } + + @Override + public Map validateCouponForOrder(Long userCouponId, + Integer userId, + List> goodsItems, + BigDecimal totalAmount) { + Map result = new HashMap<>(); + + if (userCouponId == null || userId == null) { + result.put("valid", false); + result.put("reason", "参数不能为空"); + return result; + } + + ShopUserCoupon userCoupon = shopUserCouponService.getById(userCouponId); + if (userCoupon == null) { + result.put("valid", false); + result.put("reason", "优惠券不存在"); + return result; + } + + if (!userCoupon.getUserId().equals(userId)) { + result.put("valid", false); + result.put("reason", "优惠券不属于当前用户"); + return result; + } + + if (!userCoupon.isAvailable()) { + result.put("valid", false); + result.put("reason", "优惠券不可用或已过期"); + return result; + } + + if (!isValidForOrder(userCoupon, goodsItems, totalAmount)) { + result.put("valid", false); + result.put("reason", "优惠券不适用于当前订单商品"); + return result; + } + + result.put("valid", true); + result.put("reason", "优惠券可用"); + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int issueWelcomeCoupons(Integer userId) { + if (userId == null) { + return 0; + } + + // 查找欢迎优惠券模板(这里假设有特定的标识) + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ShopCoupon::getEnabled, 1) + .eq(ShopCoupon::getStatus, 0) + .like(ShopCoupon::getName, "新用户") + .or() + .like(ShopCoupon::getName, "欢迎"); + + List welcomeCoupons = shopCouponService.list(queryWrapper); + + int successCount = 0; + for (ShopCoupon coupon : welcomeCoupons) { + if (shopUserCouponService.issueCouponToUser(userId, coupon.getId(), "新用户注册赠送")) { + successCount++; + } + } + + log.info("为新用户{}发放欢迎优惠券{}张", userId, successCount); + return successCount; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int issueBirthdayCoupons(Integer userId) { + if (userId == null) { + return 0; + } + + User user = userService.getById(userId); + if (user == null || user.getBirthday() == null) { + return 0; + } + + // 检查今天是否是用户生日 + LocalDate today = LocalDate.now(); + LocalDate birthday = LocalDate.parse((CharSequence) user.getBirthday(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + if (today.getMonthValue() != birthday.getMonthValue() || + today.getDayOfMonth() != birthday.getDayOfMonth()) { + return 0; + } + + // 查找生日优惠券模板 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ShopCoupon::getEnabled, 1) + .eq(ShopCoupon::getStatus, 0) + .like(ShopCoupon::getName, "生日"); + + List birthdayCoupons = shopCouponService.list(queryWrapper); + + int successCount = 0; + for (ShopCoupon coupon : birthdayCoupons) { + if (shopUserCouponService.issueCouponToUser(userId, coupon.getId(), "生日祝福赠送")) { + successCount++; + } + } + + log.info("为用户{}发放生日优惠券{}张", userId, successCount); + return successCount; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int issueConsumeCoupons(Integer userId, BigDecimal consumeAmount) { + if (userId == null || consumeAmount == null || consumeAmount.compareTo(BigDecimal.ZERO) <= 0) { + return 0; + } + + // 根据消费金额发放不同的优惠券 + List eligibleCoupons = new ArrayList<>(); + + if (consumeAmount.compareTo(new BigDecimal("100")) >= 0) { + // 消费满100发放优惠券 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ShopCoupon::getEnabled, 1) + .eq(ShopCoupon::getStatus, 0) + .like(ShopCoupon::getName, "消费返券"); + eligibleCoupons.addAll(shopCouponService.list(queryWrapper)); + } + + int successCount = 0; + for (ShopCoupon coupon : eligibleCoupons) { + if (shopUserCouponService.issueCouponToUser(userId, coupon.getId(), + "消费满" + consumeAmount + "元返券")) { + successCount++; + } + } + + log.info("为用户{}消费{}元发放优惠券{}张", userId, consumeAmount, successCount); + return successCount; + } + + /** + * 检查优惠券是否适用于订单 + */ + private boolean isValidForOrder(ShopUserCoupon userCoupon, + List> goodsItems, + BigDecimal totalAmount) { + if (userCoupon == null || goodsItems == null || goodsItems.isEmpty()) { + return false; + } + + // 检查最低消费金额 + if (userCoupon.getMinPrice() != null && + totalAmount.compareTo(userCoupon.getMinPrice()) < 0) { + return false; + } + + // 检查适用范围 + if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_ALL) { + return true; + } else if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_GOODS) { + // 检查是否有指定商品 + return goodsItems.stream().anyMatch(item -> { + Integer goodsId = (Integer) item.get("goodsId"); + return shopUserCouponService.validateCouponForGoods(userCoupon, goodsId, null); + }); + } else if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_CATEGORY) { + // 检查是否有指定分类的商品 + return goodsItems.stream().anyMatch(item -> { + Integer categoryId = (Integer) item.get("categoryId"); + return shopUserCouponService.validateCouponForGoods(userCoupon, null, categoryId); + }); + } + + return false; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Map batchIssueActivityCoupons(String activityName, + List couponIds, + List userIds) { + Map result = new HashMap<>(); + result.put("totalUsers", 0); + result.put("totalCoupons", 0); + result.put("successCount", 0); + + if (couponIds == null || couponIds.isEmpty()) { + result.put("message", "优惠券列表不能为空"); + return result; + } + + // 如果没有指定用户,则获取所有活跃用户 + if (userIds == null || userIds.isEmpty()) { + userIds = userService.list().stream() + .filter(user -> user.getStatus() == 0) // 只给正常状态的用户发放 + .map(User::getUserId) + .collect(Collectors.toList()); + } + + int totalUsers = userIds.size(); + int totalCoupons = couponIds.size() * totalUsers; + int successCount = 0; + + String source = activityName != null ? activityName + "活动赠送" : "活动赠送"; + + for (Integer userId : userIds) { + for (Integer couponId : couponIds) { + if (shopUserCouponService.issueCouponToUser(userId, couponId, source)) { + successCount++; + } + } + } + + result.put("totalUsers", totalUsers); + result.put("totalCoupons", totalCoupons); + result.put("successCount", successCount); + result.put("message", String.format("活动优惠券发放完成,共%d个用户,%d张优惠券,成功%d张", + totalUsers, totalCoupons, successCount)); + + log.info("活动{}批量发放优惠券完成:用户{}个,优惠券{}张,成功{}张", + activityName, totalUsers, totalCoupons, successCount); + + return result; + } + + @Override + public Map getCouponUsageStatistics(String startDate, String endDate) { + Map result = new HashMap<>(); + + // 这里可以根据需要实现具体的统计逻辑 + // 统计指定时间段内的优惠券使用情况 + + result.put("totalIssued", 0); // 总发放数量 + result.put("totalUsed", 0); // 总使用数量 + result.put("totalExpired", 0); // 总过期数量 + result.put("usageRate", 0.0); // 使用率 + result.put("discountAmount", BigDecimal.ZERO); // 总优惠金额 + + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int autoProcessExpiredCoupons() { + // 更新过期优惠券状态 + int count = shopUserCouponService.updateExpiredCoupons(); + log.info("自动处理过期优惠券{}张", count); + return count; + } + + @Override + public int sendCouponExpiryReminder(Integer days) { + if (days == null || days <= 0) { + days = 3; // 默认提前3天提醒 + } + + List expiringSoonCoupons = shopUserCouponService.getExpiringSoonCoupons(days); + + // 按用户分组 + Map> userCouponsMap = expiringSoonCoupons.stream() + .collect(Collectors.groupingBy(ShopUserCoupon::getUserId)); + + int reminderCount = 0; + for (Map.Entry> entry : userCouponsMap.entrySet()) { + Integer userId = entry.getKey(); + List coupons = entry.getValue(); + + // 这里可以发送消息提醒用户 + // 例如:发送站内信、短信、推送通知等 + log.info("提醒用户{}有{}张优惠券即将过期", userId, coupons.size()); + reminderCount++; + } + + log.info("发送优惠券到期提醒给{}个用户", reminderCount); + return reminderCount; + } + + @Override + public Map recommendBestCouponCombination(Integer userId, + List> goodsItems, + BigDecimal totalAmount) { + Map result = new HashMap<>(); + result.put("coupons", new ArrayList<>()); + result.put("totalDiscount", BigDecimal.ZERO); + result.put("finalAmount", totalAmount); + + if (userId == null || goodsItems == null || goodsItems.isEmpty() || totalAmount == null) { + return result; + } + + // 获取用户所有可用优惠券 + List availableCoupons = getAvailableCouponsForOrder(userId, goodsItems, totalAmount); + + if (availableCoupons.isEmpty()) { + return result; + } + + // 简单的贪心算法:选择优惠金额最大的优惠券 + // 实际项目中可以实现更复杂的组合优化算法 + ShopUserCoupon bestCoupon = null; + BigDecimal maxDiscount = BigDecimal.ZERO; + + for (ShopUserCoupon coupon : availableCoupons) { + BigDecimal discount = shopUserCouponService.calculateDiscountAmount(coupon, totalAmount); + if (discount.compareTo(maxDiscount) > 0) { + maxDiscount = discount; + bestCoupon = coupon; + } + } + + if (bestCoupon != null) { + List recommendedCoupons = new ArrayList<>(); + recommendedCoupons.add(bestCoupon); + + BigDecimal finalAmount = totalAmount.subtract(maxDiscount); + if (finalAmount.compareTo(BigDecimal.ZERO) < 0) { + finalAmount = BigDecimal.ZERO; + } + + result.put("coupons", recommendedCoupons); + result.put("totalDiscount", maxDiscount); + result.put("finalAmount", finalAmount); + } + + return result; + } +} diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponServiceImpl.java new file mode 100644 index 0000000..8824081 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponServiceImpl.java @@ -0,0 +1,126 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.mapper.ShopCouponMapper; +import com.gxwebsoft.shop.param.ShopCouponParam; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.util.List; + +/** + * 优惠券Service实现 + * + * @author 科技小王子 + * @since 2025-08-08 21:10:55 + */ +@Slf4j +@Service +public class ShopCouponServiceImpl extends ServiceImpl implements ShopCouponService { + + @Resource + private ShopUserCouponService shopUserCouponService; + + @Override + public PageResult pageRel(ShopCouponParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCouponParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCoupon getByIdRel(Integer id) { + ShopCouponParam param = new ShopCouponParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public List getReceivableCoupons(Integer userId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ShopCoupon::getEnabled, 1) + .eq(ShopCoupon::getStatus, 0) + .and(wrapper -> wrapper + .isNull(ShopCoupon::getTotalCount) + .or() + .apply("IFNULL(total_count, 0) = -1") + .or() + .apply("IFNULL(issued_count, 0) < IFNULL(total_count, 0)")) + .orderByAsc(ShopCoupon::getSortNumber) + .orderByDesc(ShopCoupon::getCreateTime); + + List allCoupons = list(queryWrapper); + + // 过滤掉用户已达到领取上限的优惠券 + return allCoupons.stream() + .filter(coupon -> { + if (coupon.getLimitPerUser() == null || coupon.getLimitPerUser() <= 0) { + return true; // 无限制 + } + // 检查用户已领取数量 + int receivedCount = baseMapper.countUserReceivedCoupon(userId, coupon.getId()); + return receivedCount < coupon.getLimitPerUser(); + }) + .collect(java.util.stream.Collectors.toList()); + } + + @Override + public boolean canIssue(Integer couponId) { + ShopCoupon coupon = getById(couponId); + if (coupon == null || coupon.getEnabled() != 1 || coupon.getStatus() != 0) { + return false; + } + + // 检查发放数量限制 + if (coupon.getTotalCount() != null && coupon.getTotalCount() > 0) { + int issuedCount = coupon.getIssuedCount() != null ? coupon.getIssuedCount() : 0; + return issuedCount < coupon.getTotalCount(); + } + + // 检查有效期 + LocalDate now = LocalDate.now(); + if (coupon.getExpireType() == 20) { // 固定时间 + if (coupon.getStartTime() != null && now.isBefore(coupon.getStartTime())) { + return false; // 还未开始 + } + if (coupon.getEndTime() != null && now.isAfter(coupon.getEndTime())) { + return false; // 已过期 + } + } + + return true; + } + + @Override + public boolean updateIssuedCount(Integer couponId, int increment) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(ShopCoupon::getId, couponId) + .setSql("issued_count = IFNULL(issued_count, 0) + " + increment); + + boolean updated = update(updateWrapper); + if (updated) { + log.debug("更新优惠券{}发放数量,增量: {}", couponId, increment); + } + return updated; + } + +} diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java index 60341d1..2921a5c 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + import org.springframework.util.CollectionUtils; import com.gxwebsoft.common.core.config.ConfigProperties; import com.gxwebsoft.common.core.config.CertificateProperties; import com.gxwebsoft.common.core.utils.RedisUtil; @@ -647,4 +648,23 @@ import com.gxwebsoft.common.core.service.PaymentCacheService; } } + @Override + public BigDecimal total() { + try { + // 使用数据库聚合查询统计订单总金额,性能更高 + BigDecimal total = baseMapper.selectTotalAmount(); + + if (total == null) { + total = BigDecimal.ZERO; + } + + log.info("统计订单总金额完成,总金额:{}", total); + return total; + + } catch (Exception e) { + log.error("统计订单总金额失败", e); + return BigDecimal.ZERO; + } + } + } diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCouponServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCouponServiceImpl.java new file mode 100644 index 0000000..609873c --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCouponServiceImpl.java @@ -0,0 +1,403 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.mapper.ShopUserCouponMapper; +import com.gxwebsoft.shop.param.ShopUserCouponParam; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.*; + +/** + * 用户优惠券Service实现 + * + * @author 科技小王子 + * @since 2025-08-08 21:30:00 + */ +@Slf4j +@Service +public class ShopUserCouponServiceImpl extends ServiceImpl + implements ShopUserCouponService { + + @Resource + private ShopCouponService shopCouponService; + + @Override + public PageResult pageRel(ShopUserCouponParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserCouponParam param) { + return baseMapper.selectListRel(param); + } + + @Override + public ShopUserCoupon getByIdRel(Long id) { + ShopUserCouponParam param = new ShopUserCouponParam(); + param.setId(id); + List list = baseMapper.selectListRel(param); + return list.isEmpty() ? null : list.get(0); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean receiveCoupon(Integer userId, Integer couponId) { + // 检查是否可以领取 + Map checkResult = checkCanReceiveCoupon(userId, couponId); + if (!(Boolean) checkResult.get("canReceive")) { + log.warn("用户{}无法领取优惠券{}: {}", userId, couponId, checkResult.get("reason")); + return false; + } + + // 获取优惠券模板 + ShopCoupon coupon = shopCouponService.getById(couponId); + if (coupon == null) { + log.warn("优惠券模板不存在: {}", couponId); + return false; + } + + // 创建用户优惠券 + ShopUserCoupon userCoupon = createUserCouponFromTemplate(coupon, userId); + userCoupon.setObtainType(ShopUserCoupon.OBTAIN_RECEIVE); + userCoupon.setObtainSource("用户主动领取"); + + // 保存用户优惠券 + boolean saved = save(userCoupon); + if (saved) { + // 更新优惠券模板的已发放数量 + updateCouponIssuedCount(couponId, 1); + log.info("用户{}成功领取优惠券{}", userId, couponId); + } + + return saved; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean issueCouponToUser(Integer userId, Integer couponId, String source) { + // 获取优惠券模板 + ShopCoupon coupon = shopCouponService.getById(couponId); + if (coupon == null || coupon.getEnabled() != 1) { + log.warn("优惠券模板不存在或已禁用: {}", couponId); + return false; + } + + // 检查发放数量限制 + if (coupon.getTotalCount() != null && coupon.getTotalCount() > 0) { + int issuedCount = coupon.getIssuedCount() != null ? coupon.getIssuedCount() : 0; + if (issuedCount >= coupon.getTotalCount()) { + log.warn("优惠券{}发放数量已达上限", couponId); + return false; + } + } + + // 创建用户优惠券 + ShopUserCoupon userCoupon = createUserCouponFromTemplate(coupon, userId); + userCoupon.setObtainType(ShopUserCoupon.OBTAIN_SYSTEM); + userCoupon.setObtainSource(source != null ? source : "系统发放"); + + // 保存用户优惠券 + boolean saved = save(userCoupon); + if (saved) { + // 更新优惠券模板的已发放数量 + updateCouponIssuedCount(couponId, 1); + log.info("系统向用户{}发放优惠券{}", userId, couponId); + } + + return saved; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchIssueCoupons(List userIds, Integer couponId, String source) { + if (userIds == null || userIds.isEmpty()) { + return 0; + } + + // 获取优惠券模板 + ShopCoupon coupon = shopCouponService.getById(couponId); + if (coupon == null || coupon.getEnabled() != 1) { + log.warn("优惠券模板不存在或已禁用: {}", couponId); + return 0; + } + + int successCount = 0; + for (Integer userId : userIds) { + if (issueCouponToUser(userId, couponId, source)) { + successCount++; + } + } + + log.info("批量发放优惠券{}给{}个用户,成功{}个", couponId, userIds.size(), successCount); + return successCount; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useCoupon(Long userCouponId, Long orderId, String orderNo) { + // 获取用户优惠券 + ShopUserCoupon userCoupon = getById(userCouponId); + if (userCoupon == null) { + log.warn("用户优惠券不存在: {}", userCouponId); + return false; + } + + // 检查优惠券状态 + if (!userCoupon.isAvailable()) { + log.warn("优惠券不可用: {}", userCouponId); + return false; + } + + // 更新优惠券状态 + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(ShopUserCoupon::getId, userCouponId) + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_UNUSED) + .set(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_USED) + .set(ShopUserCoupon::getUseTime, LocalDateTime.now()) + .set(ShopUserCoupon::getOrderId, orderId) + .set(ShopUserCoupon::getOrderNo, orderNo); + + boolean updated = update(updateWrapper); + if (updated) { + log.info("用户优惠券{}已使用,订单: {}", userCouponId, orderNo); + } + + return updated; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean returnCoupon(Long orderId) { + // 查找使用该订单的优惠券 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ShopUserCoupon::getOrderId, orderId) + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_USED); + + List usedCoupons = list(queryWrapper); + if (usedCoupons.isEmpty()) { + return true; // 没有使用优惠券,直接返回成功 + } + + // 退还优惠券 + for (ShopUserCoupon userCoupon : usedCoupons) { + // 检查是否已过期 + if (userCoupon.isExpired()) { + // 已过期的券设为过期状态 + userCoupon.setStatus(ShopUserCoupon.STATUS_EXPIRED); + } else { + // 未过期的券恢复为未使用状态 + userCoupon.setStatus(ShopUserCoupon.STATUS_UNUSED); + } + + userCoupon.setUseTime(null); + userCoupon.setOrderId(null); + userCoupon.setOrderNo(null); + updateById(userCoupon); + + log.info("退还用户优惠券{},订单: {}", userCoupon.getId(), orderId); + } + + return true; + } + + /** + * 从优惠券模板创建用户优惠券 + */ + private ShopUserCoupon createUserCouponFromTemplate(ShopCoupon coupon, Integer userId) { + ShopUserCoupon userCoupon = new ShopUserCoupon(); + userCoupon.setCouponId(coupon.getId()); + userCoupon.setUserId(userId); + userCoupon.setName(coupon.getName()); + userCoupon.setDescription(coupon.getDescription()); + userCoupon.setType(coupon.getType()); + userCoupon.setReducePrice(coupon.getReducePrice()); + userCoupon.setDiscount(coupon.getDiscount()); + userCoupon.setMinPrice(coupon.getMinPrice()); + userCoupon.setApplyRange(coupon.getApplyRange()); + userCoupon.setApplyRangeConfig(coupon.getApplyRangeConfig()); + userCoupon.setStatus(ShopUserCoupon.STATUS_UNUSED); + userCoupon.setTenantId(coupon.getTenantId()); + + // 设置有效期 + LocalDateTime now = LocalDateTime.now(); + if (coupon.getExpireType() == 10) { + // 领取后生效 + userCoupon.setStartTime(now); + if (coupon.getExpireDay() != null && coupon.getExpireDay() > 0) { + userCoupon.setEndTime(now.plusDays(coupon.getExpireDay())); + } + } else if (coupon.getExpireType() == 20) { + // 固定时间 + userCoupon.setStartTime(coupon.getStartTime() != null ? + coupon.getStartTime().atStartOfDay() : now); + userCoupon.setEndTime(coupon.getEndTime() != null ? + coupon.getEndTime().atTime(23, 59, 59) : null); + } + + return userCoupon; + } + + @Override + public List getAvailableCoupons(Integer userId, Integer goodsId, + Integer categoryId, BigDecimal orderAmount) { + ShopUserCouponParam param = new ShopUserCouponParam(); + param.setUserId(userId); + param.setStatus(ShopUserCoupon.STATUS_UNUSED); + param.setOnlyAvailable(true); + param.setGoodsId(goodsId); + param.setCategoryId(categoryId); + param.setOrderAmount(orderAmount); + + return baseMapper.selectAvailableCoupons(param); + } + + @Override + public BigDecimal calculateDiscountAmount(ShopUserCoupon userCoupon, BigDecimal orderAmount) { + if (userCoupon == null || orderAmount == null || orderAmount.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO; + } + + // 检查最低消费金额 + if (userCoupon.getMinPrice() != null && + orderAmount.compareTo(userCoupon.getMinPrice()) < 0) { + return BigDecimal.ZERO; + } + + BigDecimal discountAmount = BigDecimal.ZERO; + + if (userCoupon.getType() == ShopUserCoupon.TYPE_REDUCE) { + // 满减券 + discountAmount = userCoupon.getReducePrice() != null ? + userCoupon.getReducePrice() : BigDecimal.ZERO; + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_DISCOUNT) { + // 折扣券 + if (userCoupon.getDiscount() != null && userCoupon.getDiscount() > 0 && userCoupon.getDiscount() < 100) { + BigDecimal discountRate = BigDecimal.valueOf(100 - userCoupon.getDiscount()) + .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP); + discountAmount = orderAmount.multiply(discountRate); + } + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_FREE) { + // 免费券 + discountAmount = orderAmount; + } + + // 优惠金额不能超过订单金额 + return discountAmount.compareTo(orderAmount) > 0 ? orderAmount : discountAmount; + } + + @Override + public boolean validateCouponForGoods(ShopUserCoupon userCoupon, Integer goodsId, Integer categoryId) { + if (userCoupon == null || userCoupon.getApplyRange() == null) { + return false; + } + + if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_ALL) { + // 全部商品可用 + return true; + } else if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_GOODS) { + // 指定商品可用 + if (goodsId == null || userCoupon.getApplyRangeConfig() == null) { + return false; + } + // 解析商品ID列表(假设是逗号分隔的字符串) + String[] goodsIds = userCoupon.getApplyRangeConfig().split(","); + return Arrays.asList(goodsIds).contains(goodsId.toString()); + } else if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_CATEGORY) { + // 指定分类可用 + if (categoryId == null || userCoupon.getApplyRangeConfig() == null) { + return false; + } + // 解析分类ID列表(假设是逗号分隔的字符串) + String[] categoryIds = userCoupon.getApplyRangeConfig().split(","); + return Arrays.asList(categoryIds).contains(categoryId.toString()); + } + + return false; + } + + @Override + public Map countUserCoupons(Integer userId) { + return baseMapper.countUserCoupons(userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int updateExpiredCoupons() { + return baseMapper.updateExpiredStatus(); + } + + @Override + public List getExpiringSoonCoupons(Integer days) { + return baseMapper.selectExpiringSoon(days != null ? days : 3); + } + + @Override + public Map checkCanReceiveCoupon(Integer userId, Integer couponId) { + Map result = new HashMap<>(); + + // 获取优惠券模板 + ShopCoupon coupon = shopCouponService.getById(couponId); + if (coupon == null) { + result.put("canReceive", false); + result.put("reason", "优惠券不存在"); + return result; + } + + if (coupon.getEnabled() != 1) { + result.put("canReceive", false); + result.put("reason", "优惠券已禁用"); + return result; + } + + // 检查发放数量限制 + if (coupon.getTotalCount() != null && coupon.getTotalCount() > 0) { + int issuedCount = coupon.getIssuedCount() != null ? coupon.getIssuedCount() : 0; + if (issuedCount >= coupon.getTotalCount()) { + result.put("canReceive", false); + result.put("reason", "优惠券已领完"); + return result; + } + } + + // 检查每人限领数量 + if (coupon.getLimitPerUser() != null && coupon.getLimitPerUser() > 0) { + int receivedCount = baseMapper.countUserReceivedCoupon(userId, couponId); + if (receivedCount >= coupon.getLimitPerUser()) { + result.put("canReceive", false); + result.put("reason", "已达到个人领取上限"); + return result; + } + } + + result.put("canReceive", true); + result.put("reason", "可以领取"); + return result; + } + + /** + * 更新优惠券模板的已发放数量 + */ + private void updateCouponIssuedCount(Integer couponId, int increment) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(ShopCoupon::getId, couponId) + .setSql("issued_count = IFNULL(issued_count, 0) + " + increment); + shopCouponService.update(updateWrapper); + } +} diff --git a/src/main/java/com/gxwebsoft/shop/task/CouponScheduledTask.java b/src/main/java/com/gxwebsoft/shop/task/CouponScheduledTask.java new file mode 100644 index 0000000..a326d1c --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/task/CouponScheduledTask.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.shop.task; + +import com.gxwebsoft.shop.service.CouponBusinessService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 优惠券定时任务 + * + * @author 科技小王子 + * @since 2025-08-08 22:30:00 + */ +@Slf4j +@Component +public class CouponScheduledTask { + + @Resource + private CouponBusinessService couponBusinessService; + + /** + * 每天凌晨2点处理过期优惠券 + */ + @Scheduled(cron = "0 0 2 * * ?") + public void processExpiredCoupons() { + try { + log.info("开始执行过期优惠券处理任务"); + int count = couponBusinessService.autoProcessExpiredCoupons(); + log.info("过期优惠券处理任务完成,处理{}张优惠券", count); + } catch (Exception e) { + log.error("过期优惠券处理任务执行失败", e); + } + } + + /** + * 每天上午10点发送优惠券到期提醒 + */ + @Scheduled(cron = "0 0 10 * * ?") + public void sendExpiryReminder() { + try { + log.info("开始执行优惠券到期提醒任务"); + int count = couponBusinessService.sendCouponExpiryReminder(3); + log.info("优惠券到期提醒任务完成,提醒{}个用户", count); + } catch (Exception e) { + log.error("优惠券到期提醒任务执行失败", e); + } + } + + /** + * 每天凌晨1点发送生日优惠券 + */ + @Scheduled(cron = "0 0 1 * * ?") + public void issueBirthdayCoupons() { + try { + log.info("开始执行生日优惠券发放任务"); + // 这里需要获取今天生日的用户列表 + // 由于没有具体的用户生日查询方法,这里只是示例 + log.info("生日优惠券发放任务完成"); + } catch (Exception e) { + log.error("生日优惠券发放任务执行失败", e); + } + } +} diff --git a/src/main/java/com/gxwebsoft/shop/utils/CouponUtils.java b/src/main/java/com/gxwebsoft/shop/utils/CouponUtils.java new file mode 100644 index 0000000..4efe371 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/utils/CouponUtils.java @@ -0,0 +1,276 @@ +package com.gxwebsoft.shop.utils; + +import com.gxwebsoft.shop.entity.ShopUserCoupon; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.List; + +/** + * 优惠券工具类 + * + * @author 科技小王子 + * @since 2025-08-08 23:00:00 + */ +public class CouponUtils { + + /** + * 优惠券类型名称映射 + */ + public static String getTypeName(Integer type) { + if (type == null) { + return "未知"; + } + switch (type) { + case 10: + return "满减券"; + case 20: + return "折扣券"; + case 30: + return "免费券"; + default: + return "未知"; + } + } + + /** + * 优惠券状态名称映射 + */ + public static String getStatusName(Integer status) { + if (status == null) { + return "未知"; + } + switch (status) { + case 0: + return "未使用"; + case 1: + return "已使用"; + case 2: + return "已过期"; + default: + return "未知"; + } + } + + /** + * 适用范围名称映射 + */ + public static String getApplyRangeName(Integer applyRange) { + if (applyRange == null) { + return "未知"; + } + switch (applyRange) { + case 10: + return "全部商品"; + case 20: + return "指定商品"; + case 30: + return "指定分类"; + default: + return "未知"; + } + } + + /** + * 获取方式名称映射 + */ + public static String getObtainTypeName(Integer obtainType) { + if (obtainType == null) { + return "未知"; + } + switch (obtainType) { + case 10: + return "主动领取"; + case 20: + return "系统发放"; + case 30: + return "活动赠送"; + default: + return "未知"; + } + } + + /** + * 计算优惠券优惠金额 + * + * @param userCoupon 用户优惠券 + * @param orderAmount 订单金额 + * @return 优惠金额 + */ + public static BigDecimal calculateDiscountAmount(ShopUserCoupon userCoupon, BigDecimal orderAmount) { + if (userCoupon == null || orderAmount == null || orderAmount.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO; + } + + // 检查最低消费金额 + if (userCoupon.getMinPrice() != null && + orderAmount.compareTo(userCoupon.getMinPrice()) < 0) { + return BigDecimal.ZERO; + } + + BigDecimal discountAmount = BigDecimal.ZERO; + + if (userCoupon.getType() == ShopUserCoupon.TYPE_REDUCE) { + // 满减券 + discountAmount = userCoupon.getReducePrice() != null ? + userCoupon.getReducePrice() : BigDecimal.ZERO; + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_DISCOUNT) { + // 折扣券 + if (userCoupon.getDiscount() != null && userCoupon.getDiscount() > 0 && userCoupon.getDiscount() < 100) { + BigDecimal discountRate = BigDecimal.valueOf(100 - userCoupon.getDiscount()) + .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP); + discountAmount = orderAmount.multiply(discountRate); + } + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_FREE) { + // 免费券 + discountAmount = orderAmount; + } + + // 优惠金额不能超过订单金额 + return discountAmount.compareTo(orderAmount) > 0 ? orderAmount : discountAmount; + } + + /** + * 检查优惠券是否适用于指定商品 + * + * @param userCoupon 用户优惠券 + * @param goodsId 商品ID + * @param categoryId 商品分类ID + * @return 是否适用 + */ + public static boolean isApplicableToGoods(ShopUserCoupon userCoupon, Integer goodsId, Integer categoryId) { + if (userCoupon == null || userCoupon.getApplyRange() == null) { + return false; + } + + if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_ALL) { + // 全部商品可用 + return true; + } else if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_GOODS) { + // 指定商品可用 + if (goodsId == null || userCoupon.getApplyRangeConfig() == null) { + return false; + } + List goodsIds = Arrays.asList(userCoupon.getApplyRangeConfig().split(",")); + return goodsIds.contains(goodsId.toString()); + } else if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_CATEGORY) { + // 指定分类可用 + if (categoryId == null || userCoupon.getApplyRangeConfig() == null) { + return false; + } + List categoryIds = Arrays.asList(userCoupon.getApplyRangeConfig().split(",")); + return categoryIds.contains(categoryId.toString()); + } + + return false; + } + + /** + * 检查优惠券是否已过期 + * + * @param userCoupon 用户优惠券 + * @return 是否已过期 + */ + public static boolean isExpired(ShopUserCoupon userCoupon) { + if (userCoupon == null || userCoupon.getEndTime() == null) { + return false; + } + return userCoupon.getEndTime().isBefore(LocalDateTime.now()); + } + + /** + * 检查优惠券是否可用 + * + * @param userCoupon 用户优惠券 + * @return 是否可用 + */ + public static boolean isAvailable(ShopUserCoupon userCoupon) { + if (userCoupon == null) { + return false; + } + + // 检查状态 + if (userCoupon.getStatus() != ShopUserCoupon.STATUS_UNUSED) { + return false; + } + + // 检查是否过期 + if (isExpired(userCoupon)) { + return false; + } + + // 检查是否在有效期内 + LocalDateTime now = LocalDateTime.now(); + if (userCoupon.getStartTime() != null && userCoupon.getStartTime().isAfter(now)) { + return false; // 还未开始 + } + + return true; + } + + /** + * 格式化优惠券显示文本 + * + * @param userCoupon 用户优惠券 + * @return 显示文本 + */ + public static String formatCouponDisplay(ShopUserCoupon userCoupon) { + if (userCoupon == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + sb.append(userCoupon.getName()); + + if (userCoupon.getType() == ShopUserCoupon.TYPE_REDUCE && userCoupon.getReducePrice() != null) { + sb.append(" 减").append(userCoupon.getReducePrice()).append("元"); + if (userCoupon.getMinPrice() != null && userCoupon.getMinPrice().compareTo(BigDecimal.ZERO) > 0) { + sb.append("(满").append(userCoupon.getMinPrice()).append("可用)"); + } + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_DISCOUNT && userCoupon.getDiscount() != null) { + sb.append(" ").append(userCoupon.getDiscount()).append("折"); + if (userCoupon.getMinPrice() != null && userCoupon.getMinPrice().compareTo(BigDecimal.ZERO) > 0) { + sb.append("(满").append(userCoupon.getMinPrice()).append("可用)"); + } + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_FREE) { + sb.append(" 免费券"); + } + + if (userCoupon.getEndTime() != null) { + sb.append(" 有效期至").append(userCoupon.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + } + + return sb.toString(); + } + + /** + * 生成优惠券编码 + * + * @param userId 用户ID + * @param couponId 优惠券模板ID + * @return 优惠券编码 + */ + public static String generateCouponCode(Integer userId, Integer couponId) { + String timestamp = String.valueOf(System.currentTimeMillis()); + return String.format("CPN%s%s%s", + String.format("%08d", userId), + String.format("%06d", couponId), + timestamp.substring(timestamp.length() - 6)); + } + + /** + * 验证优惠券编码格式 + * + * @param couponCode 优惠券编码 + * @return 是否有效 + */ + public static boolean isValidCouponCode(String couponCode) { + if (couponCode == null || couponCode.length() != 23) { + return false; + } + return couponCode.startsWith("CPN") && couponCode.substring(3).matches("\\d{20}"); + } +} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 57406f0..c640d4b 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -45,7 +45,7 @@ mqtt: config: # 生产环境接口 server-url: https://server.websoft.top/api - upload-path: /www/wwwroot/file.ws/ + upload-path: /www/wwwroot/file.ws # 阿里云OSS云存储 endpoint: https://oss-cn-shenzhen.aliyuncs.com diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4d94f34..ad15671 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -18,16 +18,10 @@ spring: pathmatch: matching-strategy: ant_path_matcher -# 启用 SpringDoc OpenAPI -springdoc: - api-docs: - enabled: true - swagger-ui: - enabled: true - -# 启用 Knife4j -knife4j: - enable: true + # json时间格式设置 + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss # 连接池配置 datasource: @@ -54,11 +48,6 @@ knife4j: login-username: admin login-password: admin - # json时间格式设置 - jackson: - time-zone: GMT+8 - date-format: yyyy-MM-dd HH:mm:ss - # 设置上传文件大小 servlet: multipart: @@ -135,6 +124,7 @@ shop: # 默认配置 default-config: + default-title: "订单名称" default-comments: "暂无" min-order-amount: 0 order-timeout-minutes: 30 @@ -165,3 +155,14 @@ certificate: app-cert-public-key-file: "appCertPublicKey.crt" alipay-cert-public-key-file: "alipayCertPublicKey.crt" alipay-root-cert-file: "alipayRootCert.crt" + +# 启用 SpringDoc OpenAPI +springdoc: + api-docs: + enabled: true + swagger-ui: + enabled: true + +# 启用 Knife4j +knife4j: + enable: true diff --git a/src/main/resources/sql/coupon_tables.sql b/src/main/resources/sql/coupon_tables.sql new file mode 100644 index 0000000..37dd8ed --- /dev/null +++ b/src/main/resources/sql/coupon_tables.sql @@ -0,0 +1,78 @@ +-- 优惠券功能相关数据库表 + +-- 1. 更新优惠券模板表 +ALTER TABLE `shop_coupon` +ADD COLUMN `description` varchar(500) COMMENT '优惠券描述' AFTER `name`, +ADD COLUMN `total_count` int(11) DEFAULT -1 COMMENT '发放总数量(-1表示无限制)', +ADD COLUMN `issued_count` int(11) DEFAULT 0 COMMENT '已发放数量', +ADD COLUMN `limit_per_user` int(11) DEFAULT -1 COMMENT '每人限领数量(-1表示无限制)', +ADD COLUMN `enabled` tinyint(1) DEFAULT 1 COMMENT '是否启用(0禁用 1启用)', +MODIFY COLUMN `apply_range` int(11) DEFAULT 10 COMMENT '适用范围(10全部商品 20指定商品 30指定分类)', +MODIFY COLUMN `status` int(11) DEFAULT 0 COMMENT '状态, 0正常, 1禁用', +MODIFY COLUMN `user_id` int(11) COMMENT '创建用户ID'; + +-- 2. 创建用户优惠券表 +CREATE TABLE `shop_user_coupon` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `coupon_id` int(11) NOT NULL COMMENT '优惠券模板ID', + `user_id` int(11) NOT NULL COMMENT '用户ID', + `name` varchar(100) NOT NULL COMMENT '优惠券名称', + `description` varchar(500) DEFAULT NULL COMMENT '优惠券描述', + `type` int(11) NOT NULL COMMENT '优惠券类型(10满减券 20折扣券 30免费劵)', + `reduce_price` decimal(10,2) DEFAULT NULL COMMENT '满减券-减免金额', + `discount` int(11) DEFAULT NULL COMMENT '折扣券-折扣率(0-100)', + `min_price` decimal(10,2) DEFAULT NULL COMMENT '最低消费金额', + `apply_range` int(11) DEFAULT 10 COMMENT '适用范围(10全部商品 20指定商品 30指定分类)', + `apply_range_config` text COMMENT '适用范围配置(json格式)', + `start_time` datetime DEFAULT NULL COMMENT '有效期开始时间', + `end_time` datetime DEFAULT NULL COMMENT '有效期结束时间', + `status` int(11) DEFAULT 0 COMMENT '使用状态(0未使用 1已使用 2已过期)', + `use_time` datetime DEFAULT NULL COMMENT '使用时间', + `order_id` bigint(20) DEFAULT NULL COMMENT '使用订单ID', + `order_no` varchar(50) DEFAULT NULL COMMENT '使用订单号', + `obtain_type` int(11) DEFAULT 10 COMMENT '获取方式(10主动领取 20系统发放 30活动赠送)', + `obtain_source` varchar(200) DEFAULT NULL COMMENT '获取来源描述', + `deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户id', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_coupon_id` (`coupon_id`), + KEY `idx_status` (`status`), + KEY `idx_end_time` (`end_time`), + KEY `idx_order_id` (`order_id`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户优惠券'; + +-- 3. 创建优惠券使用记录表(可选,用于详细统计) +CREATE TABLE `shop_coupon_usage_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `user_coupon_id` bigint(20) NOT NULL COMMENT '用户优惠券ID', + `user_id` int(11) NOT NULL COMMENT '用户ID', + `order_id` bigint(20) NOT NULL COMMENT '订单ID', + `order_no` varchar(50) NOT NULL COMMENT '订单号', + `order_amount` decimal(10,2) NOT NULL COMMENT '订单金额', + `discount_amount` decimal(10,2) NOT NULL COMMENT '优惠金额', + `final_amount` decimal(10,2) NOT NULL COMMENT '最终金额', + `use_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '使用时间', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_order_id` (`order_id`), + KEY `idx_use_time` (`use_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券使用记录'; + +-- 4. 插入示例优惠券模板数据 +INSERT INTO `shop_coupon` (`name`, `description`, `type`, `reduce_price`, `discount`, `min_price`, `total_count`, `issued_count`, `limit_per_user`, `expire_type`, `expire_day`, `apply_range`, `apply_range_config`, `enabled`, `sort_number`, `status`, `user_id`, `tenant_id`) VALUES +('新用户专享券', '新用户注册即可领取,满100减20', 10, 20.00, NULL, 100.00, 1000, 0, 1, 10, 30, 10, NULL, 1, 1, 0, 1, 1), +('满减优惠券', '全场通用,满200减50', 10, 50.00, NULL, 200.00, 500, 0, 2, 20, NULL, 10, NULL, 1, 2, 0, 1, 1), +('折扣优惠券', '全场9折优惠券', 20, NULL, 10, 50.00, 300, 0, 1, 10, 15, 10, NULL, 1, 3, 0, 1, 1), +('生日专享券', '生日当天专享,满50减30', 10, 30.00, NULL, 50.00, -1, 0, 1, 10, 7, 10, NULL, 1, 4, 0, 1, 1), +('消费返券', '消费满500返100优惠券', 10, 100.00, NULL, 300.00, -1, 0, -1, 10, 60, 10, NULL, 1, 5, 0, 1, 1); + +-- 5. 创建索引优化查询性能 +CREATE INDEX `idx_shop_coupon_enabled_status` ON `shop_coupon` (`enabled`, `status`); +CREATE INDEX `idx_shop_coupon_expire_type` ON `shop_coupon` (`expire_type`, `start_time`, `end_time`); +CREATE INDEX `idx_shop_user_coupon_user_status` ON `shop_user_coupon` (`user_id`, `status`); +CREATE INDEX `idx_shop_user_coupon_expire` ON `shop_user_coupon` (`status`, `end_time`); diff --git a/src/test/java/com/gxwebsoft/bszx/BszxOrderTotalTest.java b/src/test/java/com/gxwebsoft/bszx/BszxOrderTotalTest.java new file mode 100644 index 0000000..7f769d6 --- /dev/null +++ b/src/test/java/com/gxwebsoft/bszx/BszxOrderTotalTest.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.bszx; + +import com.gxwebsoft.bszx.service.BszxPayService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 百色中学订单总金额统计测试 + * + * @author 科技小王子 + * @since 2025-07-31 + */ +@SpringBootTest +@ActiveProfiles("test") +public class BszxOrderTotalTest { + + @Resource + private BszxPayService bszxPayService; + + @Test + void testBszxOrderTotal() { + // 测试百色中学订单总金额统计 + BigDecimal total = bszxPayService.total(); + + // 验证返回值不为null + assertNotNull(total, "百色中学订单总金额不应该为null"); + + // 验证返回值大于等于0 + assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "百色中学订单总金额应该大于等于0"); + + System.out.println("百色中学订单总金额统计结果:" + total); + } + + @Test + void testBszxOrderTotalPerformance() { + // 测试性能 + long startTime = System.currentTimeMillis(); + + BigDecimal total = bszxPayService.total(); + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + System.out.println("百色中学订单总金额统计耗时:" + duration + "ms"); + System.out.println("统计结果:" + total); + + // 验证查询时间在合理范围内(小于5秒) + assertTrue(duration < 5000, "查询时间应该在5秒以内"); + } +} diff --git a/src/test/java/com/gxwebsoft/generator/ShopGenerator.java b/src/test/java/com/gxwebsoft/generator/ShopGenerator.java index aa208ad..4fe597a 100644 --- a/src/test/java/com/gxwebsoft/generator/ShopGenerator.java +++ b/src/test/java/com/gxwebsoft/generator/ShopGenerator.java @@ -20,9 +20,9 @@ public class ShopGenerator { // 输出目录 private static final String OUTPUT_DIR = "/src/main/java"; // Vue文件输出位置 - private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/VUE/shop"; + private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/VUE/mp-vue"; // Vue文件输出目录 - private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/APP/shop"; + private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/VUE/template-10550"; // Vue文件输出目录 private static final String OUTPUT_DIR_VUE = "/src"; // 作者名称 @@ -30,7 +30,7 @@ public class ShopGenerator { // 是否在xml中添加二级缓存配置 private static final boolean ENABLE_CACHE = false; // 数据库连接配置 - private static final String DB_URL = "jdbc:mysql://47.119.165.234:3308/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"; + private static final String DB_URL = "jdbc:mysql://1Panel-mysql-Bqdt:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"; private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String DB_USERNAME = "modules"; private static final String DB_PASSWORD = "8YdLnk7KsPAyDXGA"; diff --git a/src/test/java/com/gxwebsoft/house/util/SortSceneUtilManualTest.java b/src/test/java/com/gxwebsoft/house/util/SortSceneUtilManualTest.java new file mode 100644 index 0000000..4671c8b --- /dev/null +++ b/src/test/java/com/gxwebsoft/house/util/SortSceneUtilManualTest.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.house.util; + +/** + * SortSceneUtil手动测试类 + * 用于验证URL解码功能 + * + * @author 科技小王子 + * @since 2025-08-04 + */ +public class SortSceneUtilManualTest { + + public static void main(String[] args) { + // 测试URL编码的参数 + String urlEncoded = "%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)"; + System.out.println("原始URL编码参数: " + urlEncoded); + + String result = SortSceneUtil.normalizeSortScene(urlEncoded); + System.out.println("标准化后的参数: " + result); + System.out.println("是否为价格升序: " + SortSceneUtil.isPriceAsc(urlEncoded)); + + // 测试其他格式 + String[] testCases = { + "价格(低-高)", + "价格(高-低)", + "%E4%BB%B7%E6%A0%BC(%E9%AB%98-%E4%BD%8E)", + "最新发布", + "综合排序", + "面积(小-大)", + "面积(大-小)" + }; + + System.out.println("\n=== 测试各种排序场景 ==="); + for (String testCase : testCases) { + String normalized = SortSceneUtil.normalizeSortScene(testCase); + System.out.println("输入: " + testCase + " -> 输出: " + normalized); + } + } +} diff --git a/src/test/java/com/gxwebsoft/house/util/SortSceneUtilTest.java b/src/test/java/com/gxwebsoft/house/util/SortSceneUtilTest.java new file mode 100644 index 0000000..f15567a --- /dev/null +++ b/src/test/java/com/gxwebsoft/house/util/SortSceneUtilTest.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.house.util; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * SortSceneUtil测试类 + * + * @author 科技小王子 + * @since 2025-08-04 + */ +public class SortSceneUtilTest { + + @Test + public void testNormalizeSortScene() { + // 测试URL编码的参数 + String urlEncoded = "%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)"; + String result = SortSceneUtil.normalizeSortScene(urlEncoded); + assertEquals("价格(低-高)", result); + + // 测试已解码的参数 + String decoded = "价格(低-高)"; + result = SortSceneUtil.normalizeSortScene(decoded); + assertEquals("价格(低-高)", result); + + // 测试空值 + result = SortSceneUtil.normalizeSortScene(null); + assertNull(result); + + result = SortSceneUtil.normalizeSortScene(""); + assertNull(result); + + result = SortSceneUtil.normalizeSortScene(" "); + assertNull(result); + } + + @Test + public void testIsPriceAsc() { + assertTrue(SortSceneUtil.isPriceAsc("价格(低-高)")); + assertTrue(SortSceneUtil.isPriceAsc("%E4%BB%B7%E6%A0%BC(%E4%BD%8E-%E9%AB%98)")); + assertFalse(SortSceneUtil.isPriceAsc("价格(高-低)")); + assertFalse(SortSceneUtil.isPriceAsc("最新发布")); + } + + @Test + public void testIsPriceDesc() { + assertTrue(SortSceneUtil.isPriceDesc("价格(高-低)")); + assertFalse(SortSceneUtil.isPriceDesc("价格(低-高)")); + assertFalse(SortSceneUtil.isPriceDesc("最新发布")); + } + + @Test + public void testIsLatest() { + assertTrue(SortSceneUtil.isLatest("最新发布")); + assertFalse(SortSceneUtil.isLatest("价格(低-高)")); + } + + @Test + public void testIsComprehensive() { + assertTrue(SortSceneUtil.isComprehensive("综合排序")); + assertFalse(SortSceneUtil.isComprehensive("价格(低-高)")); + } +} diff --git a/src/test/java/com/gxwebsoft/shop/MultiSpecOrderTest.java b/src/test/java/com/gxwebsoft/shop/MultiSpecOrderTest.java new file mode 100644 index 0000000..7a47acc --- /dev/null +++ b/src/test/java/com/gxwebsoft/shop/MultiSpecOrderTest.java @@ -0,0 +1,174 @@ +package com.gxwebsoft.shop; + +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.dto.OrderCreateRequest; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.entity.ShopGoodsSku; +import com.gxwebsoft.shop.service.OrderBusinessService; +import com.gxwebsoft.shop.service.ShopGoodsService; +import com.gxwebsoft.shop.service.ShopGoodsSkuService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * 多规格订单测试类 + * + * @author 科技小王子 + * @since 2025-07-30 + */ +@ExtendWith(MockitoExtension.class) +public class MultiSpecOrderTest { + + @Mock + private ShopGoodsService shopGoodsService; + + @Mock + private ShopGoodsSkuService shopGoodsSkuService; + + @InjectMocks + private OrderBusinessService orderBusinessService; + + private User testUser; + private ShopGoods testGoods; + private ShopGoodsSku testSku; + + @BeforeEach + void setUp() { + // 创建测试用户 + testUser = new User(); + testUser.setUserId(1); + testUser.setTenantId(1); + testUser.setOpenid("test_openid"); + testUser.setPhone("13800138000"); + + // 创建测试商品 + testGoods = new ShopGoods(); + testGoods.setGoodsId(1); + testGoods.setName("测试商品"); + testGoods.setPrice(new BigDecimal("100.00")); + testGoods.setStock(50); + testGoods.setStatus(0); // 正常状态 + testGoods.setImage("test.jpg"); + + // 创建测试SKU + testSku = new ShopGoodsSku(); + testSku.setId(1); + testSku.setGoodsId(1); + testSku.setPrice(new BigDecimal("120.00")); + testSku.setStock(20); + testSku.setStatus(0); // 正常状态 + testSku.setSku("颜色:红色|尺寸:L"); + testSku.setImage("sku_test.jpg"); + } + + @Test + void testCreateOrderWithSingleSpec() { + // 测试单规格商品下单 + when(shopGoodsService.getById(1)).thenReturn(testGoods); + + OrderCreateRequest request = createOrderRequest(false); + + // 这里需要mock其他依赖服务,实际测试中需要完整的Spring上下文 + // 此测试主要验证多规格逻辑的正确性 + + assertNotNull(request); + assertEquals(1, request.getGoodsItems().size()); + assertNull(request.getGoodsItems().get(0).getSkuId()); + } + + @Test + void testCreateOrderWithMultiSpec() { + // 测试多规格商品下单 + when(shopGoodsService.getById(1)).thenReturn(testGoods); + when(shopGoodsSkuService.getById(1)).thenReturn(testSku); + + OrderCreateRequest request = createOrderRequest(true); + + assertNotNull(request); + assertEquals(1, request.getGoodsItems().size()); + assertEquals(Integer.valueOf(1), request.getGoodsItems().get(0).getSkuId()); + assertEquals("颜色:红色|尺寸:L", request.getGoodsItems().get(0).getSpecInfo()); + } + + @Test + void testSkuValidation() { + // 测试SKU验证逻辑 + when(shopGoodsService.getById(1)).thenReturn(testGoods); + + // 测试SKU不存在的情况 + when(shopGoodsSkuService.getById(999)).thenReturn(null); + + OrderCreateRequest request = createOrderRequest(true); + request.getGoodsItems().get(0).setSkuId(999); // 不存在的SKU ID + + // 在实际测试中,这里应该抛出BusinessException + // assertThrows(BusinessException.class, () -> orderBusinessService.createOrder(request, testUser)); + } + + @Test + void testStockValidation() { + // 测试库存验证 + testSku.setStock(1); // 设置库存为1 + when(shopGoodsService.getById(1)).thenReturn(testGoods); + when(shopGoodsSkuService.getById(1)).thenReturn(testSku); + + OrderCreateRequest request = createOrderRequest(true); + request.getGoodsItems().get(0).setQuantity(5); // 购买数量超过库存 + + // 在实际测试中,这里应该抛出BusinessException + // assertThrows(BusinessException.class, () -> orderBusinessService.createOrder(request, testUser)); + } + + @Test + void testPriceCalculation() { + // 测试价格计算 + when(shopGoodsService.getById(1)).thenReturn(testGoods); + when(shopGoodsSkuService.getById(1)).thenReturn(testSku); + + // 多规格商品应该使用SKU价格(120.00),而不是商品价格(100.00) + OrderCreateRequest request = createOrderRequest(true); + request.getGoodsItems().get(0).setQuantity(2); + + // 期望总价格 = SKU价格(120.00) * 数量(2) = 240.00 + BigDecimal expectedTotal = new BigDecimal("240.00"); + request.setTotalPrice(expectedTotal); + + assertEquals(expectedTotal, request.getTotalPrice()); + } + + /** + * 创建订单请求对象 + */ + private OrderCreateRequest createOrderRequest(boolean withSku) { + OrderCreateRequest request = new OrderCreateRequest(); + request.setType(0); + request.setTotalPrice(new BigDecimal("100.00")); + request.setPayPrice(new BigDecimal("100.00")); + request.setTotalNum(1); + request.setTenantId(1); + + OrderCreateRequest.OrderGoodsItem item = new OrderCreateRequest.OrderGoodsItem(); + item.setGoodsId(1); + item.setQuantity(1); + + if (withSku) { + item.setSkuId(1); + item.setSpecInfo("颜色:红色|尺寸:L"); + } + + request.setGoodsItems(Arrays.asList(item)); + return request; + } +} diff --git a/src/test/java/com/gxwebsoft/shop/OrderBusinessServiceTest.java b/src/test/java/com/gxwebsoft/shop/OrderBusinessServiceTest.java new file mode 100644 index 0000000..462282c --- /dev/null +++ b/src/test/java/com/gxwebsoft/shop/OrderBusinessServiceTest.java @@ -0,0 +1,170 @@ +package com.gxwebsoft.shop; + +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.dto.OrderCreateRequest; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.entity.ShopOrderGoods; +import com.gxwebsoft.shop.service.OrderBusinessService; +import com.gxwebsoft.shop.service.ShopGoodsService; +import com.gxwebsoft.shop.service.ShopOrderGoodsService; +import com.gxwebsoft.shop.service.ShopOrderService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * 订单业务服务测试类 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@ExtendWith(MockitoExtension.class) +public class OrderBusinessServiceTest { + + @Mock + private ShopOrderService shopOrderService; + + @Mock + private ShopOrderGoodsService shopOrderGoodsService; + + @Mock + private ShopGoodsService shopGoodsService; + + @InjectMocks + private OrderBusinessService orderBusinessService; + + private User testUser; + private OrderCreateRequest testRequest; + private ShopGoods testGoods; + + @BeforeEach + void setUp() { + // 准备测试用户 + testUser = new User(); + testUser.setUserId(1); + testUser.setOpenid("test_openid"); + testUser.setPhone("13800138000"); + + // 准备测试商品 + testGoods = new ShopGoods(); + testGoods.setGoodsId(10018); + testGoods.setName("科技小王子大米年卡套餐2.5kg"); + testGoods.setPrice(new BigDecimal("99.00")); + testGoods.setImage("test_image.jpg"); + + // 准备测试订单请求 + testRequest = new OrderCreateRequest(); + testRequest.setType(0); + testRequest.setTotalPrice(new BigDecimal("99.00")); + testRequest.setPayPrice(new BigDecimal("99.00")); + testRequest.setTotalNum(1); + testRequest.setPayType(1); + testRequest.setTenantId(1); + testRequest.setAddressId(10832); + testRequest.setComments("科技小王子大米年卡套餐2.5kg"); + testRequest.setDeliveryType(0); + + // 准备商品项列表 + OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem(); + goodsItem.setGoodsId(10018); + goodsItem.setQuantity(1); + goodsItem.setPayType(1); + + testRequest.setGoodsItems(Arrays.asList(goodsItem)); + } + + @Test + void testCreateOrderWithGoods() { + // Mock 商品查询 + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + + // Mock 订单保存 + when(shopOrderService.save(any(ShopOrder.class))).thenAnswer(invocation -> { + ShopOrder order = invocation.getArgument(0); + order.setOrderId(1); // 模拟数据库生成的ID + return true; + }); + + // Mock 订单商品批量保存 + when(shopOrderGoodsService.saveBatch(anyList())).thenReturn(true); + + // Mock 微信支付订单创建 + HashMap wxOrderInfo = new HashMap<>(); + wxOrderInfo.put("prepay_id", "test_prepay_id"); + when(shopOrderService.createWxOrder(any(ShopOrder.class))).thenReturn(wxOrderInfo); + + // 执行测试 + Map result = orderBusinessService.createOrder(testRequest, testUser); + + // 验证结果 + assert result != null; + assert result.containsKey("prepay_id"); + + // 验证方法调用 + verify(shopGoodsService, times(1)).getById(10018); + verify(shopOrderService, times(1)).save(any(ShopOrder.class)); + verify(shopOrderGoodsService, times(1)).saveBatch(anyList()); + verify(shopOrderService, times(1)).createWxOrder(any(ShopOrder.class)); + } + + @Test + void testCreateOrderWithMultipleGoods() { + // 准备多个商品项 + OrderCreateRequest.OrderGoodsItem goodsItem1 = new OrderCreateRequest.OrderGoodsItem(); + goodsItem1.setGoodsId(10018); + goodsItem1.setQuantity(1); + goodsItem1.setPayType(1); + + OrderCreateRequest.OrderGoodsItem goodsItem2 = new OrderCreateRequest.OrderGoodsItem(); + goodsItem2.setGoodsId(10019); + goodsItem2.setQuantity(2); + goodsItem2.setPayType(1); + + testRequest.setGoodsItems(Arrays.asList(goodsItem1, goodsItem2)); + testRequest.setTotalPrice(new BigDecimal("297.00")); // 99 + 99*2 + + // Mock 商品查询 + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + + ShopGoods testGoods2 = new ShopGoods(); + testGoods2.setGoodsId(10019); + testGoods2.setName("测试商品2"); + testGoods2.setPrice(new BigDecimal("99.00")); + testGoods2.setImage("test_image2.jpg"); + when(shopGoodsService.getById(10019)).thenReturn(testGoods2); + + // Mock 其他服务 + when(shopOrderService.save(any(ShopOrder.class))).thenAnswer(invocation -> { + ShopOrder order = invocation.getArgument(0); + order.setOrderId(1); + return true; + }); + when(shopOrderGoodsService.saveBatch(anyList())).thenReturn(true); + when(shopOrderService.createWxOrder(any(ShopOrder.class))).thenReturn(new HashMap<>()); + + // 执行测试 + orderBusinessService.createOrder(testRequest, testUser); + + // 验证商品查询次数 + verify(shopGoodsService, times(1)).getById(10018); + verify(shopGoodsService, times(1)).getById(10019); + + // 验证保存的商品项数量 + verify(shopOrderGoodsService, times(1)).saveBatch(argThat(list -> + ((List) list).size() == 2 + )); + } +} diff --git a/src/test/java/com/gxwebsoft/shop/OrderTotalTest.java b/src/test/java/com/gxwebsoft/shop/OrderTotalTest.java new file mode 100644 index 0000000..ca4d231 --- /dev/null +++ b/src/test/java/com/gxwebsoft/shop/OrderTotalTest.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.shop; + +import com.gxwebsoft.shop.service.ShopOrderService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 订单总金额统计测试 + * + * @author 科技小王子 + * @since 2025-07-30 + */ +@SpringBootTest +@ActiveProfiles("test") +public class OrderTotalTest { + + @Resource + private ShopOrderService shopOrderService; + + @Test + void testOrderTotal() { + // 测试订单总金额统计 + BigDecimal total = shopOrderService.total(); + + // 验证返回值不为null + assertNotNull(total, "订单总金额不应该为null"); + + // 验证返回值大于等于0 + assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "订单总金额应该大于等于0"); + + System.out.println("订单总金额统计结果:" + total); + } + + @Test + void testOrderTotalPerformance() { + // 测试性能 + long startTime = System.currentTimeMillis(); + + BigDecimal total = shopOrderService.total(); + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + System.out.println("订单总金额统计耗时:" + duration + "ms"); + System.out.println("统计结果:" + total); + + // 验证查询时间在合理范围内(小于5秒) + assertTrue(duration < 5000, "查询时间应该在5秒以内"); + } +} diff --git a/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java b/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java new file mode 100644 index 0000000..a49c444 --- /dev/null +++ b/src/test/java/com/gxwebsoft/shop/OrderValidationTest.java @@ -0,0 +1,315 @@ +package com.gxwebsoft.shop; + +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.config.OrderConfigProperties; +import com.gxwebsoft.shop.dto.OrderCreateRequest; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.service.OrderBusinessService; +import com.gxwebsoft.shop.service.ShopGoodsService; +import com.gxwebsoft.shop.service.ShopOrderGoodsService; +import com.gxwebsoft.shop.service.ShopOrderService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * 订单验证测试类 + * 测试商品信息后台验证逻辑 + */ +@ExtendWith(MockitoExtension.class) +class OrderValidationTest { + + @Mock + private ShopOrderService shopOrderService; + + @Mock + private ShopOrderGoodsService shopOrderGoodsService; + + @Mock + private ShopGoodsService shopGoodsService; + + @Mock + private OrderConfigProperties orderConfig; + + @InjectMocks + private OrderBusinessService orderBusinessService; + + private User testUser; + private OrderCreateRequest testRequest; + private ShopGoods testGoods; + + @BeforeEach + void setUp() { + // 准备测试用户 + testUser = new User(); + testUser.setUserId(1); + testUser.setNickname("测试用户"); + testUser.setPhone("13800138000"); + + // 准备测试商品 + testGoods = new ShopGoods(); + testGoods.setGoodsId(10018); + testGoods.setName("测试商品"); + testGoods.setPrice(new BigDecimal("99.00")); + testGoods.setStatus(0); // 上架状态 + testGoods.setStock(100); // 库存100 + testGoods.setCanBuyNumber(10); // 最大购买数量10 + testGoods.setCode("TEST001"); + + // 准备测试订单请求 + testRequest = new OrderCreateRequest(); + testRequest.setType(0); + testRequest.setTitle("测试订单"); + testRequest.setTotalPrice(new BigDecimal("99.00")); + testRequest.setTenantId(1); + + // 准备商品项 + OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem(); + goodsItem.setGoodsId(10018); + goodsItem.setQuantity(1); + testRequest.setGoodsItems(Arrays.asList(goodsItem)); + } + + @Test + void testValidateOrderRequest_Success() { + // Mock 商品查询 + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + when(orderConfig.getTenantRule(1)).thenReturn(null); + + // 执行验证 - 应该成功 + assertDoesNotThrow(() -> { + // 使用反射调用私有方法进行测试 + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 验证总金额被正确设置 + assertEquals(new BigDecimal("99.00"), testRequest.getTotalPrice()); + } + + @Test + void testValidateOrderRequest_GoodsNotFound() { + // Mock 商品不存在 + when(shopGoodsService.getById(10018)).thenReturn(null); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 检查是否是 InvocationTargetException 包装的 BusinessException + assertTrue(exception instanceof java.lang.reflect.InvocationTargetException); + Throwable cause = exception.getCause(); + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("商品不存在")); + } + + @Test + void testValidateOrderRequest_GoodsOffShelf() { + // 设置商品为下架状态 + testGoods.setStatus(1); + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 检查是否是 InvocationTargetException 包装的 BusinessException + assertTrue(exception instanceof java.lang.reflect.InvocationTargetException); + Throwable cause = exception.getCause(); + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("商品已下架")); + } + + @Test + void testValidateOrderRequest_InsufficientStock() { + // 设置库存不足 + testGoods.setStock(0); + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 检查是否是 InvocationTargetException 包装的 BusinessException + assertTrue(exception instanceof java.lang.reflect.InvocationTargetException); + Throwable cause = exception.getCause(); + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("商品库存不足")); + } + + @Test + void testValidateOrderRequest_ExceedBuyLimit() { + // 设置购买数量超过限制 + testRequest.getGoodsItems().get(0).setQuantity(15); // 超过最大购买数量10 + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 检查是否是 InvocationTargetException 包装的 BusinessException + assertTrue(exception instanceof java.lang.reflect.InvocationTargetException); + Throwable cause = exception.getCause(); + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("购买数量超过限制")); + } + + @Test + void testValidateOrderRequest_PriceCalculation() { + // 设置多个商品项 + OrderCreateRequest.OrderGoodsItem goodsItem1 = new OrderCreateRequest.OrderGoodsItem(); + goodsItem1.setGoodsId(10018); + goodsItem1.setQuantity(2); + + OrderCreateRequest.OrderGoodsItem goodsItem2 = new OrderCreateRequest.OrderGoodsItem(); + goodsItem2.setGoodsId(10019); + goodsItem2.setQuantity(1); + + testRequest.setGoodsItems(Arrays.asList(goodsItem1, goodsItem2)); + testRequest.setTotalPrice(new BigDecimal("297.00")); // 99*2 + 99*1 + + // 准备第二个商品 + ShopGoods testGoods2 = new ShopGoods(); + testGoods2.setGoodsId(10019); + testGoods2.setName("测试商品2"); + testGoods2.setPrice(new BigDecimal("99.00")); + testGoods2.setStatus(0); + testGoods2.setStock(100); + + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + when(shopGoodsService.getById(10019)).thenReturn(testGoods2); + when(orderConfig.getTenantRule(1)).thenReturn(null); + + // 执行验证 - 应该成功 + assertDoesNotThrow(() -> { + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 验证总金额计算正确 + assertEquals(new BigDecimal("297.00"), testRequest.getTotalPrice()); + } + + @Test + void testValidateOrderRequest_PriceDiscrepancy() { + // 设置前端传入的金额与后台计算不一致 + testRequest.setTotalPrice(new BigDecimal("88.00")); // 错误的金额 + when(shopGoodsService.getById(10018)).thenReturn(testGoods); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + java.lang.reflect.Method method = OrderBusinessService.class + .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class); + method.setAccessible(true); + method.invoke(orderBusinessService, testRequest, testUser); + }); + + // 检查是否是 InvocationTargetException 包装的 BusinessException + assertTrue(exception instanceof java.lang.reflect.InvocationTargetException); + Throwable cause = exception.getCause(); + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("订单金额计算错误")); + } + + @Test + void testBuildShopOrder_RequiredFields() throws Exception { + // Mock 配置 + OrderConfigProperties.DefaultConfig defaultConfig = new OrderConfigProperties.DefaultConfig(); + defaultConfig.setDefaultComments("默认备注"); + when(orderConfig.getDefaultConfig()).thenReturn(defaultConfig); + + // 使用反射调用 buildShopOrder 方法 + java.lang.reflect.Method buildMethod = OrderBusinessService.class + .getDeclaredMethod("buildShopOrder", OrderCreateRequest.class, User.class); + buildMethod.setAccessible(true); + + ShopOrder result = (ShopOrder) buildMethod.invoke(orderBusinessService, testRequest, testUser); + + // 验证必需字段都已设置 + assertNotNull(result.getPayPrice(), "payPrice 不能为空"); + assertNotNull(result.getPrice(), "price 不能为空"); + assertNotNull(result.getReducePrice(), "reducePrice 不能为空"); + assertNotNull(result.getMoney(), "money 不能为空"); + assertNotNull(result.getPayStatus(), "payStatus 不能为空"); + assertNotNull(result.getOrderStatus(), "orderStatus 不能为空"); + assertNotNull(result.getDeliveryStatus(), "deliveryStatus 不能为空"); + assertNotNull(result.getPayType(), "payType 不能为空"); + + // 验证默认值 + assertEquals(testRequest.getTotalPrice(), result.getPayPrice()); + assertEquals(testRequest.getTotalPrice(), result.getPrice()); + assertEquals(BigDecimal.ZERO, result.getReducePrice()); + assertEquals(testRequest.getTotalPrice(), result.getMoney()); + assertEquals(false, result.getPayStatus()); + assertEquals(Integer.valueOf(0), result.getOrderStatus()); + assertEquals(Integer.valueOf(10), result.getDeliveryStatus()); + assertEquals(Integer.valueOf(1), result.getPayType()); + + // 验证关键字段 - 租户ID(影响微信支付证书路径) + assertNotNull(result.getTenantId(), "tenantId 不能为空"); + assertEquals(testRequest.getTenantId(), result.getTenantId(), "tenantId 必须正确设置"); + } + + @Test + void testBuildShopOrder_TenantIdValidation() throws Exception { + // 创建一个新的请求对象,租户ID为空 + OrderCreateRequest requestWithoutTenant = new OrderCreateRequest(); + requestWithoutTenant.setType(0); + requestWithoutTenant.setTitle("测试订单"); + requestWithoutTenant.setTotalPrice(new BigDecimal("99.00")); + requestWithoutTenant.setTenantId(null); // 设置为空 + + // 准备商品项 + OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem(); + goodsItem.setGoodsId(10018); + goodsItem.setQuantity(1); + requestWithoutTenant.setGoodsItems(Arrays.asList(goodsItem)); + + // 使用反射调用 buildShopOrder 方法 + java.lang.reflect.Method buildMethod = OrderBusinessService.class + .getDeclaredMethod("buildShopOrder", OrderCreateRequest.class, User.class); + buildMethod.setAccessible(true); + + // 执行验证 - 应该抛出异常 + Exception exception = assertThrows(Exception.class, () -> { + buildMethod.invoke(orderBusinessService, requestWithoutTenant, testUser); + }); + + // 检查是否是 InvocationTargetException 包装的 BusinessException + assertTrue(exception instanceof java.lang.reflect.InvocationTargetException); + Throwable cause = exception.getCause(); + assertTrue(cause instanceof BusinessException); + assertTrue(cause.getMessage().contains("租户ID不能为空")); + } +} diff --git a/下单流程图.svg b/下单流程图.svg new file mode 100644 index 0000000..6dfab6c --- /dev/null +++ b/下单流程图.svg @@ -0,0 +1 @@ +

前端提交订单请求

validateOrderRequest

用户是否登录?

抛出异常: 用户未登录

validateAndCalculateTotal

遍历商品列表

根据商品ID查询商品信息

商品是否存在?

抛出异常: 商品不存在

商品是否上架?

抛出异常: 商品已下架

库存是否充足?

抛出异常: 库存不足

是否超过购买限制?

抛出异常: 超过购买限制

计算商品小计

累加到总金额

还有其他商品?

返回计算的总金额

前端金额与后台计算是否一致?

抛出异常: 金额计算错误

使用后台计算的金额

检查租户规则

验证通过

构建订单对象

保存订单

saveOrderGoods

重新验证商品状态

使用后台数据保存订单商品

订单创建成功

\ No newline at end of file