礼物区域追加

This commit is contained in:
hy001 2026-04-27 12:38:08 +08:00
parent 8e4e8f5db2
commit 82e8dc0bfe
16 changed files with 339 additions and 106 deletions

View File

@ -44,6 +44,12 @@
<version>${mysql-connector-java.version}</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
@ -116,6 +122,7 @@
<elasticjob.version>3.0.4</elasticjob.version>
<snakeyaml.version>2.2</snakeyaml.version>
<mysql-connector-java.version>8.0.33</mysql-connector-java.version>
<p6spy.version>3.8.5</p6spy.version>
</properties>
<parent>

View File

@ -23,5 +23,5 @@ feign:
elasticjob:
reg-center:
server-lists: 127.0.0.1:2181
server-lists: zookeeper:2181
namespace: rc-scheduling-local

View File

@ -27,6 +27,10 @@ spring:
config:
import:
- optional:nacos:application.@register.file-extension@
- optional:nacos:rds-config.@register.file-extension@?group=@config.group.common@
- optional:nacos:redis-config.@register.file-extension@?group=@config.group.common@
- optional:nacos:external.@register.file-extension@?refresh=true&group=@config.group.common@
- optional:nacos:rocketmq.@register.file-extension@?group=@config.group.common@
- optional:nacos:framework-config.@register.file-extension@?refresh=true&group=@config.group.common@
logging:

View File

@ -30,6 +30,8 @@ spring:
- optional:nacos:application.@register.file-extension@?refresh=true&group=@artifactId@
- optional:nacos:application-${spring-profile.active}.@register.file-extension@?refresh=true&group=@artifactId@
- optional:nacos:${spring.application.name}-${spring-profile.active}.@register.file-extension@?refresh=true&group=@artifactId@
- optional:nacos:rds-config.@register.file-extension@?group=@config.group.common@
- optional:nacos:redis-config.@register.file-extension@?group=@config.group.common@
- optional:nacos:rocketmq.@register.file-extension@?group=@config.group.common@
# - optional:nacos:external.@register.file-extension@?refresh=true&group=@config.group.common@
- optional:nacos:framework-config.@register.file-extension@?refresh=true&group=@config.group.common@

View File

@ -96,6 +96,13 @@ public interface GiftConfigClientApi {
ResultResponse<Boolean> switchDelStatus(@RequestParam("id") Long id,
@RequestParam("status") Boolean status);
/**
* 批量追加当前平台所有礼物区域.
*/
@PostMapping("/addAllGiftRegion")
ResultResponse<Boolean> addAllGiftRegion(@RequestParam("sysOrigin") String sysOrigin,
@RequestParam("regionId") String regionId);
/**
* 礼物列表.
*/

View File

@ -3,6 +3,7 @@ package com.red.circle.console.adapter.app.sys;
import com.red.circle.console.app.dto.clienobject.sys.SysGiftConfigCO;
import com.red.circle.console.app.dto.cmd.app.sys.GiftConsoleQryCmd;
import com.red.circle.console.app.dto.cmd.app.sys.GiftRegionAddCmd;
import com.red.circle.console.app.service.app.sys.SysGiftConfigService;
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
import com.red.circle.framework.dto.PageResult;
@ -65,6 +66,24 @@ public class SysGiftConfigRestController extends BaseController {
sysGiftConfigService.addGift(param);
}
/**
* 批量追加当前平台所有礼物区域.
*/
@OpsOperationReqLog(value = "批量追加礼物区域")
@PostMapping("/regions/add-all")
public void addAllGiftRegion(@RequestBody GiftRegionAddCmd param) {
sysGiftConfigService.addAllGiftRegion(param);
}
/**
* 兼容旧前端入口实际逻辑仍然是追加区域.
*/
@OpsOperationReqLog(value = "批量追加礼物区域")
@PostMapping("/regions/transfer-all")
public void addAllGiftRegionCompatible(@RequestBody GiftRegionAddCmd param) {
sysGiftConfigService.addAllGiftRegion(param);
}
/**
* 上下架礼物.
*/

View File

@ -6,6 +6,7 @@ import com.red.circle.common.business.core.ImageSizeConst;
import com.red.circle.console.app.convertor.sys.GiftAppConvertor;
import com.red.circle.console.app.dto.clienobject.sys.SysGiftConfigCO;
import com.red.circle.console.app.dto.cmd.app.sys.GiftConsoleQryCmd;
import com.red.circle.console.app.dto.cmd.app.sys.GiftRegionAddCmd;
import com.red.circle.console.infra.enums.sys.SysGiftTypeEnum;
import com.red.circle.console.inner.error.ConsoleErrorCode;
import com.red.circle.external.inner.endpoint.oss.OssServiceClient;
@ -160,6 +161,22 @@ public class SysGiftConfigServiceImpl implements SysGiftConfigService {
giftConfigClient.listByTabV2(giftAppConvertor.toGiftQryCmd(query)));
}
@Override
public void addAllGiftRegion(GiftRegionAddCmd param) {
ResponseAssert.notNull(GiftErrorCode.BAD_REQUEST, param);
ResponseAssert.isTrue(GiftErrorCode.BAD_REQUEST, StringUtils.isNotBlank(param.getSysOrigin()));
ResponseAssert.isTrue(GiftErrorCode.BAD_REQUEST, StringUtils.isNotBlank(param.getRegionId()));
Map<String, String> mapRegion = ResponseAssert.requiredSuccess(
regionConfigClient.mapRegionNameBySysOrigin(param.getSysOrigin()));
ResponseAssert.isTrue(GiftErrorCode.BAD_REQUEST, mapRegion.containsKey(param.getRegionId()));
ResponseAssert.isTrue(CommonErrorCode.UPDATE_FAILURE,
ResponseAssert.requiredSuccess(giftConfigClient.addAllGiftRegion(
param.getSysOrigin(), param.getRegionId())));
giftConfigClient.removeGiftCache();
}
@Override
public List<SysGiftConfigCO> listByExpiredTime(Timestamp now) {
return giftAppConvertor.toSysGiftConfigCOList(ResponseAssert.requiredSuccess(giftConfigClient.listByExpiredTime(now)));

View File

@ -0,0 +1,27 @@
package com.red.circle.console.app.dto.cmd.app.sys;
import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 礼物区域批量追加参数.
*/
@Data
@Accessors(chain = true)
public class GiftRegionAddCmd implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 归属系统.
*/
private String sysOrigin;
/**
* 要追加的区域ID.
*/
private String regionId;
}

View File

@ -1,6 +1,7 @@
package com.red.circle.console.app.service.app.sys;
import com.red.circle.console.app.dto.clienobject.sys.SysGiftConfigCO;
import com.red.circle.console.app.dto.cmd.app.sys.GiftRegionAddCmd;
import com.red.circle.console.app.dto.cmd.app.sys.GiftConsoleQryCmd;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
@ -59,5 +60,10 @@ public interface SysGiftConfigService {
*/
List<GiftConfigDTO> listByTabV2(GiftConsoleQryCmd query);
/**
* 批量追加当前平台所有礼物区域.
*/
void addAllGiftRegion(GiftRegionAddCmd param);
List<SysGiftConfigCO> listByExpiredTime(Timestamp now);
}

View File

@ -41,6 +41,7 @@ import org.springframework.stereotype.Service;
public class ImGroupClientServiceImpl implements ImGroupClientService {
private static final Integer GROUP_ALREADY_EXISTS_ERROR_CODE = 10025;
private static final Integer GROUP_ALREADY_USED_ERROR_CODE = 10021;
private final RcMessageProperties rcMessageProperties;
private final ImGroupMemberService imGroupMemberService;
@ -179,8 +180,9 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
if (Objects.equals(errorCode, 0)) {
return true;
}
if (Objects.equals(errorCode, GROUP_ALREADY_EXISTS_ERROR_CODE)) {
log.warn("createAVChatRoomGroup duplicate groupId={}, treat as success", cmd.getGroupId());
if (isGroupAlreadyExists(errorCode, response)) {
log.warn("createAVChatRoomGroup duplicate groupId={}, errorCode={}, treat as success",
cmd.getGroupId(), errorCode);
return true;
}
@ -212,6 +214,36 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
}
}
boolean isGroupAlreadyExists(Integer errorCode, String res) {
if (Objects.equals(errorCode, GROUP_ALREADY_EXISTS_ERROR_CODE)
|| Objects.equals(errorCode, GROUP_ALREADY_USED_ERROR_CODE)) {
return true;
}
String errorInfo = parseErrorInfo(res);
if (StringUtils.isBlank(errorInfo)) {
return false;
}
String normalizedErrorInfo = errorInfo.toLowerCase();
return normalizedErrorInfo.contains("group id in use")
|| normalizedErrorInfo.contains("group id has been used");
}
String parseErrorInfo(String res) {
try {
JsonObject jsonObject = JsonParser.parseString(res).getAsJsonObject();
if (Objects.isNull(jsonObject) || !jsonObject.has("ErrorInfo")
|| jsonObject.get("ErrorInfo").isJsonNull()) {
return null;
}
return jsonObject.get("ErrorInfo").getAsString();
} catch (Exception ex) {
log.warn("parseErrorInfo fail res={}", res, ex);
return null;
}
}
boolean recoverRoomGroup(String groupId) {
String normalizedGroupId = Objects.isNull(groupId) ? null : groupId.trim();
if (!isRecoverableRoomGroupId(normalizedGroupId)) {

View File

@ -94,6 +94,56 @@ class ImGroupClientServiceImplTest {
assertTrue(created);
}
@Test
void createAvChatRoomGroupShouldTreatUsedGroupAsSuccess() {
ImGroupManagerService imGroupManagerService = mock(ImGroupManagerService.class);
@SuppressWarnings("unchecked")
RcHttpClient.ResponseMono<String> responseMono = mock(RcHttpClient.ResponseMono.class);
when(imGroupManagerService.createGroup(any())).thenReturn(responseMono);
when(responseMono.block())
.thenReturn("{\"ErrorCode\":10021,\"ErrorInfo\":\"group id has been used!\"}");
ImGroupClientServiceImpl service = new ImGroupClientServiceImpl(
mock(RcMessageProperties.class),
mock(ImGroupMemberService.class),
mock(ImGroupMessageService.class),
imGroupManagerService,
mock(RoomManagerClient.class)
);
boolean created = service.createAVChatRoomGroup(new CreateGroupCmd()
.setOwnerAccount("2048587544039321602")
.setGroupId("1001859")
.setName("10025"));
assertTrue(created);
}
@Test
void createAvChatRoomGroupShouldTreatDuplicateErrorInfoAsSuccess() {
ImGroupManagerService imGroupManagerService = mock(ImGroupManagerService.class);
@SuppressWarnings("unchecked")
RcHttpClient.ResponseMono<String> responseMono = mock(RcHttpClient.ResponseMono.class);
when(imGroupManagerService.createGroup(any())).thenReturn(responseMono);
when(responseMono.block())
.thenReturn("{\"ErrorCode\":99999,\"ErrorInfo\":\"group id has been used!\"}");
ImGroupClientServiceImpl service = new ImGroupClientServiceImpl(
mock(RcMessageProperties.class),
mock(ImGroupMemberService.class),
mock(ImGroupMessageService.class),
imGroupManagerService,
mock(RoomManagerClient.class)
);
boolean created = service.createAVChatRoomGroup(new CreateGroupCmd()
.setOwnerAccount("2048587544039321602")
.setGroupId("1001859")
.setName("10025"));
assertTrue(created);
}
private static final class TestableImGroupClientServiceImpl extends ImGroupClientServiceImpl {
private boolean createResult;

View File

@ -122,6 +122,11 @@ public interface GiftConfigService extends BaseService<GiftConfig> {
*/
Boolean switchDelStatus(Long id, Boolean status);
/**
* 批量追加当前平台所有礼物区域.
*/
Boolean addAllGiftRegion(String sysOrigin, String regionId);
/**
* 礼物列表.
*/

View File

@ -17,6 +17,7 @@ import com.red.circle.tool.core.num.NumUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -242,6 +243,47 @@ public class GiftConfigServiceImpl extends BaseServiceImpl<GiftConfigDAO, GiftCo
.execute();
}
@Override
public Boolean addAllGiftRegion(String sysOrigin, String regionId) {
if (StringUtils.isBlank(sysOrigin) || StringUtils.isBlank(regionId)) {
return Boolean.FALSE;
}
List<GiftConfig> giftConfigs = query()
.select(GiftConfig::getId, GiftConfig::getRegions)
.eq(GiftConfig::getSysOrigin, sysOrigin)
.list();
if (CollectionUtils.isEmpty(giftConfigs)) {
return Boolean.TRUE;
}
List<GiftConfig> needUpdateGifts = giftConfigs.stream()
.map(giftConfig -> buildGiftRegionAppend(giftConfig, regionId))
.filter(Objects::nonNull)
.collect(Collectors.toList());
return CollectionUtils.isEmpty(needUpdateGifts) || updateBatchById(needUpdateGifts);
}
private GiftConfig buildGiftRegionAppend(GiftConfig giftConfig, String regionId) {
String nextRegions = appendRegion(giftConfig.getRegions(), regionId);
if (Objects.equals(nextRegions, giftConfig.getRegions())) {
return null;
}
return new GiftConfig()
.setId(giftConfig.getId())
.setRegions(nextRegions);
}
private String appendRegion(String regions, String regionId) {
if (StringUtils.isBlank(regions)) {
return regionId;
}
LinkedHashSet<String> regionSet = Stream.of(regions.split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
return regionSet.add(regionId) ? String.join(",", regionSet) : regions;
}
@Override
public List<GiftConfig> listByTab(String sysOrigin, String giftTab) {
return Optional.ofNullable(query()

View File

@ -88,6 +88,11 @@ public class GiftConfigClientEndpoint implements GiftConfigClientApi {
return ResultResponse.success(giftConfigClientService.switchDelStatus(id, status));
}
@Override
public ResultResponse<Boolean> addAllGiftRegion(String sysOrigin, String regionId) {
return ResultResponse.success(giftConfigClientService.addAllGiftRegion(sysOrigin, regionId));
}
@Override
public ResultResponse<List<GiftConfigDTO>> listByTab(String sysOrigin, String giftTab) {
return ResultResponse.success(giftConfigClientService.listByTab(sysOrigin, giftTab));

View File

@ -73,6 +73,11 @@ public interface GiftConfigClientService {
*/
Boolean switchDelStatus(Long id, Boolean status);
/**
* 批量追加当前平台所有礼物区域.
*/
Boolean addAllGiftRegion(String sysOrigin, String regionId);
/**
* 礼物列表.
*/

View File

@ -90,6 +90,11 @@ public class GiftConfigClientServiceImpl implements GiftConfigClientService {
return giftConfigService.switchDelStatus(id, status);
}
@Override
public Boolean addAllGiftRegion(String sysOrigin, String regionId) {
return giftConfigService.addAllGiftRegion(sysOrigin, regionId);
}
@Override
public List<GiftConfigDTO> listByTab(String sysOrigin, String giftTab) {
return giftInnerConvertor.toListGiftConfigDTO(giftConfigService.listByTab(sysOrigin, giftTab));