goods同步

This commit is contained in:
2026-05-30 08:26:47 +08:00
parent 246c5a7080
commit dbf408c51f
20 changed files with 1233 additions and 32 deletions

View File

@@ -0,0 +1,23 @@
package com.rj.common;
/**
* 租户第三方集成配置常量
*/
public final class LbThirdIntegrationConstants {
private LbThirdIntegrationConstants() {
}
public static final String PROVIDER_HXR_ADMIN = "HXR_ADMIN";
public static final String AUTH_COOKIE_PHPSID = "COOKIE_PHPSID";
public static final String DEFAULT_ORDER_SELECT_PATH = "/app/admin/order/select";
public static final String DEFAULT_USER_SELECT_PATH = "/app/admin/user/select";
public static final String DEFAULT_USER_UPDATE_PATH = "/app/admin/user/update";
public static final String DEFAULT_GOODS_API_PATH = "/api/order/goods";
public static final String DEFAULT_BUY_API_PATH = "/api/order/buy";
public static final int DEFAULT_ORDER_PAGE_LIMIT = 90;
public static final int DEFAULT_USER_PAGE_LIMIT = 90;
public static final int DEFAULT_GOODS_PAGE_LIMIT = 20;
}

View File

@@ -60,6 +60,7 @@ public class MybatisPlusConfig {
ignoreTables.add("industry_tags"); // 行业标签(示例:如认为是公共字典)
ignoreTables.add("menu"); // 菜单表(不需要租户隔离)
ignoreTables.add("ai_prompts"); // AI 提示词全局配置,表无 tenant_id 字段
ignoreTables.add("lb_third_integration_config"); // 每租户一条,按 tenant_id 显式查询,不走插件自动拼接
return new TenantLineHandler() {

View File

@@ -136,8 +136,9 @@ public class LbGoodsController {
@Operation(
summary = "抢购货品",
description =
"从 lb_goods 按 total_money 从大到小选取货品,调用 hxrd POST /api/order/buybody: id、seller_id"
+ "成功笔数达到 maxBuyCount 后停止token 可选,未传时使用 hxr.admin.goods-api-token")
"从 lb_goods 按 total_money 从大到小选取金额小于39000的货品,调用 hxrd POST /api/order/buybody: id、seller_id"
+ "成功笔数达到 maxBuyCount 后停止,且循环抢购总次数不超过 maxBuyCount 的5倍"
+ "token 可选,未传时使用 hxr.admin.goods-api-token")
public ResponseEntity<Map<String, Object>> rushBuy(
@Parameter(description = "maxBuyCount 必填token 可选", required = true)
@RequestBody LbGoodsRushBuyRequest request) {

View File

@@ -24,7 +24,9 @@ public class LbOrderRowController {
@PostMapping("/add")
@Operation(summary = "新增")
public ResponseEntity<Map<String, Object>> add(
@Parameter(description = "实体(id 为订单 id需调用方指定", required = true) @RequestBody LbOrderRow entity) {
@Parameter(description = "实体(复合主键 tenantId + id需调用方指定", required = true)
@RequestBody
LbOrderRow entity) {
Map<String, Object> result = lbOrderRowService.add(entity);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
@@ -36,7 +38,7 @@ public class LbOrderRowController {
@PutMapping("/update")
@Operation(summary = "编辑")
public ResponseEntity<Map<String, Object>> update(
@Parameter(description = "实体", required = true) @RequestBody LbOrderRow entity) {
@Parameter(description = "实体(须含 tenantId 与 id", required = true) @RequestBody LbOrderRow entity) {
Map<String, Object> result = lbOrderRowService.update(entity);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
@@ -48,8 +50,11 @@ public class LbOrderRowController {
@DeleteMapping("/delete/{id}")
@Operation(summary = "删除")
public ResponseEntity<Map<String, Object>> delete(
@Parameter(description = "主键(订单 id", required = true) @PathVariable Long id) {
Map<String, Object> result = lbOrderRowService.deleteById(id);
@Parameter(description = "订单 id(复合主键之一", required = true) @PathVariable Long id,
@Parameter(description = "租户 id复合主键之一未传时使用 X-Tenant-Id / Token 租户)")
@RequestParam(required = false)
String tenantId) {
Map<String, Object> result = lbOrderRowService.deleteById(id, tenantId);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
@@ -92,7 +97,7 @@ public class LbOrderRowController {
@PostMapping("/sync-order-from-third")
@Operation(
summary = "从 外部系统 同步订单",
description = "按购买时间区间、租户 id、转卖状态调用后台 order/select将结果写入 lb_order_row按订单 id upsert")
description = "按购买时间区间、租户 id、转卖状态调用后台 order/select将结果写入 lb_order_row tenant_id + 订单 id upsert")
public ResponseEntity<Map<String, Object>> syncFromHxr(
@Parameter(description = "同步条件", required = true) @RequestBody LbOrderRowSyncFromHxrRequest request) {
Map<String, Object> result =

View File

@@ -0,0 +1,138 @@
package com.rj.controller;
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
import com.rj.entity.LbThirdIntegrationConfig;
import com.rj.service.ILbThirdIntegrationConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 租户第三方集成配置控制器
*/
@Slf4j
@RestController
@RequestMapping("/api/lbThirdIntegrationConfig")
@Tag(name = "租户第三方集成配置", description = "lb_third_integration_config 增删改查与分页")
public class LbThirdIntegrationConfigController {
@Autowired
private ILbThirdIntegrationConfigService lbThirdIntegrationConfigService;
@PostMapping("/add")
@Operation(summary = "新增")
public ResponseEntity<Map<String, Object>> add(
@Parameter(description = "配置实体(凭证请传 *Plain 明文字段)", required = true)
@RequestBody LbThirdIntegrationConfig entity) {
Map<String, Object> result = lbThirdIntegrationConfigService.add(entity);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
return ResponseEntity.badRequest().body(result);
}
@PutMapping("/update")
@Operation(summary = "更新")
public ResponseEntity<Map<String, Object>> update(
@Parameter(description = "配置实体(仅传需修改字段;凭证 *Plain 非空时才轮换)", required = true)
@RequestBody LbThirdIntegrationConfig entity) {
Map<String, Object> result = lbThirdIntegrationConfigService.update(entity);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
return ResponseEntity.badRequest().body(result);
}
@DeleteMapping("/delete/{id}")
@Operation(summary = "删除")
public ResponseEntity<Map<String, Object>> delete(
@Parameter(description = "主键ID", required = true) @PathVariable String id) {
Map<String, Object> result = lbThirdIntegrationConfigService.deleteById(id);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
return ResponseEntity.badRequest().body(result);
}
@GetMapping("/list")
@Operation(summary = "分页查询")
public ResponseEntity<Map<String, Object>> list(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String tenantId,
@RequestParam(required = false) String providerCode,
@RequestParam(required = false) Integer enabled) {
Map<String, Object> result = lbThirdIntegrationConfigService.pageQuery(
current, size, tenantId, providerCode, enabled);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
return ResponseEntity.internalServerError().body(result);
}
@GetMapping("/get/{id}")
@Operation(summary = "按ID查询")
public ResponseEntity<Map<String, Object>> getById(
@Parameter(description = "主键ID", required = true) @PathVariable String id) {
Map<String, Object> result = lbThirdIntegrationConfigService.getDetailById(id);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
if ("记录不存在".equals(result.get("message"))) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.badRequest().body(result);
}
@GetMapping("/credential/{tenantId}")
@Operation(
summary = "查询租户凭证(含明文)",
description = "按 tenantId 解密返回 cookie、phpsid、goodsApiToken、goodsApiAppStr 明文,便于管理查看")
public ResponseEntity<Map<String, Object>> getCredentialStatus(
@Parameter(description = "租户 id", required = true) @PathVariable String tenantId) {
Map<String, Object> result = lbThirdIntegrationConfigService.getCredentialStatusByTenantId(tenantId);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
if ("该租户未配置第三方集成".equals(result.get("message"))) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.badRequest().body(result);
}
@PostMapping("/credential/{tenantId}")
@Operation(
summary = "更新租户凭证",
description =
"仅更新 cookie/phpsid/goodsApiToken/goodsApiAppStr 凭证列;"
+ "传明文则加密入库并 credential_version+1"
+ "传 clear* 为 true 则清除对应密文;至少操作一项")
public ResponseEntity<Map<String, Object>> updateCredential(
@Parameter(description = "租户 id", required = true) @PathVariable String tenantId,
@Parameter(description = "凭证更新请求", required = true)
@RequestBody
LbThirdIntegrationCredentialUpdateRequest request) {
Map<String, Object> result =
lbThirdIntegrationConfigService.updateCredentialByTenantId(tenantId, request);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
if ("该租户未配置第三方集成,请先新增配置".equals(result.get("message"))) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.badRequest().body(result);
}
}

View File

@@ -0,0 +1,46 @@
package com.rj.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 更新 {@code lb_third_integration_config} 凭证列的请求体(明文仅用于写入,响应不回显)。
*/
@Data
@Schema(description = "租户第三方集成凭证更新请求")
public class LbThirdIntegrationCredentialUpdateRequest {
@Schema(description = "完整 Cookie 明文,如 PHPSID=xxxx与 clearCookie 互斥")
private String cookie;
@Schema(description = "PHPSID 值明文(不含 PHPSID= 前缀);与 clearPhpsid 互斥")
private String phpsid;
@Schema(description = "货品/抢购 token 明文;与 clearGoodsApiToken 互斥")
private String goodsApiToken;
@Schema(description = "签名密钥 appStr 明文;与 clearGoodsApiAppStr 互斥")
private String goodsApiAppStr;
@Schema(description = "凭证预计过期时间(可选)")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime credentialExpireTime;
@Schema(description = "操作人(可选,写入 updated_by")
private String updatedBy;
@Schema(description = "为 true 时清除 cookie_cipher")
private Boolean clearCookie;
@Schema(description = "为 true 时清除 phpsid_cipher")
private Boolean clearPhpsid;
@Schema(description = "为 true 时清除 goods_api_token_cipher")
private Boolean clearGoodsApiToken;
@Schema(description = "为 true 时清除 goods_api_app_str_cipher")
private Boolean clearGoodsApiAppStr;
}

View File

@@ -79,6 +79,10 @@ public class LbAssessmentApply implements Serializable {
@JsonFlexibleLocalDateTime
private LocalDateTime applicationDatetime;
@TableField("sorted_num")
@Schema(description = "排序序号")
private Integer sortedNum;
@TableField("created_at")
@Schema(description = "创建时间")
@JsonFlexibleLocalDateTime

View File

@@ -19,9 +19,12 @@ public class LbOrderRow implements Serializable {
private static final long serialVersionUID = 1L;
/** 业务主键为订单 id由调用方传入非数据库自增 */
/**
* 订单 id与 {@link #tenantId} 组成复合主键 {@code (tenant_id, id)}),由调用方传入,非数据库自增。
* MyBatis-Plus 仅标注 {@code id} 为 {@link TableId},按主键定位记录时需同时使用租户 id。
*/
@TableId(value = "id", type = IdType.INPUT)
@Schema(description = "订单 id")
@Schema(description = "订单 id(复合主键之一,须与 tenantId 一起使用)")
private Long id;
@TableField("old_id")

View File

@@ -0,0 +1,212 @@
package com.rj.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 租户第三方集成配置(表 lb_third_integration_config
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("lb_third_integration_config")
@Schema(description = "租户第三方集成配置")
@JsonIgnoreProperties(ignoreUnknown = true)
public class LbThirdIntegrationConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId("id")
@Schema(description = "主键 UUID")
private String id;
@TableField("tenant_id")
@Schema(description = "租户ID")
private String tenantId;
@TableField("provider_code")
@Schema(description = "集成类型,如 HXR_ADMIN")
private String providerCode;
@TableField("enabled")
@Schema(description = "总开关1启用 0禁用")
private Integer enabled;
@TableField("admin_base_url")
@Schema(description = "后台管理域名")
private String adminBaseUrl;
@TableField("web_base_url")
@Schema(description = "前端 Web 域名")
private String webBaseUrl;
@TableField("order_select_path")
@Schema(description = "订单列表 API 路径")
private String orderSelectPath;
@TableField("user_select_path")
@Schema(description = "用户列表 API 路径")
private String userSelectPath;
@TableField("user_update_path")
@Schema(description = "用户更新 API 路径")
private String userUpdatePath;
@TableField("goods_api_path")
@Schema(description = "货品列表 API 路径")
private String goodsApiPath;
@TableField("buy_api_path")
@Schema(description = "抢购 API 路径")
private String buyApiPath;
@TableField("order_page_limit")
@Schema(description = "订单分页 limit")
private Integer orderPageLimit;
@TableField("user_page_limit")
@Schema(description = "用户分页 limit")
private Integer userPageLimit;
@TableField("goods_page_limit")
@Schema(description = "货品分页 limit")
private Integer goodsPageLimit;
@TableField("order_referer")
@Schema(description = "订单 Referer")
private String orderReferer;
@TableField("user_referer")
@Schema(description = "用户 Referer")
private String userReferer;
@TableField("goods_api_origin")
@Schema(description = "货品 Origin")
private String goodsApiOrigin;
@TableField("goods_api_referer")
@Schema(description = "货品 Referer")
private String goodsApiReferer;
@TableField("auth_type")
@Schema(description = "Admin 鉴权类型")
private String authType;
@TableField("cookie_cipher")
@Schema(description = "完整 Cookie 密文(存储字段,接口不回显)")
private byte[] cookieCipher;
@TableField("phpsid_cipher")
@Schema(description = "PHPSID 密文(存储字段,接口不回显)")
private byte[] phpsidCipher;
@TableField("goods_api_token_cipher")
@Schema(description = "货品/抢购 token 密文(存储字段,接口不回显)")
private byte[] goodsApiTokenCipher;
@TableField("goods_api_app_str_cipher")
@Schema(description = "签名密钥 appStr 密文(存储字段,接口不回显)")
private byte[] goodsApiAppStrCipher;
@TableField("credential_version")
@Schema(description = "凭证版本号")
private Integer credentialVersion;
@TableField("credential_expire_time")
@Schema(description = "凭证预计过期时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime credentialExpireTime;
@TableField("sync_order_resell_enabled")
@Schema(description = "定时同步未寄卖订单1启用 0禁用")
private Integer syncOrderResellEnabled;
@TableField("sync_order_unpaid_enabled")
@Schema(description = "定时同步未支付订单1启用 0禁用")
private Integer syncOrderUnpaidEnabled;
@TableField("sync_order_paid_enabled")
@Schema(description = "定时同步已支付订单1启用 0禁用")
private Integer syncOrderPaidEnabled;
@TableField("sync_user_enabled")
@Schema(description = "定时同步用户1启用 0禁用")
private Integer syncUserEnabled;
@TableField("extra_config")
@Schema(description = "扩展 JSON")
private String extraConfig;
@TableField("last_verified_time")
@Schema(description = "最近连通性探测时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime lastVerifiedTime;
@TableField("last_verified_ok")
@Schema(description = "最近探测结果1成功 0失败")
private Integer lastVerifiedOk;
@TableField("remark")
@Schema(description = "备注")
private String remark;
@TableField("created_by")
@Schema(description = "创建人")
private String createdBy;
@TableField("updated_by")
@Schema(description = "更新人")
private String updatedBy;
@TableField("create_time")
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@TableField("update_time")
@Schema(description = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
// ---------- 明文凭证(仅请求入参,不落库)----------
@TableField(exist = false)
@Schema(description = "完整 Cookie 明文(保存时加密入库)")
private String cookiePlain;
@TableField(exist = false)
@Schema(description = "PHPSID 明文(保存时加密入库)")
private String phpsidPlain;
@TableField(exist = false)
@Schema(description = "货品/抢购 token 明文(保存时加密入库)")
private String goodsApiTokenPlain;
@TableField(exist = false)
@Schema(description = "签名密钥 appStr 明文(保存时加密入库)")
private String goodsApiAppStrPlain;
@TableField(exist = false)
@Schema(description = "是否已配置 Cookie 密文")
private Boolean cookieConfigured;
@TableField(exist = false)
@Schema(description = "是否已配置 PHPSID 密文")
private Boolean phpsidConfigured;
@TableField(exist = false)
@Schema(description = "是否已配置货品 token 密文")
private Boolean goodsApiTokenConfigured;
@TableField(exist = false)
@Schema(description = "是否已配置 appStr 密文")
private Boolean goodsApiAppStrConfigured;
}

View File

@@ -0,0 +1,12 @@
package com.rj.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.rj.entity.LbThirdIntegrationConfig;
import org.apache.ibatis.annotations.Mapper;
/**
* 租户第三方集成配置 Mapper
*/
@Mapper
public interface LbThirdIntegrationConfigMapper extends BaseMapper<LbThirdIntegrationConfig> {
}

View File

@@ -36,7 +36,8 @@ public interface ILbGoodsService extends IService<LbGoods> {
Map<String, Object> syncFromHxrGoods(String tenantId, String token);
/**
* 按 {@code total_money} 从大到小选取 {@code lb_goods},调用 hxrd {@code /api/order/buy} 抢购
* 按 {@code total_money} 从大到小选取金额小于39000的 {@code lb_goods},调用 hxrd {@code /api/order/buy} 抢购
* 成功笔数达到 {@code maxBuyCount} 后停止,且循环抢购总次数不超过 {@code maxBuyCount} 的5倍。
*/
Map<String, Object> rushBuy(String token, Integer maxBuyCount);
}

View File

@@ -11,7 +11,10 @@ public interface ILbOrderRowService extends IService<LbOrderRow> {
Map<String, Object> update(LbOrderRow entity);
Map<String, Object> deleteById(Long id);
/**
* 按复合主键 {@code (tenant_id, id)} 删除;{@code tenantId} 为空时使用当前租户上下文。
*/
Map<String, Object> deleteById(Long id, String tenantId);
Map<String, Object> pageQuery(
Integer current,

View File

@@ -0,0 +1,38 @@
package com.rj.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
import com.rj.entity.LbThirdIntegrationConfig;
import java.util.Map;
/**
* 租户第三方集成配置服务
*/
public interface ILbThirdIntegrationConfigService extends IService<LbThirdIntegrationConfig> {
Map<String, Object> add(LbThirdIntegrationConfig entity);
Map<String, Object> update(LbThirdIntegrationConfig entity);
Map<String, Object> deleteById(String id);
Map<String, Object> pageQuery(Integer current,
Integer size,
String tenantId,
String providerCode,
Integer enabled);
Map<String, Object> getDetailById(String id);
/**
* 按租户 id 查询凭证配置(解密后返回明文,便于管理查看)。
*/
Map<String, Object> getCredentialStatusByTenantId(String tenantId);
/**
* 按租户 id 更新凭证列;至少需更新或清除一项凭证。
*/
Map<String, Object> updateCredentialByTenantId(
String tenantId, LbThirdIntegrationCredentialUpdateRequest request);
}

View File

@@ -71,7 +71,7 @@ public class LbAssessmentApplyServiceImpl
moderatorName 主持人姓名;
meetingNumber 会议号;
applicationDatetime 申请日期时间,优先 ISO-8601如 2026-05-15T14:30:00也可 yyyy-MM-dd HH:mm:ss若仅有日期可设为当天 00:00:00。
不要输出 id、tenantId、createdAt、updatedAt、notificationText。
不要输出 id、tenantId、createdAt、updatedAt、notificationText、sortedNum
""";
@Override
@@ -194,6 +194,9 @@ public class LbAssessmentApplyServiceImpl
entity.setCreatedAt(now);
}
entity.setUpdatedAt(now);
if (entity.getSortedNum() == null) {
entity.setSortedNum(resolveNextSortedNum(entity.getTenantId()));
}
refreshNotificationText(entity);
boolean ok = this.save(entity);
@@ -512,6 +515,7 @@ public class LbAssessmentApplyServiceImpl
queryWrapper.eq(LbAssessmentApply::getTenantId, tenantId.trim())
.ge(LbAssessmentApply::getApplicationDatetime, start)
.le(LbAssessmentApply::getApplicationDatetime, end)
.orderByAsc(LbAssessmentApply::getSortedNum)
.orderByDesc(LbAssessmentApply::getApplicationDatetime);
List<LbAssessmentApply> rows = this.list(queryWrapper);
@@ -554,7 +558,7 @@ public class LbAssessmentApplyServiceImpl
for (LbAssessmentApply item : rows) {
Row row = sheet.createRow(rowIndex);
row.setHeightInPoints(20);
createCell(row, 0, String.valueOf(rowIndex), dataStyle);
createCell(row, 0, formatSortedNum(item.getSortedNum(), rowIndex), dataStyle);
createCell(row, 1, nullToEmpty(item.getApplicantName()), dataStyle);
createCell(row, 2, nullToEmpty(item.getApplicantPhone()), dataStyle);
createCell(row, 3, nullToEmpty(item.getColleagueName()), dataStyle);
@@ -633,11 +637,28 @@ public class LbAssessmentApplyServiceImpl
if (meetingNumber != null && !meetingNumber.trim().isEmpty()) {
queryWrapper.like(LbAssessmentApply::getMeetingNumber, meetingNumber.trim());
}
queryWrapper.orderByDesc(LbAssessmentApply::getUpdatedAt)
queryWrapper.orderByAsc(LbAssessmentApply::getSortedNum)
.orderByDesc(LbAssessmentApply::getUpdatedAt)
.orderByDesc(LbAssessmentApply::getCreatedAt);
return queryWrapper;
}
private Integer resolveNextSortedNum(String tenantId) {
LambdaQueryWrapper<LbAssessmentApply> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(LbAssessmentApply::getTenantId, tenantId.trim())
.orderByDesc(LbAssessmentApply::getSortedNum)
.last("LIMIT 1");
LbAssessmentApply latest = this.getOne(queryWrapper);
if (latest == null || latest.getSortedNum() == null) {
return 1;
}
return latest.getSortedNum() + 1;
}
private static String formatSortedNum(Integer sortedNum, int fallback) {
return sortedNum != null ? String.valueOf(sortedNum) : String.valueOf(fallback);
}
private static String nullToEmpty(String value) {
return value == null ? "" : value;
}

View File

@@ -32,6 +32,8 @@ import java.util.Optional;
@RequiredArgsConstructor
public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> implements ILbGoodsService {
private static final BigDecimal RUSH_BUY_MAX_TOTAL_MONEY = new BigDecimal("39000");
private static final DateTimeFormatter DATETIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final HxrAdminGoodsService hxrAdminGoodsService;
@@ -387,37 +389,46 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
LambdaQueryWrapper<LbGoods> w = new LambdaQueryWrapper<>();
w.isNotNull(LbGoods::getSellerId);
w.lt(LbGoods::getTotalMoney, RUSH_BUY_MAX_TOTAL_MONEY);
w.orderByDesc(LbGoods::getTotalMoney).orderByDesc(LbGoods::getId);
List<LbGoods> goodsList = this.list(w);
if (goodsList.isEmpty()) {
result.put("success", false);
result.put("message", "lb_goods 中无可抢购货品");
result.put("message", "lb_goods 中无可抢购货品金额需小于39000");
result.put("successCount", 0);
result.put("failCount", 0);
result.put("details", List.of());
return result;
}
int maxAttempts = maxBuyCount * 10;
List<Map<String, Object>> details = new ArrayList<>();
int successCount = 0;
int failCount = 0;
int attemptCount = 0;
boolean stoppedByMax = false;
boolean stoppedByMaxAttempts = false;
for (LbGoods goods : goodsList) {
if (successCount >= maxBuyCount) {
stoppedByMax = true;
break;
}
if (attemptCount >= maxAttempts) {
stoppedByMaxAttempts = true;
break;
}
if (goods.getId() == null) {
continue;
}
attemptCount++;
Map<String, Object> item = new LinkedHashMap<>();
item.put("id", goods.getId());
item.put("sellerId", goods.getSellerId());
item.put("title", goods.getTitle());
item.put("totalMoney", goods.getTotalMoney());
log.info("正在抢购货品是:{}",item.toString());
HxrAdminBuyService.BuyApiResult buyResult =
hxrAdminBuyService.buy(goods.getId(), goods.getSellerId(), token);
item.put("apiCode", buyResult.apiCode());
@@ -438,7 +449,10 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
: "抢购未成功");
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("details", details);
return result;
} catch (Exception e) {

View File

@@ -99,13 +99,12 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
result.put("message", "merchandiseId不能为空");
return result;
}
if (this.getById(entity.getId()) != null) {
entity.setTenantId(entity.getTenantId().trim());
if (getByTenantAndId(entity.getTenantId(), entity.getId()) != null) {
result.put("success", false);
result.put("message", "该订单 id 已存在");
result.put("message", "租户下订单 id 已存在");
return result;
}
entity.setTenantId(entity.getTenantId().trim());
entity.setOrderSn(entity.getOrderSn().trim());
if (entity.getStatus() == null) {
entity.setStatus(0);
@@ -121,7 +120,7 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
result.put("success", ok);
result.put("message", ok ? "新增成功" : "新增失败");
if (ok) {
result.put("data", this.getById(entity.getId()));
result.put("data", getByTenantAndId(entity.getTenantId(), entity.getId()));
}
return result;
} catch (Exception e) {
@@ -140,16 +139,28 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
result.put("message", "id不能为空");
return result;
}
if (this.getById(entity.getId()) == null) {
String tenantId = resolveTenantId(entity.getTenantId());
if (tenantId == null) {
result.put("success", false);
result.put("message", "tenantId不能为空");
return result;
}
entity.setTenantId(tenantId);
if (getByTenantAndId(tenantId, entity.getId()) == null) {
result.put("success", false);
result.put("message", "记录不存在");
return result;
}
boolean ok = this.updateById(entity);
boolean ok =
this.update(
entity,
new LambdaQueryWrapper<LbOrderRow>()
.eq(LbOrderRow::getTenantId, tenantId)
.eq(LbOrderRow::getId, entity.getId()));
result.put("success", ok);
result.put("message", ok ? "编辑成功" : "编辑失败");
if (ok) {
result.put("data", this.getById(entity.getId()));
result.put("data", getByTenantAndId(tenantId, entity.getId()));
}
return result;
} catch (Exception e) {
@@ -160,10 +171,30 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
}
@Override
public Map<String, Object> deleteById(Long id) {
public Map<String, Object> deleteById(Long id, String tenantId) {
Map<String, Object> result = new HashMap<>();
try {
boolean ok = this.removeById(id);
if (id == null) {
result.put("success", false);
result.put("message", "id不能为空");
return result;
}
String tid = resolveTenantId(tenantId);
if (tid == null) {
result.put("success", false);
result.put("message", "tenantId不能为空");
return result;
}
if (getByTenantAndId(tid, id) == null) {
result.put("success", false);
result.put("message", "记录不存在");
return result;
}
boolean ok =
this.remove(
new LambdaQueryWrapper<LbOrderRow>()
.eq(LbOrderRow::getTenantId, tid)
.eq(LbOrderRow::getId, id));
result.put("success", ok);
result.put("message", ok ? "删除成功" : "删除失败");
return result;
@@ -615,19 +646,25 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
}
/**
* 按外部订单 id主键插入或更新;同批重复 id 保留最后一条。
* 按复合主键 {@code (tenant_id, id)} 插入或更新;同批重复保留最后一条。
*
* @return 实际 upsert 条数;无有效 id 时返回 0失败返回 -1
* @return 实际 upsert 条数;无有效时返回 0失败返回 -1
*/
private int upsertBatch(List<LbOrderRow> entities) {
if (entities == null || entities.isEmpty()) {
return 0;
}
Map<Long, LbOrderRow> deduped = new LinkedHashMap<>();
Map<String, LbOrderRow> deduped = new LinkedHashMap<>();
for (LbOrderRow entity : entities) {
if (entity.getId() != null) {
deduped.put(entity.getId(), entity);
if (entity.getId() == null) {
continue;
}
String tenantId = trimToNull(entity.getTenantId());
if (tenantId == null) {
continue;
}
entity.setTenantId(tenantId);
deduped.put(compositeKey(tenantId, entity.getId()), entity);
}
if (deduped.isEmpty()) {
return 0;
@@ -764,4 +801,35 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
e.setUpdatedAt(row.updatedAt());
return e;
}
private LbOrderRow getByTenantAndId(String tenantId, Long id) {
if (trimToNull(tenantId) == null || id == null) {
return null;
}
return this.getOne(
new LambdaQueryWrapper<LbOrderRow>()
.eq(LbOrderRow::getTenantId, tenantId.trim())
.eq(LbOrderRow::getId, id),
false);
}
private String resolveTenantId(String tenantIdFromParam) {
String current = trimToNull(TenantContextHolder.getTenantId());
if (current != null) {
return current;
}
return trimToNull(tenantIdFromParam);
}
private static String compositeKey(String tenantId, Long id) {
return tenantId + ":" + id;
}
private static String trimToNull(String value) {
if (value == null) {
return null;
}
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
}

View File

@@ -0,0 +1,543 @@
package com.rj.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.common.LbThirdIntegrationConstants;
import com.rj.common.PasswordUtil;
import com.rj.dto.LbThirdIntegrationCredentialUpdateRequest;
import com.rj.entity.LbThirdIntegrationConfig;
import com.rj.mapper.LbThirdIntegrationConfigMapper;
import com.rj.service.ILbThirdIntegrationConfigService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* 租户第三方集成配置服务实现
*/
@Service
public class LbThirdIntegrationConfigServiceImpl
extends ServiceImpl<LbThirdIntegrationConfigMapper, LbThirdIntegrationConfig>
implements ILbThirdIntegrationConfigService {
@Override
public Map<String, Object> add(LbThirdIntegrationConfig entity) {
Map<String, Object> result = new HashMap<>();
try {
String validationError = validateRequiredForAdd(entity);
if (validationError != null) {
result.put("success", false);
result.put("message", validationError);
return result;
}
String tenantId = entity.getTenantId().trim();
if (this.count(new LambdaQueryWrapper<LbThirdIntegrationConfig>()
.eq(LbThirdIntegrationConfig::getTenantId, tenantId)) > 0) {
result.put("success", false);
result.put("message", "该租户已存在集成配置,不能重复添加");
return result;
}
applyDefaults(entity);
entity.setTenantId(tenantId);
entity.setId(UUID.randomUUID().toString());
LocalDateTime now = LocalDateTime.now();
entity.setCreateTime(now);
entity.setUpdateTime(now);
boolean credentialUpdated = applyCredentialEncryption(entity, null);
if (credentialUpdated && entity.getCredentialVersion() == null) {
entity.setCredentialVersion(1);
} else if (entity.getCredentialVersion() == null) {
entity.setCredentialVersion(1);
}
boolean ok = this.save(entity);
result.put("success", ok);
result.put("message", ok ? "添加成功" : "添加失败");
if (ok) {
result.put("data", maskForResponse(this.getById(entity.getId())));
}
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "添加异常:" + e.getMessage());
return result;
}
}
@Override
public Map<String, Object> update(LbThirdIntegrationConfig entity) {
Map<String, Object> result = new HashMap<>();
try {
if (!StringUtils.hasText(entity.getId())) {
result.put("success", false);
result.put("message", "ID不能为空");
return result;
}
LbThirdIntegrationConfig existing = this.getById(entity.getId().trim());
if (existing == null) {
result.put("success", false);
result.put("message", "记录不存在");
return result;
}
if (StringUtils.hasText(entity.getTenantId())
&& !entity.getTenantId().trim().equals(existing.getTenantId())) {
String newTenantId = entity.getTenantId().trim();
long dup = this.count(new LambdaQueryWrapper<LbThirdIntegrationConfig>()
.eq(LbThirdIntegrationConfig::getTenantId, newTenantId)
.ne(LbThirdIntegrationConfig::getId, existing.getId()));
if (dup > 0) {
result.put("success", false);
result.put("message", "目标租户已存在集成配置");
return result;
}
}
boolean credentialUpdated = applyCredentialEncryption(entity, existing);
if (credentialUpdated) {
int version = existing.getCredentialVersion() == null ? 1 : existing.getCredentialVersion();
entity.setCredentialVersion(version + 1);
}
entity.setUpdateTime(LocalDateTime.now());
boolean ok = this.updateById(entity);
result.put("success", ok);
result.put("message", ok ? "更新成功" : "更新失败");
if (ok) {
result.put("data", maskForResponse(this.getById(entity.getId())));
}
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "更新异常:" + e.getMessage());
return result;
}
}
@Override
public Map<String, Object> deleteById(String id) {
Map<String, Object> result = new HashMap<>();
try {
if (!StringUtils.hasText(id)) {
result.put("success", false);
result.put("message", "ID不能为空");
return result;
}
boolean ok = this.removeById(id.trim());
result.put("success", ok);
result.put("message", ok ? "删除成功" : "删除失败");
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "删除异常:" + e.getMessage());
return result;
}
}
@Override
public Map<String, Object> pageQuery(Integer current,
Integer size,
String tenantId,
String providerCode,
Integer enabled) {
Map<String, Object> result = new HashMap<>();
try {
if (current == null || current < 1) {
current = 1;
}
if (size == null || size < 1) {
size = 10;
}
LambdaQueryWrapper<LbThirdIntegrationConfig> q = new LambdaQueryWrapper<>();
if (StringUtils.hasText(tenantId)) {
q.eq(LbThirdIntegrationConfig::getTenantId, tenantId.trim());
}
if (StringUtils.hasText(providerCode)) {
q.eq(LbThirdIntegrationConfig::getProviderCode, providerCode.trim());
}
if (enabled != null) {
q.eq(LbThirdIntegrationConfig::getEnabled, enabled);
}
q.orderByDesc(LbThirdIntegrationConfig::getUpdateTime)
.orderByDesc(LbThirdIntegrationConfig::getCreateTime);
Page<LbThirdIntegrationConfig> page = this.page(new Page<>(current, size), q);
List<LbThirdIntegrationConfig> records = page.getRecords().stream()
.map(this::maskForResponse)
.toList();
result.put("success", true);
result.put("message", "查询成功");
result.put("data", records);
result.put("total", page.getTotal());
result.put("current", page.getCurrent());
result.put("size", page.getSize());
result.put("pages", page.getPages());
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "查询异常:" + e.getMessage());
return result;
}
}
@Override
public Map<String, Object> getDetailById(String id) {
Map<String, Object> result = new HashMap<>();
try {
if (!StringUtils.hasText(id)) {
result.put("success", false);
result.put("message", "ID不能为空");
return result;
}
LbThirdIntegrationConfig data = this.getById(id.trim());
if (data == null) {
result.put("success", false);
result.put("message", "记录不存在");
return result;
}
result.put("success", true);
result.put("message", "查询成功");
result.put("data", maskForResponse(data));
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "查询异常:" + e.getMessage());
return result;
}
}
@Override
public Map<String, Object> getCredentialStatusByTenantId(String tenantId) {
Map<String, Object> result = new HashMap<>();
try {
if (!StringUtils.hasText(tenantId)) {
result.put("success", false);
result.put("message", "tenantId不能为空");
return result;
}
LbThirdIntegrationConfig config = getByTenantIdOrNull(tenantId.trim());
if (config == null) {
result.put("success", false);
result.put("message", "该租户未配置第三方集成");
return result;
}
result.put("success", true);
result.put("message", "查询成功");
result.put("data", buildCredentialStatus(config, true));
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "查询异常:" + e.getMessage());
return result;
}
}
@Override
public Map<String, Object> updateCredentialByTenantId(
String tenantId, LbThirdIntegrationCredentialUpdateRequest request) {
Map<String, Object> result = new HashMap<>();
try {
if (!StringUtils.hasText(tenantId)) {
result.put("success", false);
result.put("message", "tenantId不能为空");
return result;
}
if (request == null) {
result.put("success", false);
result.put("message", "请求体不能为空");
return result;
}
LbThirdIntegrationConfig existing = getByTenantIdOrNull(tenantId.trim());
if (existing == null) {
result.put("success", false);
result.put("message", "该租户未配置第三方集成,请先新增配置");
return result;
}
String validationError = validateCredentialUpdateRequest(request);
if (validationError != null) {
result.put("success", false);
result.put("message", validationError);
return result;
}
LambdaUpdateWrapper<LbThirdIntegrationConfig> uw = new LambdaUpdateWrapper<>();
uw.eq(LbThirdIntegrationConfig::getId, existing.getId());
applyCredentialUpdateWrapper(uw, request);
if (request.getCredentialExpireTime() != null) {
uw.set(LbThirdIntegrationConfig::getCredentialExpireTime, request.getCredentialExpireTime());
}
if (StringUtils.hasText(request.getUpdatedBy())) {
uw.set(LbThirdIntegrationConfig::getUpdatedBy, request.getUpdatedBy().trim());
}
int version = existing.getCredentialVersion() == null ? 1 : existing.getCredentialVersion();
uw.set(LbThirdIntegrationConfig::getCredentialVersion, version + 1);
uw.set(LbThirdIntegrationConfig::getUpdateTime, LocalDateTime.now());
boolean ok = this.update(uw);
result.put("success", ok);
result.put("message", ok ? "凭证更新成功" : "凭证更新失败");
if (ok) {
LbThirdIntegrationConfig latest = this.getById(existing.getId());
result.put("data", buildCredentialStatus(latest, true));
}
return result;
} catch (Exception e) {
result.put("success", false);
result.put("message", "凭证更新异常:" + e.getMessage());
return result;
}
}
private LbThirdIntegrationConfig getByTenantIdOrNull(String tenantId) {
return this.getOne(new LambdaQueryWrapper<LbThirdIntegrationConfig>()
.eq(LbThirdIntegrationConfig::getTenantId, tenantId)
.last("LIMIT 1"));
}
private static String validateCredentialUpdateRequest(LbThirdIntegrationCredentialUpdateRequest request) {
boolean hasUpdate = StringUtils.hasText(request.getCookie())
|| StringUtils.hasText(request.getPhpsid())
|| StringUtils.hasText(request.getGoodsApiToken())
|| StringUtils.hasText(request.getGoodsApiAppStr());
boolean hasClear = Boolean.TRUE.equals(request.getClearCookie())
|| Boolean.TRUE.equals(request.getClearPhpsid())
|| Boolean.TRUE.equals(request.getClearGoodsApiToken())
|| Boolean.TRUE.equals(request.getClearGoodsApiAppStr());
if (!hasUpdate && !hasClear) {
return "请至少提供一项凭证明文,或指定一项 clear* 清除操作";
}
if (Boolean.TRUE.equals(request.getClearCookie()) && StringUtils.hasText(request.getCookie())) {
return "clearCookie 与 cookie 不能同时传";
}
if (Boolean.TRUE.equals(request.getClearPhpsid()) && StringUtils.hasText(request.getPhpsid())) {
return "clearPhpsid 与 phpsid 不能同时传";
}
if (Boolean.TRUE.equals(request.getClearGoodsApiToken()) && StringUtils.hasText(request.getGoodsApiToken())) {
return "clearGoodsApiToken 与 goodsApiToken 不能同时传";
}
if (Boolean.TRUE.equals(request.getClearGoodsApiAppStr()) && StringUtils.hasText(request.getGoodsApiAppStr())) {
return "clearGoodsApiAppStr 与 goodsApiAppStr 不能同时传";
}
return null;
}
private void applyCredentialUpdateWrapper(
LambdaUpdateWrapper<LbThirdIntegrationConfig> uw,
LbThirdIntegrationCredentialUpdateRequest request) {
if (Boolean.TRUE.equals(request.getClearCookie())) {
uw.set(LbThirdIntegrationConfig::getCookieCipher, null);
} else if (StringUtils.hasText(request.getCookie())) {
uw.set(LbThirdIntegrationConfig::getCookieCipher, encryptToBytes(request.getCookie()));
}
if (Boolean.TRUE.equals(request.getClearPhpsid())) {
uw.set(LbThirdIntegrationConfig::getPhpsidCipher, null);
} else if (StringUtils.hasText(request.getPhpsid())) {
uw.set(LbThirdIntegrationConfig::getPhpsidCipher, encryptToBytes(request.getPhpsid()));
}
if (Boolean.TRUE.equals(request.getClearGoodsApiToken())) {
uw.set(LbThirdIntegrationConfig::getGoodsApiTokenCipher, null);
} else if (StringUtils.hasText(request.getGoodsApiToken())) {
uw.set(LbThirdIntegrationConfig::getGoodsApiTokenCipher, encryptToBytes(request.getGoodsApiToken()));
}
if (Boolean.TRUE.equals(request.getClearGoodsApiAppStr())) {
uw.set(LbThirdIntegrationConfig::getGoodsApiAppStrCipher, null);
} else if (StringUtils.hasText(request.getGoodsApiAppStr())) {
uw.set(LbThirdIntegrationConfig::getGoodsApiAppStrCipher, encryptToBytes(request.getGoodsApiAppStr()));
}
}
private Map<String, Object> buildCredentialStatus(LbThirdIntegrationConfig config, boolean includePlaintext) {
Map<String, Object> data = new HashMap<>();
data.put("id", config.getId());
data.put("tenantId", config.getTenantId());
data.put("providerCode", config.getProviderCode());
data.put("authType", config.getAuthType());
data.put("cookieConfigured", hasCipher(config.getCookieCipher()));
data.put("phpsidConfigured", hasCipher(config.getPhpsidCipher()));
data.put("goodsApiTokenConfigured", hasCipher(config.getGoodsApiTokenCipher()));
data.put("goodsApiAppStrConfigured", hasCipher(config.getGoodsApiAppStrCipher()));
data.put("credentialVersion", config.getCredentialVersion());
data.put("credentialExpireTime", config.getCredentialExpireTime());
data.put("lastVerifiedTime", config.getLastVerifiedTime());
data.put("lastVerifiedOk", config.getLastVerifiedOk());
data.put("updateTime", config.getUpdateTime());
if (includePlaintext) {
data.put("cookie", decryptFromBytes(config.getCookieCipher()));
data.put("phpsid", decryptFromBytes(config.getPhpsidCipher()));
data.put("goodsApiToken", decryptFromBytes(config.getGoodsApiTokenCipher()));
data.put("goodsApiAppStr", decryptFromBytes(config.getGoodsApiAppStrCipher()));
}
return data;
}
private String validateRequiredForAdd(LbThirdIntegrationConfig entity) {
if (entity == null) {
return "请求体不能为空";
}
if (!StringUtils.hasText(entity.getTenantId())) {
return "tenantId不能为空";
}
if (!StringUtils.hasText(entity.getAdminBaseUrl())) {
return "adminBaseUrl不能为空";
}
if (!StringUtils.hasText(entity.getWebBaseUrl())) {
return "webBaseUrl不能为空";
}
return null;
}
private void applyDefaults(LbThirdIntegrationConfig entity) {
if (!StringUtils.hasText(entity.getProviderCode())) {
entity.setProviderCode(LbThirdIntegrationConstants.PROVIDER_HXR_ADMIN);
}
if (entity.getEnabled() == null) {
entity.setEnabled(1);
}
if (!StringUtils.hasText(entity.getOrderSelectPath())) {
entity.setOrderSelectPath(LbThirdIntegrationConstants.DEFAULT_ORDER_SELECT_PATH);
}
if (!StringUtils.hasText(entity.getUserSelectPath())) {
entity.setUserSelectPath(LbThirdIntegrationConstants.DEFAULT_USER_SELECT_PATH);
}
if (!StringUtils.hasText(entity.getUserUpdatePath())) {
entity.setUserUpdatePath(LbThirdIntegrationConstants.DEFAULT_USER_UPDATE_PATH);
}
if (!StringUtils.hasText(entity.getGoodsApiPath())) {
entity.setGoodsApiPath(LbThirdIntegrationConstants.DEFAULT_GOODS_API_PATH);
}
if (!StringUtils.hasText(entity.getBuyApiPath())) {
entity.setBuyApiPath(LbThirdIntegrationConstants.DEFAULT_BUY_API_PATH);
}
if (entity.getOrderPageLimit() == null) {
entity.setOrderPageLimit(LbThirdIntegrationConstants.DEFAULT_ORDER_PAGE_LIMIT);
}
if (entity.getUserPageLimit() == null) {
entity.setUserPageLimit(LbThirdIntegrationConstants.DEFAULT_USER_PAGE_LIMIT);
}
if (entity.getGoodsPageLimit() == null) {
entity.setGoodsPageLimit(LbThirdIntegrationConstants.DEFAULT_GOODS_PAGE_LIMIT);
}
if (!StringUtils.hasText(entity.getAuthType())) {
entity.setAuthType(LbThirdIntegrationConstants.AUTH_COOKIE_PHPSID);
}
if (entity.getSyncOrderResellEnabled() == null) {
entity.setSyncOrderResellEnabled(0);
}
if (entity.getSyncOrderUnpaidEnabled() == null) {
entity.setSyncOrderUnpaidEnabled(0);
}
if (entity.getSyncOrderPaidEnabled() == null) {
entity.setSyncOrderPaidEnabled(0);
}
if (entity.getSyncUserEnabled() == null) {
entity.setSyncUserEnabled(0);
}
if (entity.getCredentialVersion() == null) {
entity.setCredentialVersion(1);
}
}
/**
* 将明文凭证加密为 VARBINARY未传明文则保留已有密文更新场景
*
* @return 是否有任一凭证字段被更新
*/
private boolean applyCredentialEncryption(LbThirdIntegrationConfig entity, LbThirdIntegrationConfig existing) {
boolean updated = false;
if (StringUtils.hasText(entity.getCookiePlain())) {
entity.setCookieCipher(encryptToBytes(entity.getCookiePlain()));
updated = true;
} else if (existing != null) {
entity.setCookieCipher(existing.getCookieCipher());
}
if (StringUtils.hasText(entity.getPhpsidPlain())) {
entity.setPhpsidCipher(encryptToBytes(entity.getPhpsidPlain()));
updated = true;
} else if (existing != null) {
entity.setPhpsidCipher(existing.getPhpsidCipher());
}
if (StringUtils.hasText(entity.getGoodsApiTokenPlain())) {
entity.setGoodsApiTokenCipher(encryptToBytes(entity.getGoodsApiTokenPlain()));
updated = true;
} else if (existing != null) {
entity.setGoodsApiTokenCipher(existing.getGoodsApiTokenCipher());
}
if (StringUtils.hasText(entity.getGoodsApiAppStrPlain())) {
entity.setGoodsApiAppStrCipher(encryptToBytes(entity.getGoodsApiAppStrPlain()));
updated = true;
} else if (existing != null) {
entity.setGoodsApiAppStrCipher(existing.getGoodsApiAppStrCipher());
}
entity.setCookiePlain(null);
entity.setPhpsidPlain(null);
entity.setGoodsApiTokenPlain(null);
entity.setGoodsApiAppStrPlain(null);
return updated;
}
private static byte[] encryptToBytes(String plainText) {
String encrypted = PasswordUtil.encryptReversibleWithDefaultSalt(plainText);
return encrypted.getBytes(StandardCharsets.UTF_8);
}
/**
* 供业务层读取凭证明文(内部使用)
*/
public static String decryptFromBytes(byte[] cipherBytes) {
if (cipherBytes == null || cipherBytes.length == 0) {
return null;
}
String stored = new String(cipherBytes, StandardCharsets.UTF_8);
return PasswordUtil.decryptReversibleWithDefaultSalt(stored);
}
private LbThirdIntegrationConfig maskForResponse(LbThirdIntegrationConfig entity) {
if (entity == null) {
return null;
}
entity.setCookieConfigured(hasCipher(entity.getCookieCipher()));
entity.setPhpsidConfigured(hasCipher(entity.getPhpsidCipher()));
entity.setGoodsApiTokenConfigured(hasCipher(entity.getGoodsApiTokenCipher()));
entity.setGoodsApiAppStrConfigured(hasCipher(entity.getGoodsApiAppStrCipher()));
entity.setCookieCipher(null);
entity.setPhpsidCipher(null);
entity.setGoodsApiTokenCipher(null);
entity.setGoodsApiAppStrCipher(null);
entity.setCookiePlain(null);
entity.setPhpsidPlain(null);
entity.setGoodsApiTokenPlain(null);
entity.setGoodsApiAppStrPlain(null);
return entity;
}
private static boolean hasCipher(byte[] cipher) {
return cipher != null && cipher.length > 0;
}
}