Compare commits
10 Commits
main
...
47ef45054a
| Author | SHA1 | Date | |
|---|---|---|---|
| 47ef45054a | |||
| 9297d13045 | |||
| 701a135edd | |||
| 6781374c1e | |||
| 7c90f5e8af | |||
| 721ce5a595 | |||
| 506505bb46 | |||
| 8b83e4862f | |||
| 800b4f6f93 | |||
| 498a47977e |
39
.workbuddy/expert-history.json
Normal file
39
.workbuddy/expert-history.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"version": 2,
|
||||
"sessions": {
|
||||
"7759a9e57f984a0bb5af2ffd05be2f63": [
|
||||
{
|
||||
"expertId": "SeniorDeveloper",
|
||||
"name": "Will",
|
||||
"profession": "高级开发工程师",
|
||||
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/SeniorDeveloper/SeniorDeveloper.png",
|
||||
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/SeniorDeveloper/SeniorDeveloper_zh.md",
|
||||
"usedAt": 1775972794982,
|
||||
"industryId": "all"
|
||||
}
|
||||
],
|
||||
"e7c3c15a2556446884e56ce4d588e133": [
|
||||
{
|
||||
"expertId": "SeniorDeveloper",
|
||||
"name": "Will",
|
||||
"profession": "高级开发工程师",
|
||||
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/SeniorDeveloper/SeniorDeveloper.png",
|
||||
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/SeniorDeveloper/SeniorDeveloper_zh.md",
|
||||
"usedAt": 1776000797914,
|
||||
"industryId": "all"
|
||||
}
|
||||
],
|
||||
"44c34a14b6dc4139b39ff61239e259ea": [
|
||||
{
|
||||
"expertId": "SeniorDeveloper",
|
||||
"name": "Will",
|
||||
"profession": "高级开发工程师",
|
||||
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/SeniorDeveloper/SeniorDeveloper.png",
|
||||
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/SeniorDeveloper/SeniorDeveloper_zh.md",
|
||||
"usedAt": 1776000797914,
|
||||
"industryId": "all"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lastUpdated": 1776017699886
|
||||
}
|
||||
13
.workbuddy/memory/2026-04-12.md
Normal file
13
.workbuddy/memory/2026-04-12.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 2026-04-12 工作日志
|
||||
|
||||
## 修复登录日志时间显示问题
|
||||
|
||||
**问题描述**:小程序后台登录日志中的登录时间显示不正确,实际登录时间 9:20:20,显示为 17:16:31,相差约 8 小时。
|
||||
|
||||
**问题原因**:`LoginRecord` 实体类中的 `createTime` 和 `updateTime` 字段使用了 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")` 注解,但没有指定 `timezone` 属性。对于 `LocalDateTime` 类型,Jackson 序列化时未正确应用全局时区配置,导致时间多了 8 小时。
|
||||
|
||||
**修复方案**:为 `@JsonFormat` 注解添加 `timezone = "GMT+8"` 属性。
|
||||
|
||||
**修改文件**:`src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java`
|
||||
|
||||
**状态**:已修复
|
||||
15
.workbuddy/memory/2026-04-13.md
Normal file
15
.workbuddy/memory/2026-04-13.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 2026-04-13 工作日志
|
||||
|
||||
## 修复支付回调订单状态不更新问题
|
||||
|
||||
**问题描述**:支付成功后,订单支付状态没有更新,回调地址 `https://glt-api.websoft.top/api/shop/shop-order/notify` 接收到了通知但订单状态未改变。
|
||||
|
||||
**问题原因**:`ShopOrderController.java` 的 `wxNotify` 方法中,使用 `StrUtil.equals("支付成功", transaction.getTradeStateDesc())` 来判断支付状态。但微信返回的 `tradeStateDesc` 可能不是固定的 "支付成功" 字符串(可能是 "SUCCESS" 或其他描述),导致支付成功的回调没有被正确处理。
|
||||
|
||||
**修复方案**:将状态判断从字符串比较改为枚举值比较:
|
||||
- 原代码:`if (StrUtil.equals("支付成功", transaction.getTradeStateDesc()))`
|
||||
- 修复后:`if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState()))`
|
||||
|
||||
**修改文件**:`src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java`
|
||||
|
||||
**状态**:已修复
|
||||
0
.workbuddy/memory/MEMORY.md
Normal file
0
.workbuddy/memory/MEMORY.md
Normal file
7
sql/glt_ticket_order_delivery_fields.sql
Normal file
7
sql/glt_ticket_order_delivery_fields.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
-- 配送方式、楼层、配送费字段
|
||||
-- 对应需求:送水订单下单时选择配送方式(电梯/步梯/一楼商铺),步梯送上楼需选楼层,配送费 = 数量 × (楼层-1)
|
||||
|
||||
ALTER TABLE glt_ticket_order
|
||||
ADD COLUMN delivery_method VARCHAR(32) DEFAULT NULL COMMENT '配送方式:elevator(电梯) / stairs(步梯) / groundFloor(一楼商铺/其他)' AFTER buyer_remarks,
|
||||
ADD COLUMN delivery_floor INT DEFAULT NULL COMMENT '楼层(步梯+送上楼时有值,从2开始)' AFTER delivery_method,
|
||||
ADD COLUMN delivery_fee DECIMAL(10,2) DEFAULT NULL COMMENT '配送费(数量 × (楼层-1))' AFTER delivery_floor;
|
||||
@@ -58,11 +58,11 @@ public class LoginRecord implements Serializable {
|
||||
private Integer tenantId;
|
||||
|
||||
@Schema(description = "操作时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@Schema(description = "用户id")
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package com.gxwebsoft.glt.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
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.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import com.gxwebsoft.common.system.mapper.UserMapper;
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
import com.gxwebsoft.glt.param.GltTicketOrderDeliveredParam;
|
||||
import com.gxwebsoft.glt.param.GltTicketOrderParam;
|
||||
import com.gxwebsoft.glt.service.GltSubscribeMessageService;
|
||||
import com.gxwebsoft.glt.service.GltTicketOrderService;
|
||||
import com.gxwebsoft.shop.entity.ShopStoreRider;
|
||||
import com.gxwebsoft.shop.entity.ShopUserAddress;
|
||||
@@ -19,12 +22,13 @@ import com.gxwebsoft.shop.service.ShopUserAddressService;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 送水订单控制器
|
||||
@@ -32,6 +36,7 @@ import java.util.List;
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:21
|
||||
*/
|
||||
@Slf4j
|
||||
@Tag(name = "送水订单管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/glt/glt-ticket-order")
|
||||
@@ -44,6 +49,10 @@ public class GltTicketOrderController extends BaseController {
|
||||
private ShopStoreFenceService shopStoreFenceService;
|
||||
@Resource
|
||||
private ShopStoreRiderService shopStoreRiderService;
|
||||
@Resource
|
||||
private GltSubscribeMessageService gltSubscribeMessageService;
|
||||
@Resource
|
||||
private UserMapper userMapper;
|
||||
|
||||
@Operation(summary = "分页查询送水订单")
|
||||
@GetMapping("/page")
|
||||
@@ -167,9 +176,76 @@ public class GltTicketOrderController extends BaseController {
|
||||
}
|
||||
|
||||
gltTicketOrderService.createWithWriteOff(gltTicketOrder, loginUser.getUserId(), loginUser.getTenantId());
|
||||
|
||||
// 订单创建成功后,异步通知所有在线配送员有新订单
|
||||
try {
|
||||
notifyRidersOfNewOrder(gltTicketOrder, loginUser.getTenantId());
|
||||
} catch (Exception e) {
|
||||
log.warn("通知配送员失败(不影响下单): {}", e.getMessage());
|
||||
}
|
||||
|
||||
return success("下单成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知所有在线配送员有新订单
|
||||
*/
|
||||
private void notifyRidersOfNewOrder(GltTicketOrder order, Integer tenantId) {
|
||||
if (order == null || tenantId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询所有启用且在线的配送员
|
||||
List<ShopStoreRider> onlineRiders = shopStoreRiderService.list(
|
||||
new LambdaQueryWrapper<ShopStoreRider>()
|
||||
.eq(ShopStoreRider::getTenantId, tenantId)
|
||||
.eq(ShopStoreRider::getIsDelete, 0)
|
||||
.eq(ShopStoreRider::getStatus, 1)
|
||||
.eq(ShopStoreRider::getWorkStatus, 1) // 在线状态
|
||||
.or()
|
||||
.eq(ShopStoreRider::getTenantId, tenantId)
|
||||
.eq(ShopStoreRider::getIsDelete, 0)
|
||||
.eq(ShopStoreRider::getStatus, 1)
|
||||
.isNull(ShopStoreRider::getWorkStatus) // 兼容未设置状态的配送员
|
||||
);
|
||||
|
||||
if (onlineRiders == null || onlineRiders.isEmpty()) {
|
||||
log.info("当前无在线配送员,无需发送订阅消息");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取配送员的 userId 列表
|
||||
List<Integer> riderUserIds = onlineRiders.stream()
|
||||
.map(ShopStoreRider::getUserId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (riderUserIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 批量查询配送员的 openId
|
||||
List<User> riders = userMapper.selectList(
|
||||
new LambdaQueryWrapper<User>()
|
||||
.select(User::getUserId, User::getOpenid)
|
||||
.in(User::getUserId, riderUserIds)
|
||||
.isNotNull(User::getOpenid)
|
||||
);
|
||||
|
||||
// 发送订阅消息
|
||||
for (User rider : riders) {
|
||||
if (StrUtil.isNotBlank(rider.getOpenid())) {
|
||||
try {
|
||||
gltSubscribeMessageService.sendNewOrderNotice(order, rider.getOpenid(), tenantId);
|
||||
} catch (Exception e) {
|
||||
log.warn("发送订阅消息给配送员失败 - userId={}, error={}", rider.getUserId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("已向 {} 位配送员发送新订单通知", riders.size());
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@Operation(summary = "配送员接单")
|
||||
@PostMapping("/{id}/accept")
|
||||
|
||||
@@ -191,6 +191,15 @@ public class GltTicketOrder implements Serializable {
|
||||
@TableField(exist = false)
|
||||
private String warehouseLngAndLat;
|
||||
|
||||
@Schema(description = "配送方式:elevator(电梯) / stairs(步梯) / groundFloor(一楼商铺/其他)")
|
||||
private String deliveryMethod;
|
||||
|
||||
@Schema(description = "楼层(步梯+送上楼时有值,从2开始)")
|
||||
private Integer deliveryFloor;
|
||||
|
||||
@Schema(description = "配送费(步梯+送上楼时计算:数量 × (楼层-1))")
|
||||
private BigDecimal deliveryFee;
|
||||
|
||||
@Schema(description = "排序(数字越小越靠前)")
|
||||
private Integer sortNumber;
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.gxwebsoft.glt.service;
|
||||
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
|
||||
/**
|
||||
* 微信订阅消息服务接口
|
||||
*/
|
||||
public interface GltSubscribeMessageService {
|
||||
|
||||
/**
|
||||
* 发送新订单通知给配送员
|
||||
* @param order 订单信息
|
||||
* @param riderOpenId 配送员微信openId
|
||||
* @param tenantId 租户ID
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
boolean sendNewOrderNotice(GltTicketOrder order, String riderOpenId, Integer tenantId);
|
||||
|
||||
/**
|
||||
* 发送订单状态变更通知
|
||||
* @param order 订单信息
|
||||
* @param riderOpenId 配送员微信openId
|
||||
* @param statusText 状态描述
|
||||
* @param tenantId 租户ID
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
boolean sendOrderStatusNotice(GltTicketOrder order, String riderOpenId, String statusText, Integer tenantId);
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package com.gxwebsoft.glt.service.impl;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.core.utils.RedisUtil;
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
import com.gxwebsoft.glt.service.GltSubscribeMessageService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.gxwebsoft.common.core.constants.RedisConstants.*;
|
||||
|
||||
/**
|
||||
* 微信订阅消息服务实现
|
||||
*
|
||||
* <p>功能:
|
||||
* <ul>
|
||||
* <li>新订单通知配送员</li>
|
||||
* <li>订单状态变更通知</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageService {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 订阅消息模板ID(需在微信公众平台配置)
|
||||
* 模板名称:订单配送通知
|
||||
* 关键词:订单编号、订单内容、配送地址、订单金额
|
||||
*/
|
||||
private static final String SUBSCRIBE_TEMPLATE_ID = "YOUR_TEMPLATE_ID"; // TODO: 替换为实际模板ID
|
||||
|
||||
/**
|
||||
* 发送新订单通知给配送员
|
||||
*/
|
||||
@Override
|
||||
public boolean sendNewOrderNotice(GltTicketOrder order, String riderOpenId, Integer tenantId) {
|
||||
if (order == null || StrUtil.isBlank(riderOpenId) || tenantId == null) {
|
||||
log.warn("发送订阅消息参数不完整");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
String accessToken = getAccessToken(tenantId);
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
log.warn("获取access_token失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 构建消息内容
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("phrase1", Map.of("value", "待配送")); // 订单状态
|
||||
data.put("character_string2", Map.of("value", String.valueOf(order.getId()))); // 订单编号
|
||||
data.put("thing3", Map.of("value", truncateStr(order.getAddress(), 20))); // 配送地址
|
||||
data.put("number4", Map.of("value", String.valueOf(order.getTotalNum()))); // 商品数量
|
||||
data.put("time5", Map.of("value", formatTime(order.getSendTime()))); // 期望送达时间
|
||||
|
||||
// 发送订阅消息
|
||||
return sendSubscribeMessage(accessToken, riderOpenId, data);
|
||||
} catch (Exception e) {
|
||||
log.error("发送新订单订阅消息失败 - orderId={}, riderOpenId={}, error={}",
|
||||
order.getId(), riderOpenId, e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送订单状态变更通知
|
||||
*/
|
||||
@Override
|
||||
public boolean sendOrderStatusNotice(GltTicketOrder order, String riderOpenId, String statusText, Integer tenantId) {
|
||||
if (order == null || StrUtil.isBlank(riderOpenId) || tenantId == null) {
|
||||
log.warn("发送订阅消息参数不完整");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
String accessToken = getAccessToken(tenantId);
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
log.warn("获取access_token失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 构建消息内容
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("phrase1", Map.of("value", truncateStr(statusText, 5))); // 状态描述
|
||||
data.put("character_string2", Map.of("value", String.valueOf(order.getId()))); // 订单编号
|
||||
data.put("time3", Map.of("value", formatTime(null))); // 通知时间
|
||||
|
||||
// 发送订阅消息
|
||||
return sendSubscribeMessage(accessToken, riderOpenId, data);
|
||||
} catch (Exception e) {
|
||||
log.error("发送订单状态变更订阅消息失败 - orderId={}, riderOpenId={}, error={}",
|
||||
order.getId(), riderOpenId, e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小程序的 access_token
|
||||
*/
|
||||
private String getAccessToken(Integer tenantId) {
|
||||
if (tenantId == null) {
|
||||
throw new BusinessException("tenantId 不能为空");
|
||||
}
|
||||
|
||||
final String tokenCacheKey = ACCESS_TOKEN_KEY + ":" + tenantId;
|
||||
|
||||
// 1) 优先从缓存取
|
||||
String cachedValue = stringRedisTemplate.opsForValue().get(tokenCacheKey);
|
||||
if (StrUtil.isNotBlank(cachedValue)) {
|
||||
try {
|
||||
JSONObject cachedJson = JSON.parseObject(cachedValue);
|
||||
String accessToken = cachedJson.getString("access_token");
|
||||
if (StrUtil.isNotBlank(accessToken)) {
|
||||
return accessToken;
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// 旧格式:直接存 token
|
||||
return cachedValue;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 缓存没有则从租户配置获取 appId/appSecret
|
||||
final String wxConfigKey = MP_WX_KEY + tenantId;
|
||||
final String wxConfigValue = stringRedisTemplate.opsForValue().get(wxConfigKey);
|
||||
if (StrUtil.isBlank(wxConfigValue)) {
|
||||
log.warn("未找到微信小程序配置,请检查缓存key: {}", wxConfigKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject wxConfig;
|
||||
try {
|
||||
wxConfig = JSON.parseObject(wxConfigValue);
|
||||
} catch (Exception e) {
|
||||
log.error("微信小程序配置格式错误: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
final String appId = wxConfig.getString("appId");
|
||||
final String appSecret = wxConfig.getString("appSecret");
|
||||
if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) {
|
||||
log.error("微信小程序配置不完整(appId/appSecret)");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3) 调用微信接口获取 token
|
||||
final String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
|
||||
+ "&appid=" + appId + "&secret=" + appSecret;
|
||||
String result = HttpUtil.get(apiUrl);
|
||||
|
||||
JSONObject json = JSON.parseObject(result);
|
||||
if (json.containsKey("errcode") && json.getIntValue("errcode") != 0) {
|
||||
log.error("获取小程序access_token失败: {}", json.getString("errmsg"));
|
||||
return null;
|
||||
}
|
||||
|
||||
String accessToken = json.getString("access_token");
|
||||
Integer expiresIn = json.getInteger("expires_in");
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
log.error("获取小程序access_token失败: access_token为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4) 缓存,提前5分钟过期
|
||||
long ttlSeconds = 7000L;
|
||||
if (expiresIn != null && expiresIn > 300) {
|
||||
ttlSeconds = expiresIn - 300L;
|
||||
}
|
||||
stringRedisTemplate.opsForValue().set(tokenCacheKey, result, ttlSeconds, java.util.concurrent.TimeUnit.SECONDS);
|
||||
|
||||
log.info("获取小程序access_token成功 - tenantId={}, ttlSeconds={}", tenantId, ttlSeconds);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送订阅消息
|
||||
*/
|
||||
private boolean sendSubscribeMessage(String accessToken, String openId, Map<String, Object> data) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("touser", openId); // 用户 openid
|
||||
params.put("template_id", SUBSCRIBE_TEMPLATE_ID); // 模板ID
|
||||
params.put("page", "pages/rider/orders/index"); // 点击后跳转的页面
|
||||
params.put("data", data);
|
||||
|
||||
String response = HttpUtil.createPost(url)
|
||||
.contentType("application/json")
|
||||
.body(JSON.toJSONString(params))
|
||||
.timeout(10000)
|
||||
.execute()
|
||||
.body();
|
||||
|
||||
JSONObject result = JSON.parseObject(response);
|
||||
int errcode = result.getIntValue("errcode");
|
||||
|
||||
if (errcode == 0) {
|
||||
log.info("订阅消息发送成功 - openId={}", openId);
|
||||
return true;
|
||||
} else {
|
||||
log.warn("订阅消息发送失败 - openId={}, errcode={}, errmsg={}",
|
||||
openId, errcode, result.getString("errmsg"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 截断字符串
|
||||
*/
|
||||
private String truncateStr(String str, int maxLen) {
|
||||
if (str == null) return "";
|
||||
return str.length() > maxLen ? str.substring(0, maxLen) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间
|
||||
*/
|
||||
private String formatTime(String timeStr) {
|
||||
if (StrUtil.isBlank(timeStr)) {
|
||||
return cn.hutool.core.date.DateUtil.now();
|
||||
}
|
||||
return timeStr;
|
||||
}
|
||||
}
|
||||
@@ -888,7 +888,8 @@ public class ShopOrderController extends BaseController {
|
||||
logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}",
|
||||
transaction.getTradeStateDesc(), transaction.getOutTradeNo());
|
||||
|
||||
if (StrUtil.equals("支付成功", transaction.getTradeStateDesc())) {
|
||||
// 使用枚举值判断支付状态,避免依赖状态描述字符串
|
||||
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
|
||||
final String outTradeNo = transaction.getOutTradeNo();
|
||||
final String transactionId = transaction.getTransactionId();
|
||||
final Integer total = transaction.getAmount().getTotal();
|
||||
|
||||
@@ -116,4 +116,7 @@ public class ShopDealerUser implements Serializable {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@Schema(description = "分销商等级:0-普通用户 1-超级管理员 2-合伙人(总店) 3-合伙人(分店)")
|
||||
private Integer dealerLevel;
|
||||
|
||||
}
|
||||
|
||||
@@ -153,6 +153,12 @@ public class ShopGoods implements Serializable {
|
||||
@Schema(description = "状态, 0上架 1待上架 2待审核 3审核不通过")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "活动方式: 0全平台 1新用户专享")
|
||||
private Integer activityType;
|
||||
|
||||
@Schema(description = "配送方式: 0送上门 1限自提")
|
||||
private Integer deliveryMode;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String comments;
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
<if test="param.sortNumber != null">
|
||||
AND a.sort_number = #{param.sortNumber}
|
||||
</if>
|
||||
<if test="param.dealerLevel != null">
|
||||
AND a.dealer_level = #{param.dealerLevel}
|
||||
</if>
|
||||
<if test="param.keywords != null">
|
||||
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||
OR a.user_id = #{param.keywords} OR a.dealer_name LIKE CONCAT('%', #{param.keywords}, '%') OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') OR a.mobile LIKE CONCAT('%', #{param.keywords}, '%')
|
||||
|
||||
@@ -135,6 +135,12 @@
|
||||
OR a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||
)
|
||||
</if>
|
||||
<if test="param.activityType != null">
|
||||
AND a.activity_type = #{param.activityType}
|
||||
</if>
|
||||
<if test="param.deliveryMode != null">
|
||||
AND a.delivery_mode = #{param.deliveryMode}
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
|
||||
@@ -86,4 +86,8 @@ public class ShopDealerUserParam extends BaseParam {
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer isDelete;
|
||||
|
||||
@Schema(description = "分销商等级:0-普通用户 1-超级管理员 2-合伙人(总店) 3-合伙人(分店)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer dealerLevel;
|
||||
|
||||
}
|
||||
|
||||
@@ -150,4 +150,12 @@ public class ShopGoodsParam extends BaseParam {
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer deleted;
|
||||
|
||||
@Schema(description = "活动方式: 0全平台 1新用户专享")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer activityType;
|
||||
|
||||
@Schema(description = "配送方式: 0送上门 1限自提")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer deliveryMode;
|
||||
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@ server:
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://47.107.249.41:13306/gltdb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
|
||||
username: gltdb
|
||||
password: EeD4FtzyA5ksj7Bk
|
||||
url: jdbc:mysql://8.134.55.105:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
|
||||
username: modules
|
||||
password: tYmmMGh5wpwXR3ae
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
|
||||
# redis
|
||||
redis:
|
||||
database: 0
|
||||
host: 47.107.249.41
|
||||
host: 8.134.55.105
|
||||
port: 16379
|
||||
password: redis_t74P8C
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://1Panel-mysql-XsWW:3306/gltdb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: gltdb
|
||||
password: EeD4FtzyA5ksj7Bk
|
||||
url: jdbc:mysql://1Panel-mysql-XsWW:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: modules
|
||||
password: tYmmMGh5wpwXR3ae
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
druid:
|
||||
|
||||
@@ -7,7 +7,7 @@ server:
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://47.107.249.41:13306/gltdb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://1Panel-mysql-XsWW:3306/gltdb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: gltdb
|
||||
password: EeD4FtzyA5ksj7Bk
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
@@ -16,8 +16,8 @@ spring:
|
||||
# redis
|
||||
redis:
|
||||
database: 0
|
||||
host: 8.134.55.105
|
||||
port: 16379
|
||||
host: 1Panel-redis-GmNr
|
||||
port: 6379
|
||||
password: redis_t74P8C
|
||||
|
||||
# 日志配置
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://1Panel-mysql-Bqdt:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://1Panel-mysql-XsWW:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: modules
|
||||
password: P7KsAyDXG8YdLnkA
|
||||
password: tYmmMGh5wpwXR3ae
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
druid:
|
||||
@@ -14,9 +14,9 @@ spring:
|
||||
# redis
|
||||
redis:
|
||||
database: 0
|
||||
host: 1Panel-redis-Q1LE
|
||||
host: 1Panel-redis-GmNr
|
||||
port: 6379
|
||||
password: redis_WSDb88
|
||||
password: redis_t74P8C
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
|
||||
@@ -4,7 +4,7 @@ server:
|
||||
# 多环境配置
|
||||
spring:
|
||||
profiles:
|
||||
active: glt2
|
||||
active: dev
|
||||
|
||||
application:
|
||||
name: server
|
||||
|
||||
Reference in New Issue
Block a user