diff --git a/src/main/java/com/rj/entity/LbFanManagement.java b/src/main/java/com/rj/entity/LbFanManagement.java index bd1a29e..f7268f9 100644 --- a/src/main/java/com/rj/entity/LbFanManagement.java +++ b/src/main/java/com/rj/entity/LbFanManagement.java @@ -11,6 +11,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; +import java.math.BigDecimal; import java.time.LocalDateTime; /** @@ -68,6 +69,18 @@ public class LbFanManagement implements Serializable { @Schema(description = "登录 token") private String token; + @TableField("coupon") + @Schema(description = "优惠券金额") + private BigDecimal coupon; + + @TableField("self_bonus") + @Schema(description = "自购奖金") + private BigDecimal selfBonus; + + @TableField("share_bonus") + @Schema(description = "分享奖金") + private BigDecimal shareBonus; + @TableField("created_at") @Schema(description = "创建时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") diff --git a/src/main/java/com/rj/service/HxrAdminBuyService.java b/src/main/java/com/rj/service/HxrAdminBuyService.java index 73fbf6e..8206cd6 100644 --- a/src/main/java/com/rj/service/HxrAdminBuyService.java +++ b/src/main/java/com/rj/service/HxrAdminBuyService.java @@ -37,6 +37,9 @@ public class HxrAdminBuyService { /** 与 hxrd 前端 DevTools 一致,使用 {@code Token} 而非小写 {@code token}。 */ private static final String HEADER_TOKEN = "Token"; + /** 外部系统返回此文案时表示该账号当日可抢订单数已满,应停止继续抢购。 */ + public static final String MSG_DAILY_LIMIT_EXCEEDED = "已超出当天可抢订单数"; + private static final ObjectMapper JSON = new ObjectMapper() .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); @@ -148,6 +151,10 @@ public class HxrAdminBuyService { log.warn("hxr /api/order/buy 鉴权失败常见原因:Token 与浏览器不一致或已过期、goodsApiAppStr 错误;" + "请在 rush-buy 请求体传入浏览器 DevTools 中 Token 头的值,并核对 lb_third_integration_config.goods_api_token / goods_api_app_str"); } + if (MSG_DAILY_LIMIT_EXCEEDED.equals(msg)) { + log.warn("hxr /api/order/buy 当日可抢订单数已满,停止该账号继续抢购 id={} sellerId={} tokenPrefix={}", + goodsId, sellerId, abbreviate(resolvedToken, 8)); + } } return new BuyApiResult(code == 0, code, msg); } @@ -169,6 +176,11 @@ public class HxrAdminBuyService { public static BuyApiResult failure(int code, String msg) { return new BuyApiResult(false, code, msg); } + + /** {@code code=1} 且 msg 为「已超出当天可抢订单数」时,调用方应停止该账号后续抢购。 */ + public boolean dailyLimitExceeded() { + return apiCode == 1 && MSG_DAILY_LIMIT_EXCEEDED.equals(apiMsg); + } } private static String randomNoncestr() { diff --git a/src/main/java/com/rj/service/HxrAdminUserLoginService.java b/src/main/java/com/rj/service/HxrAdminUserLoginService.java index cdc7522..c48d990 100644 --- a/src/main/java/com/rj/service/HxrAdminUserLoginService.java +++ b/src/main/java/com/rj/service/HxrAdminUserLoginService.java @@ -59,7 +59,7 @@ public class HxrAdminUserLoginService { String noncestr = randomNoncestr(); Map body = new LinkedHashMap<>(); - body.put("mobile", mobile.trim()); + body.put("account", mobile.trim()); body.put("password", password.trim()); String bodyJson = JSON.writeValueAsString(body); @@ -76,7 +76,7 @@ public class HxrAdminUserLoginService { String appStr = ctx.appStr(); if (StringUtils.hasText(appStr)) { Map signParams = new LinkedHashMap<>(); - signParams.put("mobile", mobile.trim()); + signParams.put("account", mobile.trim()); signParams.put("password", password.trim()); signParams.put("timestamp", timestamp); signParams.put("noncestr", noncestr); diff --git a/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java b/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java index c1642d3..bc1357b 100644 --- a/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java +++ b/src/main/java/com/rj/service/ILbThirdIntegrationConfigService.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest; import com.rj.dto.hxr.HxrAdminOrderApiContext; import com.rj.dto.hxr.HxrAdminUserApiContext; +import com.rj.dto.hxr.HxrFansApiContext; import com.rj.dto.hxr.HxrGoodsApiContext; import com.rj.dto.hxr.HxrUserLoginApiContext; import com.rj.entity.LbThirdIntegrationConfig; @@ -60,4 +61,10 @@ public interface ILbThirdIntegrationConfigService extends IService resolveUserLoginApiContext(String tenantId); + + /** + * 按租户 id 解析粉丝列表 API 运行时配置(fans_api_path、fans_page_limit、Origin、Referer、appStr); + * {@code token} 为登录用户 token,必填。 + */ + Optional resolveFansApiContext(String tenantId, String token); } diff --git a/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java b/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java index 9ed7772..f42a64c 100644 --- a/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbFanManagementServiceImpl.java @@ -4,9 +4,13 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.rj.dto.LbFanSimulateLoginRequest; +import com.rj.dto.hxr.HxrFansApiContext; +import com.rj.dto.hxr.HxrLbFansPageData; +import com.rj.dto.hxr.HxrLbFansSelectResponse; import com.rj.dto.hxr.HxrUserLoginApiContext; import com.rj.entity.LbFanManagement; import com.rj.mapper.LbFanManagementMapper; +import com.rj.service.HxrAdminFansService; import com.rj.service.HxrAdminUserLoginService; import com.rj.service.ILbFanManagementService; import com.rj.service.ILbThirdIntegrationConfigService; @@ -16,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; +import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -40,6 +45,9 @@ public class LbFanManagementServiceImpl @Autowired private HxrAdminUserLoginService hxrAdminUserLoginService; + @Autowired + private HxrAdminFansService hxrAdminFansService; + private static final String DEFAULT_SIMULATE_LOGIN_PASSWORD = "123456"; private static final DateTimeFormatter DATE_TIME_FORMATTER = @@ -67,6 +75,15 @@ public class LbFanManagementServiceImpl if (entity.getShareNum() == null) { entity.setShareNum(0); } + if (entity.getCoupon() == null) { + entity.setCoupon(BigDecimal.ZERO); + } + if (entity.getSelfBonus() == null) { + entity.setSelfBonus(BigDecimal.ZERO); + } + if (entity.getShareBonus() == null) { + entity.setShareBonus(BigDecimal.ZERO); + } if (entity.getCreatedAt() == null) { entity.setCreatedAt(LocalDateTime.now()); } @@ -288,6 +305,18 @@ public class LbFanManagementServiceImpl item.put("parsed", loginResult.parsed()); if (loginResult.success()) { successCount++; + Map userinfo = extractUserinfo(loginResult.parsed()); + if (userinfo != null) { + Map saveResult = + saveFanFromLoginUserinfo(userinfo, tenantId); + item.putAll(saveResult); + if (Boolean.TRUE.equals(saveResult.get("saved"))) { + item.putAll(fetchAndSaveFansFromThirdParty(userinfo, tenantId)); + } + } else { + item.put("saved", false); + item.put("saveMsg", "响应中无 data.userinfo"); + } } else { failCount++; } @@ -408,4 +437,350 @@ public class LbFanManagementServiceImpl return null; } } + + @SuppressWarnings("unchecked") + private static Map extractUserinfo(Object parsed) { + if (!(parsed instanceof Map root)) { + return null; + } + Object dataObj = root.get("data"); + if (!(dataObj instanceof Map data)) { + return null; + } + Object userinfoObj = data.get("userinfo"); + if (!(userinfoObj instanceof Map)) { + return null; + } + return (Map) userinfoObj; + } + + private Map saveFanFromLoginUserinfo(Map userinfo, String tenantId) { + Map saveResult = new LinkedHashMap<>(); + Long fanId = parseLong(userinfo.get("id")); + if (fanId == null) { + saveResult.put("saved", false); + saveResult.put("saveMsg", "userinfo.id 为空"); + return saveResult; + } + + LbFanManagement entity = new LbFanManagement(); + entity.setTenantId(tenantId); + entity.setId(fanId); + entity.setIdTenantId(buildIdTenantId(fanId, tenantId)); + entity.setAvatar(parseString(userinfo.get("avatar"))); + entity.setNickname(parseString(userinfo.get("nickname"))); + entity.setMobile(parseString(userinfo.get("mobile"))); + entity.setToken(parseString(userinfo.get("token"))); + entity.setCoupon(parseDecimal(userinfo.get("coupon"))); + entity.setSelfBonus(parseDecimal(userinfo.get("self_bonus"))); + entity.setShareBonus(parseDecimal(userinfo.get("share_bonus"))); + trimStringFields(entity); + + LbFanManagement existing = this.getById(entity.getIdTenantId()); + if (existing != null) { + entity.setCreatedAt(existing.getCreatedAt()); + entity.setShareNum(existing.getShareNum()); + entity.setPName(existing.getPName()); + entity.setPid(existing.getPid()); + entity.setPPhone(existing.getPPhone()); + if (entity.getCoupon() == null) { + entity.setCoupon(existing.getCoupon()); + } + if (entity.getSelfBonus() == null) { + entity.setSelfBonus(existing.getSelfBonus()); + } + if (entity.getShareBonus() == null) { + entity.setShareBonus(existing.getShareBonus()); + } + boolean ok = this.updateById(entity); + saveResult.put("saved", ok); + saveResult.put("saveMsg", ok ? "已更新" : "更新失败"); + if (ok) { + saveResult.put("fan", this.getById(entity.getIdTenantId())); + } + return saveResult; + } + + if (entity.getShareNum() == null) { + entity.setShareNum(0); + } + if (entity.getCoupon() == null) { + entity.setCoupon(BigDecimal.ZERO); + } + if (entity.getSelfBonus() == null) { + entity.setSelfBonus(BigDecimal.ZERO); + } + if (entity.getShareBonus() == null) { + entity.setShareBonus(BigDecimal.ZERO); + } + entity.setCreatedAt(LocalDateTime.now()); + try { + boolean ok = this.save(entity); + saveResult.put("saved", ok); + saveResult.put("saveMsg", ok ? "已新增" : "新增失败"); + if (ok) { + saveResult.put("fan", entity); + } + } catch (DuplicateKeyException e) { + log.warn("粉丝模拟登录入库重复键, idTenantId={}", entity.getIdTenantId()); + saveResult.put("saved", false); + saveResult.put("saveMsg", "唯一ID已存在:" + entity.getIdTenantId()); + } + return saveResult; + } + + /** + * 登录用户保存成功后,分页调用第三方粉丝列表 API 并入库。 + */ + private Map fetchAndSaveFansFromThirdParty(Map parentUserinfo, + String tenantId) { + Map result = new LinkedHashMap<>(); + String token = parseString(parentUserinfo.get("token")); + if (token == null) { + result.put("fansFetchSuccess", false); + result.put("fansFetchMsg", "userinfo.token 为空,无法拉取粉丝"); + result.put("fansSaved", 0); + return result; + } + + Optional ctxOpt = + lbThirdIntegrationConfigService.resolveFansApiContext(tenantId, token); + if (ctxOpt.isEmpty()) { + result.put("fansFetchSuccess", false); + result.put("fansFetchMsg", + "未找到粉丝 API 配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)"); + result.put("fansSaved", 0); + return result; + } + HxrFansApiContext ctx = ctxOpt.get(); + + Long parentId = parseLong(parentUserinfo.get("id")); + String parentName = parseString(parentUserinfo.get("nickname")); + String parentPhone = parseString(parentUserinfo.get("mobile")); + + int page = 1; + int totalSaved = 0; + int totalFetched = 0; + HxrLbFansPageData firstPageData = null; + try { + while (true) { + Optional opt = + hxrAdminFansService.fetchFansPage(page, ctx); + if (opt.isEmpty()) { + if (page == 1) { + result.put("fansFetchSuccess", false); + result.put("fansFetchMsg", + "未拉取到粉丝(请检查 lb_third_integration_config 中 token、appStr、URL 或网络)"); + result.put("fansSaved", 0); + result.put("fansApiUrl", ctx.fansApiBaseUrl()); + return result; + } + result.put("fansFetchSuccess", false); + result.put("fansFetchMsg", "第 " + page + " 页拉取失败,已成功保存前 " + + (page - 1) + " 页共 " + totalSaved + " 条粉丝"); + result.put("fansSaved", totalSaved); + result.put("fansFetched", totalFetched); + if (firstPageData != null) { + result.put("lastPage", firstPageData.lastPage()); + } + result.put("fansPages", page - 1); + result.put("fansApiUrl", ctx.fansApiBaseUrl()); + return result; + } + + HxrLbFansSelectResponse body = opt.get(); + HxrLbFansPageData pageData = body.data(); + if (firstPageData == null && pageData != null) { + firstPageData = pageData; + } + List> rows = pageData != null ? pageData.list() : null; + if (rows == null || rows.isEmpty()) { + break; + } + totalFetched += rows.size(); + + for (Map row : rows) { + Map rowSave = saveFanFromShareRow( + row, tenantId, parentId, parentName, parentPhone); + if (Boolean.TRUE.equals(rowSave.get("saved"))) { + totalSaved++; + } + } + + boolean hasMore = pageData != null && pageData.hasmore(); + int lastPage = pageData != null ? pageData.lastPage() : page; + if (!hasMore || page >= lastPage) { + break; + } + page++; + } + + result.put("fansFetchSuccess", true); + result.put("fansFetchMsg", totalSaved == 0 ? "接口成功,无粉丝数据" : "粉丝拉取完成"); + result.put("fansSaved", totalSaved); + result.put("fansFetched", totalFetched); + result.put("lastPage", firstPageData != null ? firstPageData.lastPage() : page); + result.put("fansPages", page); + result.put("fansApiUrl", ctx.fansApiBaseUrl()); + return result; + } catch (Exception e) { + log.warn("拉取粉丝异常 tenantId={} parentId={}", tenantId, parentId, e); + result.put("fansFetchSuccess", false); + result.put("fansFetchMsg", "拉取粉丝异常:" + e.getMessage()); + result.put("fansSaved", totalSaved); + result.put("fansFetched", totalFetched); + if (firstPageData != null) { + result.put("lastPage", firstPageData.lastPage()); + } + result.put("fansPages", page > 1 ? page - 1 : 0); + result.put("fansApiUrl", ctx.fansApiBaseUrl()); + return result; + } + } + + private Map saveFanFromShareRow(Map row, + String tenantId, + Long parentId, + String parentName, + String parentPhone) { + Map saveResult = new LinkedHashMap<>(); + Long fanId = parseLong(row.get("id")); + if (fanId == null) { + saveResult.put("saved", false); + saveResult.put("saveMsg", "粉丝 id 为空"); + return saveResult; + } + + LbFanManagement entity = new LbFanManagement(); + entity.setTenantId(tenantId); + entity.setId(fanId); + entity.setIdTenantId(buildIdTenantId(fanId, tenantId)); + entity.setAvatar(parseString(row.get("avatar"))); + entity.setNickname(parseString(row.get("nickname"))); + entity.setMobile(parseString(row.get("mobile"))); + entity.setPid(parentId); + entity.setPName(parentName); + entity.setPPhone(parentPhone); + entity.setCoupon(parseDecimal(row.get("coupon"))); + entity.setSelfBonus(parseDecimal(row.get("self_bonus"))); + entity.setShareBonus(parseDecimal(row.get("share_bonus"))); + Integer shareNum = parseInteger(row.get("share_num")); + if (shareNum != null) { + entity.setShareNum(shareNum); + } + trimStringFields(entity); + + LbFanManagement existing = this.getById(entity.getIdTenantId()); + if (existing != null) { + entity.setCreatedAt(existing.getCreatedAt()); + if (entity.getShareNum() == null) { + entity.setShareNum(existing.getShareNum()); + } + if (entity.getCoupon() == null) { + entity.setCoupon(existing.getCoupon()); + } + if (entity.getSelfBonus() == null) { + entity.setSelfBonus(existing.getSelfBonus()); + } + if (entity.getShareBonus() == null) { + entity.setShareBonus(existing.getShareBonus()); + } + if (entity.getToken() == null) { + entity.setToken(existing.getToken()); + } + boolean ok = this.updateById(entity); + saveResult.put("saved", ok); + saveResult.put("saveMsg", ok ? "已更新" : "更新失败"); + return saveResult; + } + + if (entity.getShareNum() == null) { + entity.setShareNum(0); + } + if (entity.getCoupon() == null) { + entity.setCoupon(BigDecimal.ZERO); + } + if (entity.getSelfBonus() == null) { + entity.setSelfBonus(BigDecimal.ZERO); + } + if (entity.getShareBonus() == null) { + entity.setShareBonus(BigDecimal.ZERO); + } + entity.setCreatedAt(LocalDateTime.now()); + try { + boolean ok = this.save(entity); + saveResult.put("saved", ok); + saveResult.put("saveMsg", ok ? "已新增" : "新增失败"); + } catch (DuplicateKeyException e) { + log.warn("粉丝拉取入库重复键, idTenantId={}", entity.getIdTenantId()); + saveResult.put("saved", false); + saveResult.put("saveMsg", "唯一ID已存在:" + entity.getIdTenantId()); + } + return saveResult; + } + + private static Integer parseInteger(Object value) { + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.intValue(); + } + String text = value.toString().trim(); + if (text.isEmpty()) { + return null; + } + try { + return Integer.parseInt(text); + } catch (NumberFormatException e) { + return null; + } + } + + private static Long parseLong(Object value) { + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.longValue(); + } + String text = value.toString().trim(); + if (text.isEmpty()) { + return null; + } + try { + return Long.parseLong(text); + } catch (NumberFormatException e) { + return null; + } + } + + private static String parseString(Object value) { + if (value == null) { + return null; + } + String text = value.toString().trim(); + return text.isEmpty() ? null : text; + } + + private static BigDecimal parseDecimal(Object value) { + if (value == null) { + return null; + } + if (value instanceof BigDecimal decimal) { + return decimal; + } + if (value instanceof Number number) { + return BigDecimal.valueOf(number.doubleValue()); + } + String text = value.toString().trim(); + if (text.isEmpty()) { + return null; + } + try { + return new BigDecimal(text); + } catch (NumberFormatException e) { + return null; + } + } } diff --git a/src/main/java/com/rj/service/impl/LbGoodsServiceImpl.java b/src/main/java/com/rj/service/impl/LbGoodsServiceImpl.java index 6d9a89a..084b3bb 100644 --- a/src/main/java/com/rj/service/impl/LbGoodsServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbGoodsServiceImpl.java @@ -34,7 +34,7 @@ import java.util.Optional; @RequiredArgsConstructor public class LbGoodsServiceImpl extends ServiceImpl implements ILbGoodsService { - private static final BigDecimal RUSH_BUY_MIN_TOTAL_MONEY = new BigDecimal("26000"); + private static final BigDecimal RUSH_BUY_MIN_TOTAL_MONEY = new BigDecimal("25000"); private static final DateTimeFormatter DATETIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @@ -569,6 +569,7 @@ public class LbGoodsServiceImpl extends ServiceImpl impl int attemptCount = 0; boolean stoppedByMax = false; boolean stoppedByMaxAttempts = false; + boolean stoppedByDailyLimit = false; for (LbGoods goods : goodsList) { if (successCount >= maxBuyCount) { @@ -605,19 +606,35 @@ public class LbGoodsServiceImpl extends ServiceImpl impl successCount++; } else { failCount++; + if (buyResult.dailyLimitExceeded()) { + stoppedByDailyLimit = true; + if (accountTag.isEmpty()) { + log.info("当日可抢订单数已满,停止继续抢购"); + } else { + log.info("{} 当日可抢订单数已满,停止继续抢购", accountTag); + } + break; + } } } result.put("success", successCount > 0); - result.put("message", successCount > 0 - ? "抢购完成,成功 " + successCount + " 笔,失败 " + failCount + " 笔" - : "抢购未成功"); + if (stoppedByDailyLimit) { + result.put("message", successCount > 0 + ? "当日可抢订单数已满,已停止抢购;成功 " + successCount + " 笔,失败 " + failCount + " 笔" + : HxrAdminBuyService.MSG_DAILY_LIMIT_EXCEEDED); + } else { + result.put("message", successCount > 0 + ? "抢购完成,成功 " + successCount + " 笔,失败 " + failCount + " 笔" + : "抢购未成功"); + } result.put("successCount", successCount); result.put("failCount", failCount); result.put("attemptCount", attemptCount); result.put("maxAttempts", maxAttempts); result.put("stoppedByMax", stoppedByMax); result.put("stoppedByMaxAttempts", stoppedByMaxAttempts); + result.put("stoppedByDailyLimit", stoppedByDailyLimit); result.put("details", details); if (accountTag.isEmpty()) { log.info("抢购结束,success={},message={}", successCount > 0, result.get("message")); diff --git a/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java b/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java index 7c0ffd8..ae5b50c 100644 --- a/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java +++ b/src/main/java/com/rj/service/impl/LbThirdIntegrationConfigServiceImpl.java @@ -8,6 +8,7 @@ import com.rj.common.LbThirdIntegrationConstants; import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest; import com.rj.dto.hxr.HxrAdminOrderApiContext; import com.rj.dto.hxr.HxrAdminUserApiContext; +import com.rj.dto.hxr.HxrFansApiContext; import com.rj.dto.hxr.HxrGoodsApiContext; import com.rj.dto.hxr.HxrUserLoginApiContext; import com.rj.entity.LbThirdIntegrationConfig; @@ -397,6 +398,37 @@ public class LbThirdIntegrationConfigServiceImpl } } + @Override + public Optional resolveFansApiContext(String tenantId, String token) { + if (!StringUtils.hasText(tenantId) || !StringUtils.hasText(token)) { + return Optional.empty(); + } + LbThirdIntegrationConfig config = getByTenantIdOrNull(tenantId.trim()); + if (config == null) { + return Optional.empty(); + } + if (config.getEnabled() == null || config.getEnabled() != 1) { + return Optional.empty(); + } + + String appStr = config.getGoodsApiAppStr(); + if (!StringUtils.hasText(appStr)) { + return Optional.empty(); + } + + try { + return Optional.of(new HxrFansApiContext( + LbThirdIntegrationConfigUtil.resolveFansApiBaseUrl(config), + LbThirdIntegrationConfigUtil.resolveFansPageLimit(config), + LbThirdIntegrationConfigUtil.resolveGoodsApiOrigin(config), + LbThirdIntegrationConfigUtil.resolveGoodsApiReferer(config), + token.trim(), + appStr.trim())); + } catch (IllegalStateException e) { + return Optional.empty(); + } + } + @Override public Optional resolveAdminOrderApiContext(String tenantId) { if (!StringUtils.hasText(tenantId)) { diff --git a/src/main/sql/lb_fan_management.sql b/src/main/sql/lb_fan_management.sql index 82e5f23..61dd484 100644 --- a/src/main/sql/lb_fan_management.sql +++ b/src/main/sql/lb_fan_management.sql @@ -13,6 +13,9 @@ CREATE TABLE `lb_fan_management` ( `pid` BIGINT NULL DEFAULT NULL COMMENT '父ID', `p_phone` VARCHAR(32) NULL DEFAULT NULL COMMENT '父手机号', `token` VARCHAR(512) NULL DEFAULT NULL COMMENT '登录 token', + `coupon` DECIMAL(12,3) NOT NULL DEFAULT 0.000 COMMENT '优惠券金额', + `self_bonus` DECIMAL(12,3) NOT NULL DEFAULT 0.000 COMMENT '自购奖金', + `share_bonus` DECIMAL(12,3) NOT NULL DEFAULT 0.000 COMMENT '分享奖金', `created_at` DATETIME NULL DEFAULT NULL COMMENT '创建时间', `share_num` INT NOT NULL DEFAULT 0 COMMENT '分享次数', PRIMARY KEY (`id_tenant_id`) USING BTREE,