diff --git a/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java b/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java new file mode 100644 index 0000000..3a3a44b --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service; + +/** + * 微信小程序 access_token 获取服务(按租户)。 + * + *

用于调用微信小程序开放接口(例如:上传发货信息)。

+ */ +public interface WxMiniappAccessTokenService { + + /** + * 获取指定租户的小程序 access_token(内部带缓存)。 + * + * @param tenantId 租户ID + * @return access_token + */ + String getAccessToken(Integer tenantId); +} + diff --git a/src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java b/src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java new file mode 100644 index 0000000..b6dbe7a --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/system/service/impl/WxMiniappAccessTokenServiceImpl.java @@ -0,0 +1,108 @@ +package com.gxwebsoft.common.system.service.impl; + +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.common.system.service.WxMiniappAccessTokenService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +import static com.gxwebsoft.common.core.constants.RedisConstants.ACCESS_TOKEN_KEY; +import static com.gxwebsoft.common.core.constants.RedisConstants.MP_WX_KEY; + +/** + * 微信小程序 access_token 获取实现(按租户)。 + * + *

复用现有缓存结构: + *

+ *

+ */ +@Slf4j +@Service +public class WxMiniappAccessTokenServiceImpl implements WxMiniappAccessTokenService { + + @Resource + private RedisUtil redisUtil; + + @Override + public String getAccessToken(Integer tenantId) { + if (tenantId == null) { + throw new BusinessException("tenantId 不能为空"); + } + + final String tokenCacheKey = ACCESS_TOKEN_KEY + ":" + tenantId; + + // 1) 优先从缓存取(兼容 JSON 或纯字符串 token 的历史格式) + String cachedValue = redisUtil.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 = redisUtil.get(wxConfigKey); + if (StrUtil.isBlank(wxConfigValue)) { + throw new BusinessException("未找到微信小程序配置,请检查缓存key: " + wxConfigKey); + } + + JSONObject wxConfig; + try { + wxConfig = JSON.parseObject(wxConfigValue); + } catch (Exception e) { + throw new BusinessException("微信小程序配置格式错误: " + e.getMessage()); + } + + final String appId = wxConfig.getString("appId"); + final String appSecret = wxConfig.getString("appSecret"); + if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) { + throw new BusinessException("微信小程序配置不完整(appId/appSecret)"); + } + + // 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) { + Integer errcode = json.getInteger("errcode"); + String errmsg = json.getString("errmsg"); + throw new BusinessException("获取小程序access_token失败: " + errmsg + " (errcode: " + errcode + ")"); + } + + String accessToken = json.getString("access_token"); + Integer expiresIn = json.getInteger("expires_in"); + if (StrUtil.isBlank(accessToken)) { + throw new BusinessException("获取小程序access_token失败: access_token为空"); + } + + // 4) 缓存微信原始 JSON(与现有实现保持一致),提前5分钟过期 + long ttlSeconds = 7000L; + if (expiresIn != null && expiresIn > 300) { + ttlSeconds = expiresIn - 300L; + } + redisUtil.set(tokenCacheKey, result, ttlSeconds, TimeUnit.SECONDS); + + log.info("获取小程序access_token成功 - tenantId={}, ttlSeconds={}", tenantId, ttlSeconds); + return accessToken; + } +} + diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java b/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java index 32be34d..e7a8a77 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java @@ -1,19 +1,18 @@ package com.gxwebsoft.shop.entity; -import java.math.BigDecimal; - import cn.afterturn.easypoi.excel.annotation.Excel; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; -import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonFormat; -import java.io.Serializable; - 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; + /** * 分销商订单记录表 * @@ -120,9 +119,15 @@ public class ShopDealerOrder implements Serializable { @Schema(description = "佣金结算(0未结算 1已结算)") private Integer isSettled; + @Schema(description = "佣金冻结(1解冻中 0已解冻)") + private Integer isUnfreeze; + @Schema(description = "结算时间") private LocalDateTime settleTime; + @Schema(description = "解冻时间") + private LocalDateTime unfreezeTime; + @Schema(description = "备注") private String comments; diff --git a/src/main/resources/application-glt.yml b/src/main/resources/application-glt.yml index ca0f52c..8e5af90 100644 --- a/src/main/resources/application-glt.yml +++ b/src/main/resources/application-glt.yml @@ -32,7 +32,7 @@ socketio: # MQTT配置 mqtt: - enabled: true # 启用MQTT服务 + enabled: false # 启用MQTT服务 host: tcp://132.232.214.96:1883 username: swdev password: Sw20250523