fix: 提交标签同步
This commit is contained in:
@@ -30,4 +30,10 @@ public interface CustomTagMapper extends BaseMapperX<CustomTagDO> {
|
||||
.orderByDesc(CustomTagDO::getId));
|
||||
}
|
||||
|
||||
default List<CustomTagDO> selectListByType(String type) {
|
||||
return selectList(new LambdaQueryWrapperX<CustomTagDO>()
|
||||
.eq(CustomTagDO::getType, type)
|
||||
.orderByAsc(CustomTagDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,4 +29,10 @@ public interface TagMapper extends BaseMapperX<TagDO> {
|
||||
.eqIfPresent(TagDO::getType, type)
|
||||
.orderByDesc(TagDO::getId));
|
||||
}
|
||||
|
||||
default TagDO selectByNameAndType(String name, String type) {
|
||||
return selectOne(new LambdaQueryWrapperX<TagDO>()
|
||||
.eq(TagDO::getName, name)
|
||||
.eq(TagDO::getType, type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,5 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode TAG_CONFIG_NOT_EXISTS = new ErrorCode(1_001_001_002, "标签同步配置不存在");
|
||||
ErrorCode TAG_SYNC_HISTORY_NOT_EXISTS = new ErrorCode(1_001_001_003, "标签同步历史不存在");
|
||||
ErrorCode TAG_CONFIG_DATABASE_REQUIRED = new ErrorCode(1_001_001_004, "新增配置时同步数据源不能为空");
|
||||
ErrorCode TAG_NAME_DUPLICATE = new ErrorCode(1_001_001_005, "同类型下已存在相同名称的标签");
|
||||
}
|
||||
|
||||
@@ -59,4 +59,12 @@ public interface CustomTagService {
|
||||
*/
|
||||
PageResult<CustomTagDO> getCustomTagPage(CustomTagPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 根据类型获取定制标签列表(用于同步)
|
||||
*
|
||||
* @param type 标签类型 product/store/supplier/member
|
||||
* @return 定制标签列表
|
||||
*/
|
||||
List<CustomTagDO> getCustomTagListByType(String type);
|
||||
|
||||
}
|
||||
@@ -82,4 +82,9 @@ public class CustomTagServiceImpl implements CustomTagService {
|
||||
return customTagMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CustomTagDO> getCustomTagListByType(String type) {
|
||||
return customTagMapper.selectListByType(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.mysql.tag.TagMapper;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.ydoyun.enums.ErrorCodeConstants.TAG_NAME_DUPLICATE;
|
||||
import static cn.iocoder.yudao.module.ydoyun.enums.ErrorCodeConstants.TAG_NOT_EXISTS;
|
||||
|
||||
@Service
|
||||
@@ -21,6 +22,7 @@ public class TagServiceImpl implements TagService {
|
||||
|
||||
@Override
|
||||
public Long createTag(TagSaveReqVO createReqVO) {
|
||||
validateTagNameUnique(createReqVO.getName(), createReqVO.getType(), null);
|
||||
TagDO tag = BeanUtils.toBean(createReqVO, TagDO.class);
|
||||
tagMapper.insert(tag);
|
||||
return tag.getId();
|
||||
@@ -29,10 +31,19 @@ public class TagServiceImpl implements TagService {
|
||||
@Override
|
||||
public void updateTag(TagSaveReqVO updateReqVO) {
|
||||
validateTagExists(updateReqVO.getId());
|
||||
validateTagNameUnique(updateReqVO.getName(), updateReqVO.getType(), updateReqVO.getId());
|
||||
TagDO updateObj = BeanUtils.toBean(updateReqVO, TagDO.class);
|
||||
tagMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
private void validateTagNameUnique(String name, String type, Long excludeId) {
|
||||
if (name == null || type == null) return;
|
||||
TagDO existing = tagMapper.selectByNameAndType(name, type);
|
||||
if (existing != null && (excludeId == null || !existing.getId().equals(excludeId))) {
|
||||
throw exception(TAG_NAME_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTag(Long id) {
|
||||
validateTagExists(id);
|
||||
|
||||
@@ -19,4 +19,5 @@ public interface TagConfigService {
|
||||
PageResult<TagConfigDO> getTagConfigPage(TagConfigPageReqVO pageReqVO);
|
||||
void saveAll(@Valid TagConfigSaveAllReqVO reqVO);
|
||||
void manualSync(Long tagConfigId);
|
||||
void initTagTables(Long databaseId);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package cn.iocoder.yudao.module.ydoyun.service.tagconfig;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.module.ydoyun.config.ProcedureHttpClient;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.dataobject.reportdatabase.ReportDatabaseDO;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.dataobject.customtag.CustomTagDO;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.dataobject.tag.TagDO;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.dataobject.tagsyncdetail.TagSyncDetailDO;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.mysql.reportdatabase.ReportDatabaseMapper;
|
||||
import cn.iocoder.yudao.module.ydoyun.service.tagsyncdetail.TagSyncDetailService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -13,11 +21,14 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.mysql.tagconfig.TagConfigMapper;
|
||||
import cn.iocoder.yudao.module.ydoyun.dal.mysql.tagsynchistory.TagSyncHistoryMapper;
|
||||
import cn.iocoder.yudao.module.ydoyun.service.customtag.CustomTagService;
|
||||
import cn.iocoder.yudao.module.ydoyun.service.tag.TagService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.ydoyun.enums.ErrorCodeConstants.TAG_CONFIG_DATABASE_REQUIRED;
|
||||
import static cn.iocoder.yudao.module.ydoyun.enums.ErrorCodeConstants.TAG_CONFIG_NOT_EXISTS;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Validated
|
||||
public class TagConfigServiceImpl implements TagConfigService {
|
||||
@@ -31,6 +42,18 @@ public class TagConfigServiceImpl implements TagConfigService {
|
||||
@Resource
|
||||
private TagService tagService;
|
||||
|
||||
@Resource
|
||||
private ReportDatabaseMapper reportDatabaseMapper;
|
||||
|
||||
@Resource
|
||||
private ProcedureHttpClient httpClient;
|
||||
|
||||
@Resource
|
||||
private TagSyncDetailService tagSyncDetailService;
|
||||
|
||||
@Resource
|
||||
private CustomTagService customTagService;
|
||||
|
||||
@Override
|
||||
public Long createTagConfig(TagConfigSaveReqVO createReqVO) {
|
||||
TagConfigDO tagConfig = BeanUtils.toBean(createReqVO, TagConfigDO.class);
|
||||
@@ -120,19 +143,176 @@ public class TagConfigServiceImpl implements TagConfigService {
|
||||
public void manualSync(Long tagConfigId) {
|
||||
validateTagConfigExists(tagConfigId);
|
||||
TagConfigDO config = tagConfigMapper.selectById(tagConfigId);
|
||||
if (config.getDatabaseId() == null) {
|
||||
throw exception(TAG_CONFIG_DATABASE_REQUIRED);
|
||||
}
|
||||
ReportDatabaseDO reportDatabase = reportDatabaseMapper.selectById(config.getDatabaseId());
|
||||
if (reportDatabase == null) {
|
||||
throw exception(TAG_CONFIG_DATABASE_REQUIRED);
|
||||
}
|
||||
|
||||
// 0. 先执行初始化标签库(删除并重建四张表)
|
||||
initTagTables(config.getDatabaseId());
|
||||
|
||||
// 1. 收集标准标签的拼接好的脚本,过滤掉空的
|
||||
List<TagDO> tagsWithScript = new ArrayList<>();
|
||||
for (String type : Arrays.asList("product", "store", "supplier", "member")) {
|
||||
List<TagDO> list = tagService.getTagListByType(type);
|
||||
for (TagDO tag : list) {
|
||||
String sql = tag.getSqlScriptResolved();
|
||||
if (StrUtil.isNotBlank(sql) && sql.trim().length() > 0) {
|
||||
tagsWithScript.add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1.1 收集定制标签(按类型,仅 useParams=false 的参与同步)
|
||||
List<CustomTagDO> customTagsWithScript = new ArrayList<>();
|
||||
for (String type : Arrays.asList("product", "store", "supplier", "member")) {
|
||||
List<CustomTagDO> customList = customTagService.getCustomTagListByType(type);
|
||||
for (CustomTagDO ct : customList) {
|
||||
if (Boolean.TRUE.equals(ct.getUseParams())) {
|
||||
continue; // 代入参数的定制标签在报表运行时执行,不同步
|
||||
}
|
||||
String sql = ct.getSqlScript();
|
||||
if (StrUtil.isNotBlank(sql) && sql.trim().length() > 0) {
|
||||
customTagsWithScript.add(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int totalTagCount = tagsWithScript.size() + customTagsWithScript.size();
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
TagSyncHistoryDO history = TagSyncHistoryDO.builder()
|
||||
.tagConfigId(tagConfigId)
|
||||
.syncType("manual")
|
||||
.syncTime(now)
|
||||
.syncStatus("success")
|
||||
.totalCount(0)
|
||||
.totalCount(totalTagCount)
|
||||
.successCount(0)
|
||||
.failCount(0)
|
||||
.recordCount(0L)
|
||||
.build();
|
||||
tagSyncHistoryMapper.insert(history);
|
||||
|
||||
List<TagSyncDetailDO> detailList = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
long totalRecordCount = 0L;
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
|
||||
// 2. 循环调用 postExecuteSql 执行每个脚本
|
||||
for (int i = 0; i < tagsWithScript.size(); i++) {
|
||||
TagDO tag = tagsWithScript.get(i);
|
||||
String sql = tag.getSqlScriptResolved().trim();
|
||||
TagSyncDetailDO detail = TagSyncDetailDO.builder()
|
||||
.syncHistoryId(history.getId())
|
||||
.tagId(tag.getId())
|
||||
.tagName(tag.getName())
|
||||
.tagType(tag.getType())
|
||||
.sqlExecuted(sql)
|
||||
.execOrder(i + 1)
|
||||
.build();
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>(4);
|
||||
params.put("reportDatabase", reportDatabase);
|
||||
params.put("sql", sql);
|
||||
httpClient.postExecuteSql(params);
|
||||
detail.setExecStatus("success");
|
||||
detail.setRecordCount(0L);
|
||||
successCount++;
|
||||
detailList.add(detail);
|
||||
} catch (Exception e) {
|
||||
log.error("标签同步执行失败 tagId={} name={}", tag.getId(), tag.getName(), e);
|
||||
detail.setExecStatus("fail");
|
||||
detail.setErrorMessage(e.getMessage());
|
||||
failCount++;
|
||||
errorMessages.add(tag.getName() + ": " + e.getMessage());
|
||||
detailList.add(detail);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 执行定制标签 SQL(按类型)
|
||||
int execOrderOffset = tagsWithScript.size();
|
||||
for (int i = 0; i < customTagsWithScript.size(); i++) {
|
||||
CustomTagDO ct = customTagsWithScript.get(i);
|
||||
String sql = ct.getSqlScript().trim();
|
||||
TagSyncDetailDO detail = TagSyncDetailDO.builder()
|
||||
.syncHistoryId(history.getId())
|
||||
.tagId(ct.getId())
|
||||
.tagName("[定制]" + ct.getName())
|
||||
.tagType(ct.getType())
|
||||
.sqlExecuted(sql)
|
||||
.execOrder(execOrderOffset + i + 1)
|
||||
.build();
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>(4);
|
||||
params.put("reportDatabase", reportDatabase);
|
||||
params.put("sql", sql);
|
||||
httpClient.postExecuteSql(params);
|
||||
detail.setExecStatus("success");
|
||||
detail.setRecordCount(0L);
|
||||
successCount++;
|
||||
detailList.add(detail);
|
||||
} catch (Exception e) {
|
||||
log.error("定制标签同步执行失败 customTagId={} name={}", ct.getId(), ct.getName(), e);
|
||||
detail.setExecStatus("fail");
|
||||
detail.setErrorMessage(e.getMessage());
|
||||
failCount++;
|
||||
errorMessages.add("[定制]" + ct.getName() + ": " + e.getMessage());
|
||||
detailList.add(detail);
|
||||
}
|
||||
}
|
||||
|
||||
tagSyncDetailService.insertBatch(detailList);
|
||||
|
||||
history.setSuccessCount(successCount);
|
||||
history.setFailCount(failCount);
|
||||
history.setRecordCount(totalRecordCount);
|
||||
history.setSyncStatus(failCount > 0 ? (successCount > 0 ? "partial" : "fail") : "success");
|
||||
if (!errorMessages.isEmpty()) {
|
||||
history.setErrorMessage(String.join("; ", errorMessages));
|
||||
}
|
||||
tagSyncHistoryMapper.updateById(history);
|
||||
|
||||
config.setLastSyncTime(now);
|
||||
tagConfigMapper.updateById(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initTagTables(Long databaseId) {
|
||||
if (databaseId == null) {
|
||||
throw exception(TAG_CONFIG_DATABASE_REQUIRED);
|
||||
}
|
||||
ReportDatabaseDO reportDatabase = reportDatabaseMapper.selectById(databaseId);
|
||||
if (reportDatabase == null) {
|
||||
throw exception(TAG_CONFIG_DATABASE_REQUIRED);
|
||||
}
|
||||
|
||||
// SQL Server 语法:先删除再创建(不记录同步历史),color 用于保存标签颜色
|
||||
String[][] tableDdl = {
|
||||
{"ydoyun_tag_product", "CREATE TABLE ydoyun_tag_product (id BIGINT IDENTITY(1,1) PRIMARY KEY, code NVARCHAR(64) NOT NULL, name NVARCHAR(128) NOT NULL, color NVARCHAR(32) NULL, create_time DATETIME NOT NULL DEFAULT GETDATE())"},
|
||||
{"ydoyun_tag_supplier", "CREATE TABLE ydoyun_tag_supplier (id BIGINT IDENTITY(1,1) PRIMARY KEY, code NVARCHAR(64) NOT NULL, name NVARCHAR(128) NOT NULL, color NVARCHAR(32) NULL, create_time DATETIME NOT NULL DEFAULT GETDATE())"},
|
||||
{"ydoyun_tag_store", "CREATE TABLE ydoyun_tag_store (id BIGINT IDENTITY(1,1) PRIMARY KEY, code NVARCHAR(64) NOT NULL, name NVARCHAR(128) NOT NULL, color NVARCHAR(32) NULL, create_time DATETIME NOT NULL DEFAULT GETDATE())"},
|
||||
{"ydoyun_tag_member", "CREATE TABLE ydoyun_tag_member (id BIGINT IDENTITY(1,1) PRIMARY KEY, code NVARCHAR(64) NOT NULL, name NVARCHAR(128) NOT NULL, color NVARCHAR(32) NULL, create_time DATETIME NOT NULL DEFAULT GETDATE())"}
|
||||
};
|
||||
|
||||
for (String[] pair : tableDdl) {
|
||||
String tableName = pair[0];
|
||||
String createSql = pair[1];
|
||||
try {
|
||||
Map<String, Object> dropParams = new HashMap<>(4);
|
||||
dropParams.put("reportDatabase", reportDatabase);
|
||||
dropParams.put("sql", "DROP TABLE IF EXISTS " + tableName);
|
||||
httpClient.postExecuteSql(dropParams);
|
||||
} catch (Exception e) {
|
||||
log.warn("删除表 {} 时忽略错误(可能表不存在): {}", tableName, e.getMessage());
|
||||
}
|
||||
Map<String, Object> createParams = new HashMap<>(4);
|
||||
createParams.put("reportDatabase", reportDatabase);
|
||||
createParams.put("sql", createSql);
|
||||
httpClient.postExecuteSql(createParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user