Prepare chart business block generation
This commit is contained in:
@@ -6,6 +6,10 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.generator.domain.GenProject;
|
||||
@@ -18,8 +22,11 @@ import com.ruoyi.generator.domain.front.dto.block.BusinessBlockConfigField;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockDefinition;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockInstance;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockTemplateFile;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartQueryRenderModel;
|
||||
import com.ruoyi.generator.domain.front.dto.block.PageBusinessBlockLayout;
|
||||
import com.ruoyi.generator.service.front.BusinessBlockRegistryService;
|
||||
import com.ruoyi.generator.util.BusinessActionRenderSupport;
|
||||
import com.ruoyi.generator.util.ChartBlockRenderSupport;
|
||||
import com.ruoyi.generator.util.VelocityInitializer;
|
||||
import com.ruoyi.generator.util.VelocityUtils;
|
||||
import org.apache.velocity.Template;
|
||||
@@ -35,10 +42,15 @@ public class BusinessBlockGenerationService
|
||||
private static final String FRONTEND_PAGE_TEMPLATE_RESOURCE = "qing/index.vue.vm";
|
||||
private static final String BUSINESS_BLOCK_CATEGORY_PREFIX = "business-block:";
|
||||
private static final String PAGE_DESIGN_CATEGORY_PREFIX = "page-design:";
|
||||
private static final Pattern STATUS_VALUE_PATTERN = Pattern.compile(
|
||||
"([0-9]+)\\s*[=::]?\\s*([^A-Za-z0-9_\\s,,;;()()]+)");
|
||||
|
||||
@Autowired
|
||||
private BusinessBlockRegistryService businessBlockRegistryService;
|
||||
|
||||
@Autowired
|
||||
private ChartBlockRenderSupport chartBlockRenderSupport;
|
||||
|
||||
public List<GeneratedBusinessBlockFile> listFiles(GenProject project, String templateType)
|
||||
{
|
||||
if (project == null || StringUtils.isEmpty(project.getPageDesigns()))
|
||||
@@ -46,35 +58,48 @@ public class BusinessBlockGenerationService
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<GeneratedBusinessBlockFile> files = new ArrayList<GeneratedBusinessBlockFile>();
|
||||
Set<String> emittedSharedOutputs = new HashSet<String>();
|
||||
for (FrontProjectPageDesign pageDesign : project.getPageDesigns())
|
||||
{
|
||||
if (pageDesign == null || "admin".equals(pageDesign.getPageScope()))
|
||||
if (pageDesign == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
boolean adminScope = "admin".equals(pageDesign.getPageScope());
|
||||
if ("frontend".equals(templateType) && adminScope)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ("admin_frontend".equals(templateType) && !adminScope)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int index = 1;
|
||||
if (isFrontendBusinessBlockPage(pageDesign))
|
||||
if (isBusinessBlockPage(pageDesign))
|
||||
{
|
||||
PageBusinessBlockLayout layout = registry().parseLayout(pageDesign.getLayoutJson());
|
||||
if (BusinessBlockRegistryService.BUSINESS_BLOCK_CANVAS.equals(layout.getCanvas()))
|
||||
{
|
||||
if ("frontend".equals(templateType))
|
||||
if ("frontend".equals(templateType) || "admin_frontend".equals(templateType))
|
||||
{
|
||||
files.add(pageFile(pageDesign));
|
||||
files.add(pageFile(pageDesign, templateType));
|
||||
}
|
||||
index = appendBlockFiles(files, project, pageDesign, safeBlocks(layout), templateType, index);
|
||||
index = appendBlockFiles(files, emittedSharedOutputs, project, pageDesign,
|
||||
safeBlocks(layout), templateType, index);
|
||||
}
|
||||
}
|
||||
else if ("frontend".equals(templateType) && isFrontendDesignedPage(pageDesign))
|
||||
{
|
||||
files.add(frontendPageFile(pageDesign));
|
||||
}
|
||||
appendBlockFiles(files, project, pageDesign, embeddedBlocks(pageDesign), templateType, index);
|
||||
appendBlockFiles(files, emittedSharedOutputs, project, pageDesign,
|
||||
embeddedBlocks(pageDesign), templateType, index);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private int appendBlockFiles(List<GeneratedBusinessBlockFile> files, GenProject project,
|
||||
private int appendBlockFiles(List<GeneratedBusinessBlockFile> files, Set<String> emittedSharedOutputs,
|
||||
GenProject project,
|
||||
FrontProjectPageDesign pageDesign, List<BusinessBlockInstance> instances, String templateType, int startIndex)
|
||||
{
|
||||
int index = startIndex;
|
||||
@@ -89,10 +114,13 @@ public class BusinessBlockGenerationService
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ("admin_frontend".equals(templateType) && isChartDefinition(definition))
|
||||
{
|
||||
addSharedChartRuntime(files, emittedSharedOutputs);
|
||||
}
|
||||
for (BusinessBlockTemplateFile templateFile : definition.getTemplates())
|
||||
{
|
||||
String fileTemplateType = templateType(templateFile);
|
||||
if (!StringUtils.equals(fileTemplateType, templateType))
|
||||
if (!templateMatches(templateType, templateFile))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -103,6 +131,22 @@ public class BusinessBlockGenerationService
|
||||
return index;
|
||||
}
|
||||
|
||||
private void addSharedChartRuntime(List<GeneratedBusinessBlockFile> files, Set<String> emittedSharedOutputs)
|
||||
{
|
||||
String outputPath = "src/utils/chartRuntime.js";
|
||||
if (!emittedSharedOutputs.add(outputPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
GeneratedBusinessBlockFile file = new GeneratedBusinessBlockFile();
|
||||
file.setCategory("business-block:admin_frontend:shared:chartRuntime");
|
||||
file.setTemplateType("admin_frontend");
|
||||
file.setOutputPath(outputPath);
|
||||
file.setTemplateResource("business-blocks/chart/templates/frontend/chartRuntime.js.vm");
|
||||
file.setTemplateKey("chartRuntime");
|
||||
files.add(file);
|
||||
}
|
||||
|
||||
public GeneratedBusinessBlockFile findFile(GenProject project, String templateType, String keyword)
|
||||
{
|
||||
if (StringUtils.isEmpty(keyword))
|
||||
@@ -194,10 +238,14 @@ public class BusinessBlockGenerationService
|
||||
{
|
||||
List<BusinessActionDesign> candidates = project == null || StringUtils.isEmpty(project.getBusinessActions())
|
||||
? Collections.<BusinessActionDesign>emptyList() : project.getBusinessActions();
|
||||
FrontProjectPageDesign currentPageDesign = context.get("currentPageDesign") instanceof FrontProjectPageDesign
|
||||
? (FrontProjectPageDesign) context.get("currentPageDesign") : null;
|
||||
List<BusinessActionDesign> toolbarBusinessActions = filterPageDesignBusinessActions(
|
||||
candidates, context.get("pageDesignToolbarActionCodes"));
|
||||
candidates, context.get("pageDesignToolbarActionCodes"), currentPageDesign, "primary",
|
||||
project == null ? null : project.getTables());
|
||||
List<BusinessActionDesign> rowBusinessActions = filterPageDesignBusinessActions(
|
||||
candidates, context.get("pageDesignRowActionCodes"));
|
||||
candidates, context.get("pageDesignRowActionCodes"), currentPageDesign, "text",
|
||||
project == null ? null : project.getTables());
|
||||
List<BusinessActionDesign> allActions = mergeBusinessActions(toolbarBusinessActions, rowBusinessActions);
|
||||
context.put("pageDesignToolbarBusinessActions", toolbarBusinessActions);
|
||||
context.put("hasPageDesignToolbarBusinessActions", StringUtils.isNotEmpty(toolbarBusinessActions));
|
||||
@@ -209,7 +257,8 @@ public class BusinessBlockGenerationService
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<BusinessActionDesign> filterPageDesignBusinessActions(List<BusinessActionDesign> candidates,
|
||||
Object actionCodesObject)
|
||||
Object actionCodesObject, FrontProjectPageDesign pageDesign, String fallbackButtonType,
|
||||
List<GenTable> projectTables)
|
||||
{
|
||||
if (StringUtils.isEmpty(candidates) || !(actionCodesObject instanceof List))
|
||||
{
|
||||
@@ -229,20 +278,82 @@ public class BusinessBlockGenerationService
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<BusinessActionDesign> result = new ArrayList<BusinessActionDesign>();
|
||||
Set<String> addedCodes = new HashSet<String>();
|
||||
for (String requestedCode : requestedCodes)
|
||||
{
|
||||
for (BusinessActionDesign candidate : candidates)
|
||||
{
|
||||
if (candidate != null && StringUtils.equals(requestedCode, candidate.getCode())
|
||||
&& !result.contains(candidate))
|
||||
&& addedCodes.add(candidate.getCode()))
|
||||
{
|
||||
result.add(candidate);
|
||||
result.add(applyBusinessButtonConfig(candidate, pageDesign, fallbackButtonType, projectTables));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private BusinessActionDesign applyBusinessButtonConfig(BusinessActionDesign source, FrontProjectPageDesign pageDesign,
|
||||
String fallbackButtonType, List<GenTable> projectTables)
|
||||
{
|
||||
BusinessActionDesign action = copyBusinessAction(source);
|
||||
Map<String, Object> config = businessButtonConfig(pageDesign, action.getCode());
|
||||
action.setButtonLabel(stringConfig(config, "label", action.getName()));
|
||||
action.setButtonType(stringConfig(config, "type", fallbackButtonType));
|
||||
action.setButtonIcon(stringConfig(config, "icon", "el-icon-position"));
|
||||
action.setConfirmMessage(stringConfig(config, "confirmMessage", ""));
|
||||
action.setSuccessMessage(stringConfig(config, "successMessage",
|
||||
StringUtils.defaultIfEmpty(action.getName(), action.getCode()) + "成功"));
|
||||
action.setRefreshTarget(stringConfig(config, "refreshTarget", "list"));
|
||||
BusinessActionRenderSupport.enrich(action, projectTables);
|
||||
return action;
|
||||
}
|
||||
|
||||
private BusinessActionDesign copyBusinessAction(BusinessActionDesign source)
|
||||
{
|
||||
BusinessActionDesign copy = new BusinessActionDesign();
|
||||
copy.setCode(source.getCode());
|
||||
copy.setName(source.getName());
|
||||
copy.setOwnerTable(source.getOwnerTable());
|
||||
copy.setMethod(source.getMethod());
|
||||
copy.setPath(source.getPath());
|
||||
copy.setTransaction(source.getTransaction());
|
||||
copy.setRequestFields(source.getRequestFields());
|
||||
copy.setRules(source.getRules());
|
||||
copy.setRuleChecks(source.getRuleChecks());
|
||||
copy.setEffects(source.getEffects());
|
||||
copy.setUiBindings(source.getUiBindings());
|
||||
copy.setCurrentUserFields(source.getCurrentUserFields());
|
||||
copy.setInputFields(source.getInputFields());
|
||||
return copy;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> businessButtonConfig(FrontProjectPageDesign pageDesign, String actionCode)
|
||||
{
|
||||
if (pageDesign == null || pageDesign.getLayout() == null || StringUtils.isEmpty(actionCode))
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Object configs = pageDesign.getLayout().get("businessButtons");
|
||||
if (!(configs instanceof Map))
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Object config = ((Map<String, Object>) configs).get(actionCode);
|
||||
return config instanceof Map ? (Map<String, Object>) config : Collections.<String, Object>emptyMap();
|
||||
}
|
||||
|
||||
private String stringConfig(Map<String, Object> config, String key, String fallback)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
Object value = config.get(key);
|
||||
return value == null || StringUtils.isEmpty(String.valueOf(value)) ? fallback : String.valueOf(value);
|
||||
}
|
||||
|
||||
private List<BusinessActionDesign> mergeBusinessActions(List<BusinessActionDesign> first,
|
||||
List<BusinessActionDesign> second)
|
||||
{
|
||||
@@ -265,11 +376,17 @@ public class BusinessBlockGenerationService
|
||||
}
|
||||
|
||||
private GeneratedBusinessBlockFile pageFile(FrontProjectPageDesign pageDesign)
|
||||
{
|
||||
return pageFile(pageDesign, "admin".equals(pageDesign == null ? null : pageDesign.getPageScope())
|
||||
? "admin_frontend" : "frontend");
|
||||
}
|
||||
|
||||
private GeneratedBusinessBlockFile pageFile(FrontProjectPageDesign pageDesign, String templateType)
|
||||
{
|
||||
GeneratedBusinessBlockFile file = new GeneratedBusinessBlockFile();
|
||||
String pageCode = safePageCode(pageDesign);
|
||||
file.setCategory(BUSINESS_BLOCK_CATEGORY_PREFIX + "frontend:" + pageCode + ":page");
|
||||
file.setTemplateType("frontend");
|
||||
file.setCategory(BUSINESS_BLOCK_CATEGORY_PREFIX + templateType + ":" + pageCode + ":page");
|
||||
file.setTemplateType(templateType);
|
||||
file.setOutputPath("src/views/pages/" + pageCode + "/index.vue");
|
||||
file.setTemplateResource(PAGE_TEMPLATE_RESOURCE);
|
||||
file.setPageCode(pageCode);
|
||||
@@ -307,7 +424,7 @@ public class BusinessBlockGenerationService
|
||||
file.setTemplateType(fileTemplateType);
|
||||
file.setOutputPath(resolveOutputPath(project, pageCode, blockCode, instanceCode, instanceClassName,
|
||||
templateFile.getOutputPath()));
|
||||
file.setTemplateResource("business-blocks/" + blockCode + "/" + normalizePath(templateFile.getTemplate()));
|
||||
file.setTemplateResource(templateResource(blockCode, templateFile.getTemplate()));
|
||||
file.setPageCode(pageCode);
|
||||
file.setBlockCode(blockCode);
|
||||
file.setInstanceCode(instanceCode);
|
||||
@@ -348,6 +465,16 @@ public class BusinessBlockGenerationService
|
||||
context.put("instanceClassName", StringUtils.uncapitalize(file.getInstanceClassName()));
|
||||
context.put("apiBasePath", "/business-blocks/" + file.getInstanceCode());
|
||||
context.put("apiModulePath", "@/api/business-blocks/" + file.getInstanceCode());
|
||||
if (isChartDefinition(file.getDefinition()))
|
||||
{
|
||||
ChartQueryRenderModel chartQuery = chartRenderSupport().build(
|
||||
requireTable(project, instance.getDataset().getTable()), file.getDefinition(), instance);
|
||||
context.put("chartQuery", chartQuery);
|
||||
context.put("chartType", file.getDefinition().getChartType());
|
||||
context.put("chartDataset", instance.getDataset());
|
||||
context.put("chartDisplay", instance.getDisplay());
|
||||
context.put("apiBasePath", "/admin/business-blocks/" + file.getInstanceCode());
|
||||
}
|
||||
context.put("cartPkColumn", pkColumnName(project, renderConfig.get("cartTable")));
|
||||
context.put("noticePkColumn", pkColumnName(project, renderConfig.get("noticeTable")));
|
||||
context.put("carouselPkColumn", pkColumnName(project, renderConfig.get("carouselTable")));
|
||||
@@ -359,6 +486,8 @@ public class BusinessBlockGenerationService
|
||||
context.put("hasProductImage", StringUtils.isNotEmpty(renderConfig.get("productImage")));
|
||||
context.put("hasStock", StringUtils.isNotEmpty(renderConfig.get("stock")));
|
||||
context.put("hasNoticeStatus", StringUtils.isNotEmpty(renderConfig.get("status")));
|
||||
context.put("noticeStatusActiveValue", activeStatusValue(project, renderConfig.get("noticeTable"),
|
||||
renderConfig.get("status"), "0"));
|
||||
context.put("hasNoticePublishTime", StringUtils.isNotEmpty(renderConfig.get("publishTime")));
|
||||
context.put("hasCarouselLink", StringUtils.isNotEmpty(renderConfig.get("link")));
|
||||
context.put("hasCarouselSort", StringUtils.isNotEmpty(renderConfig.get("sort")));
|
||||
@@ -464,6 +593,7 @@ public class BusinessBlockGenerationService
|
||||
block.put("instanceCode", blockFile.getInstanceCode());
|
||||
block.put("blockCode", blockFile.getBlockCode());
|
||||
block.put("name", StringUtils.defaultIfEmpty(instance.getName(), definition.getName()));
|
||||
block.put("span", instance.getSpan() == null ? Integer.valueOf(12) : instance.getSpan());
|
||||
blocks.add(block);
|
||||
index++;
|
||||
}
|
||||
@@ -523,12 +653,46 @@ public class BusinessBlockGenerationService
|
||||
return "backend";
|
||||
}
|
||||
|
||||
private boolean templateMatches(String requestedType, BusinessBlockTemplateFile templateFile)
|
||||
{
|
||||
String fileType = templateType(templateFile);
|
||||
if ("admin_frontend".equals(requestedType))
|
||||
{
|
||||
return "frontend".equals(fileType);
|
||||
}
|
||||
return StringUtils.equals(requestedType, fileType);
|
||||
}
|
||||
|
||||
private String templateResource(String blockCode, String template)
|
||||
{
|
||||
String normalized = normalizePath(template);
|
||||
if (normalized.startsWith("/"))
|
||||
{
|
||||
return normalized.substring(1);
|
||||
}
|
||||
return "business-blocks/" + blockCode + "/" + normalized;
|
||||
}
|
||||
|
||||
private boolean isChartDefinition(BusinessBlockDefinition definition)
|
||||
{
|
||||
return definition != null && "chart".equals(definition.getKind());
|
||||
}
|
||||
|
||||
private boolean isFrontendBusinessBlockPage(FrontProjectPageDesign pageDesign)
|
||||
{
|
||||
if (pageDesign == null || "admin".equals(pageDesign.getPageScope()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return isBusinessBlockPage(pageDesign);
|
||||
}
|
||||
|
||||
private boolean isBusinessBlockPage(FrontProjectPageDesign pageDesign)
|
||||
{
|
||||
if (pageDesign == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ("business_block".equals(pageDesign.getPageType()))
|
||||
{
|
||||
return true;
|
||||
@@ -662,6 +826,59 @@ public class BusinessBlockGenerationService
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
private String activeStatusValue(GenProject project, String tableName, String statusColumnName, String defaultValue)
|
||||
{
|
||||
GenTableColumn column = findColumn(project, tableName, statusColumnName);
|
||||
if (column == null || StringUtils.isEmpty(column.getColumnComment()))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
Matcher matcher = STATUS_VALUE_PATTERN.matcher(column.getColumnComment());
|
||||
while (matcher.find())
|
||||
{
|
||||
String value = matcher.group(1);
|
||||
String label = matcher.group(2);
|
||||
if (isActiveStatusLabel(label) && !isInactiveStatusLabel(label))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private boolean isActiveStatusLabel(String label)
|
||||
{
|
||||
return StringUtils.containsAny(label, "发布", "启用", "上架", "正常", "可用", "有效", "显示");
|
||||
}
|
||||
|
||||
private boolean isInactiveStatusLabel(String label)
|
||||
{
|
||||
return StringUtils.containsAny(label, "未发布", "草稿", "下架", "关闭", "禁用", "停用", "暂停", "删除", "失效",
|
||||
"不显示");
|
||||
}
|
||||
|
||||
private GenTableColumn findColumn(GenProject project, String tableName, String columnName)
|
||||
{
|
||||
GenTable table = findTable(project, tableName);
|
||||
if (table == null || StringUtils.isEmpty(table.getColumns()) || StringUtils.isEmpty(columnName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
for (GenTableColumn column : table.getColumns())
|
||||
{
|
||||
if (column == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.equals(columnName, column.getColumnName())
|
||||
|| StringUtils.equals(columnName, column.getJavaField()))
|
||||
{
|
||||
return column;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private GenTable findTable(GenProject project, String tableName)
|
||||
{
|
||||
if (project == null || StringUtils.isEmpty(project.getTables()) || StringUtils.isEmpty(tableName))
|
||||
@@ -678,6 +895,16 @@ public class BusinessBlockGenerationService
|
||||
return null;
|
||||
}
|
||||
|
||||
private GenTable requireTable(GenProject project, String tableName)
|
||||
{
|
||||
GenTable table = findTable(project, tableName);
|
||||
if (table == null)
|
||||
{
|
||||
throw new ServiceException("图表数据表不存在:" + StringUtils.defaultString(tableName));
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private String relativeImportPath(String fromDir, String targetPath)
|
||||
{
|
||||
String[] from = normalizePath(fromDir).split("/");
|
||||
@@ -756,4 +983,13 @@ public class BusinessBlockGenerationService
|
||||
}
|
||||
return businessBlockRegistryService;
|
||||
}
|
||||
|
||||
private ChartBlockRenderSupport chartRenderSupport()
|
||||
{
|
||||
if (chartBlockRenderSupport == null)
|
||||
{
|
||||
chartBlockRenderSupport = new ChartBlockRenderSupport();
|
||||
}
|
||||
return chartBlockRenderSupport;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.ruoyi.generator.service;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
@@ -15,6 +18,9 @@ import com.ruoyi.generator.domain.GenTable;
|
||||
import com.ruoyi.generator.domain.GenTableColumn;
|
||||
import com.ruoyi.generator.domain.GeneratedBusinessBlockFile;
|
||||
import com.ruoyi.generator.domain.front.FrontProjectPageDesign;
|
||||
import com.ruoyi.generator.domain.front.dto.BusinessActionDesign;
|
||||
import com.ruoyi.generator.domain.front.dto.BusinessActionEffectDesign;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartQueryRenderModel;
|
||||
import com.ruoyi.generator.service.front.BusinessBlockRegistryService;
|
||||
|
||||
public class BusinessBlockGenerationServiceTest
|
||||
@@ -72,6 +78,7 @@ public class BusinessBlockGenerationServiceTest
|
||||
assertTrue(pageContent.contains("<Cart001Block />"));
|
||||
assertTrue(blockContent.contains("listCart001BlockItems"));
|
||||
assertTrue(blockContent.contains("@/api/business-blocks/cart_001"));
|
||||
assertTrue(apiContent.contains("import request from \"@/api/request\""));
|
||||
assertTrue(apiContent.contains("url: \"/business-blocks/cart_001/\" + id + \"/quantity\""));
|
||||
assertTrue(apiContent.contains("url: \"/business-blocks/cart_001/\" + id"));
|
||||
assertTrue(controllerContent.contains("class Cart001BlockController"));
|
||||
@@ -113,6 +120,8 @@ public class BusinessBlockGenerationServiceTest
|
||||
GenProject project = businessBlocksProject();
|
||||
String noticeMapper = service.renderFile(project, findPath(service.listFiles(project, "backend"),
|
||||
"src/main/resources/mapper/block/Notice001BlockMapper.xml"));
|
||||
String carouselMapper = service.renderFile(project, findPath(service.listFiles(project, "backend"),
|
||||
"src/main/resources/mapper/block/Carousel001BlockMapper.xml"));
|
||||
String carouselComponent = service.renderFile(project, findPath(service.listFiles(project, "frontend"),
|
||||
"src/views/pages/business_page/blocks/carousel_001/CarouselBlock.vue"));
|
||||
String orderMapper = service.renderFile(project, findPath(service.listFiles(project, "backend"),
|
||||
@@ -124,7 +133,10 @@ public class BusinessBlockGenerationServiceTest
|
||||
|
||||
assertTrue(noticeMapper.contains("from sys_notice n"));
|
||||
assertTrue(noticeMapper.contains("n.notice_title as title"));
|
||||
assertTrue(carouselMapper.contains("(b.status = '1' or b.status = 1)"));
|
||||
assertTrue(carouselComponent.contains("listCarousel001BlockCarouselItems"));
|
||||
assertTrue(carouselComponent.contains(":src=\"resolveResourceUrl(item.image)\""));
|
||||
assertTrue(carouselComponent.contains("return \"/api\" + url"));
|
||||
assertTrue(orderMapper.contains("insert into shop_order"));
|
||||
assertTrue(orderMapper.contains("left join shop_product p on i.product_id = p.id"));
|
||||
assertTrue(orderComponent.contains("this.$message.success(\"订单已提交\")"));
|
||||
@@ -132,6 +144,33 @@ public class BusinessBlockGenerationServiceTest
|
||||
assertTrue(masterDetailMapper.contains("where d.book_id = #{masterId}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderNoticeMapperUsesPublishedStatusValueFromStatusComment()
|
||||
{
|
||||
GenProject project = businessBlocksProject();
|
||||
findColumn(project, "sys_notice", "status").setColumnComment("状态(1发布 0草稿/下架)");
|
||||
|
||||
String noticeMapper = service.renderFile(project, findPath(service.listFiles(project, "backend"),
|
||||
"src/main/resources/mapper/block/Notice001BlockMapper.xml"));
|
||||
|
||||
assertTrue(noticeMapper.contains("where (n.status = '1' or n.status = 1)"));
|
||||
assertFalse(noticeMapper.contains("where (n.status = '0' or n.status = 0)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderedBackendBusinessBlockFilesDoNotDependOnRuoYiRuntime()
|
||||
{
|
||||
GenProject project = businessBlocksProject();
|
||||
List<GeneratedBusinessBlockFile> files = service.listFiles(project, "backend");
|
||||
|
||||
for (GeneratedBusinessBlockFile file : files)
|
||||
{
|
||||
String content = service.renderFile(project, file);
|
||||
|
||||
assertFalse(file.getOutputPath(), content.contains("com.ruoyi.common"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderFileRendersEveryBundledBusinessBlockFile()
|
||||
{
|
||||
@@ -187,6 +226,48 @@ public class BusinessBlockGenerationServiceTest
|
||||
assertEquals(Boolean.TRUE, context.get("hasPageDesignEmbeddedBusinessBlocks"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void pageDesignBusinessActionsIncludeRenderMetadata() throws Exception
|
||||
{
|
||||
GenProject project = new GenProject();
|
||||
GenTable book = table(301L, "library_book", "LibraryBook");
|
||||
GenTableColumn dueDate = column("due_date", "dueDate", "0");
|
||||
dueDate.setColumnComment("Due date");
|
||||
dueDate.setHtmlType("datetime");
|
||||
book.setColumns(Arrays.asList(column("id", "id", "1"), column("user_id", "userId", "0"), dueDate));
|
||||
project.setTables(Arrays.asList(book));
|
||||
|
||||
BusinessActionDesign action = new BusinessActionDesign();
|
||||
action.setCode("borrow_book");
|
||||
action.setName("Borrow");
|
||||
action.setOwnerTable("library_book");
|
||||
action.setRequestFields(Arrays.asList("id", "user_id", "due_date"));
|
||||
BusinessActionEffectDesign effect = new BusinessActionEffectDesign();
|
||||
Map<String, String> values = new LinkedHashMap<String, String>();
|
||||
values.put("user_id", "${current_user.id}");
|
||||
effect.setValues(values);
|
||||
action.setEffects(Arrays.asList(effect));
|
||||
project.setBusinessActions(Arrays.asList(action));
|
||||
|
||||
VelocityContext context = new VelocityContext();
|
||||
context.put("currentPageDesign", new FrontProjectPageDesign());
|
||||
context.put("pageDesignToolbarActionCodes", Arrays.asList("business:borrow_book"));
|
||||
context.put("pageDesignRowActionCodes", Arrays.asList());
|
||||
|
||||
Method method = BusinessBlockGenerationService.class.getDeclaredMethod(
|
||||
"putPageDesignBusinessActions", VelocityContext.class, GenProject.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(service, context, project);
|
||||
|
||||
List<BusinessActionDesign> actions =
|
||||
(List<BusinessActionDesign>) context.get("pageDesignBusinessActions");
|
||||
assertEquals(Arrays.asList("user_id"), actions.get(0).getCurrentUserFields());
|
||||
assertEquals("due_date", actions.get(0).getInputFields().get(1).getField());
|
||||
assertEquals("Due date", actions.get(0).getInputFields().get(1).getLabel());
|
||||
assertEquals("datetime", actions.get(0).getInputFields().get(1).getHtmlType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFileMatchesCategoryOrPath()
|
||||
{
|
||||
@@ -198,6 +279,71 @@ public class BusinessBlockGenerationServiceTest
|
||||
assertEquals(file.getCategory(), service.findFile(project, "frontend", file.getOutputPath()).getCategory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartBlockUsesSharedTemplatesAndAdminApiContext() throws Exception
|
||||
{
|
||||
GenProject project = chartProject();
|
||||
List<GeneratedBusinessBlockFile> files = service.listFiles(project, "admin_frontend");
|
||||
GeneratedBusinessBlockFile component = findBlockFile(
|
||||
files, "admin_line_chart_001", "frontendComponent");
|
||||
|
||||
assertEquals("business-blocks/chart/templates/frontend/AdminChartBlock.vue.vm",
|
||||
component.getTemplateResource());
|
||||
assertEquals(Integer.valueOf(6), component.getInstance().getSpan());
|
||||
|
||||
VelocityContext context = new VelocityContext();
|
||||
Method method = BusinessBlockGenerationService.class.getDeclaredMethod(
|
||||
"putFileContext", VelocityContext.class, GenProject.class, GeneratedBusinessBlockFile.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(service, context, project, component);
|
||||
|
||||
assertEquals("/admin/business-blocks/admin_line_chart_001", context.get("apiBasePath"));
|
||||
assertEquals("line", context.get("chartType"));
|
||||
ChartQueryRenderModel chartQuery = (ChartQueryRenderModel) context.get("chartQuery");
|
||||
assertEquals("DATE_FORMAT(t.create_time, '%Y-%m-%d')", chartQuery.getDimensionSql());
|
||||
assertTrue(chartQuery.getWhereSql().contains("t.status = #{filter0}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartProjectEmitsOneSharedRuntime()
|
||||
{
|
||||
List<GeneratedBusinessBlockFile> files = service.listFiles(chartProject(), "admin_frontend");
|
||||
|
||||
assertEquals(1, countOutput(files, "src/utils/chartRuntime.js"));
|
||||
GeneratedBusinessBlockFile runtime = findPath(files, "src/utils/chartRuntime.js");
|
||||
assertEquals("business-block:admin_frontend:shared:chartRuntime", runtime.getCategory());
|
||||
assertEquals("business-blocks/chart/templates/frontend/chartRuntime.js.vm",
|
||||
runtime.getTemplateResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adminChartGeneratesFrontendAndBackendFiles()
|
||||
{
|
||||
assertTrue(hasBlockFile(service.listFiles(chartProject(), "admin_frontend"),
|
||||
"admin_line_chart_001", "frontendComponent"));
|
||||
assertTrue(hasBlockFile(service.listFiles(chartProject(), "backend"),
|
||||
"admin_line_chart_001", "mapperXml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void chartPageViewModelExposesConfiguredSpan() throws Exception
|
||||
{
|
||||
GenProject project = chartProject();
|
||||
GeneratedBusinessBlockFile page = findPath(service.listFiles(project, "admin_frontend"),
|
||||
"src/views/pages/sales_dashboard/index.vue");
|
||||
VelocityContext context = new VelocityContext();
|
||||
Method method = BusinessBlockGenerationService.class.getDeclaredMethod(
|
||||
"putFileContext", VelocityContext.class, GenProject.class, GeneratedBusinessBlockFile.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(service, context, project, page);
|
||||
|
||||
List<Map<String, Object>> blocks = (List<Map<String, Object>>) context.get("businessBlocks");
|
||||
|
||||
assertEquals(Integer.valueOf(6), blocks.get(0).get("span"));
|
||||
assertEquals(Integer.valueOf(4), blocks.get(1).get("span"));
|
||||
}
|
||||
|
||||
private void setField(String name, Object value) throws Exception
|
||||
{
|
||||
Field field = BusinessBlockGenerationService.class.getDeclaredField(name);
|
||||
@@ -222,6 +368,44 @@ public class BusinessBlockGenerationServiceTest
|
||||
return null;
|
||||
}
|
||||
|
||||
private GeneratedBusinessBlockFile findBlockFile(List<GeneratedBusinessBlockFile> files,
|
||||
String instanceCode, String templateKey)
|
||||
{
|
||||
for (GeneratedBusinessBlockFile file : files)
|
||||
{
|
||||
if (instanceCode.equals(file.getInstanceCode()) && templateKey.equals(file.getTemplateKey()))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("Missing block file " + instanceCode + ":" + templateKey);
|
||||
}
|
||||
|
||||
private boolean hasBlockFile(List<GeneratedBusinessBlockFile> files, String instanceCode, String templateKey)
|
||||
{
|
||||
for (GeneratedBusinessBlockFile file : files)
|
||||
{
|
||||
if (instanceCode.equals(file.getInstanceCode()) && templateKey.equals(file.getTemplateKey()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int countOutput(List<GeneratedBusinessBlockFile> files, String outputPath)
|
||||
{
|
||||
int count = 0;
|
||||
for (GeneratedBusinessBlockFile file : files)
|
||||
{
|
||||
if (outputPath.equals(file.getOutputPath()))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void assertRenderedFiles(GenProject project, List<GeneratedBusinessBlockFile> files)
|
||||
{
|
||||
for (GeneratedBusinessBlockFile file : files)
|
||||
@@ -274,6 +458,18 @@ public class BusinessBlockGenerationServiceTest
|
||||
return project;
|
||||
}
|
||||
|
||||
private GenProject chartProject()
|
||||
{
|
||||
GenProject project = new GenProject();
|
||||
project.setProjectId(13L);
|
||||
project.setProjectName("ChartBlocks");
|
||||
project.setProjectFileName("chart-blocks");
|
||||
project.setPackageName("com.example.demo");
|
||||
project.setTables(Arrays.asList(orderTable()));
|
||||
project.setPageDesigns(Arrays.asList(chartPageDesign()));
|
||||
return project;
|
||||
}
|
||||
|
||||
private FrontProjectPageDesign cartPageDesign()
|
||||
{
|
||||
FrontProjectPageDesign design = new FrontProjectPageDesign();
|
||||
@@ -340,6 +536,30 @@ public class BusinessBlockGenerationServiceTest
|
||||
return design;
|
||||
}
|
||||
|
||||
private FrontProjectPageDesign chartPageDesign()
|
||||
{
|
||||
FrontProjectPageDesign design = new FrontProjectPageDesign();
|
||||
design.setPageCode("sales_dashboard");
|
||||
design.setPageName("Sales Dashboard");
|
||||
design.setPageScope("admin");
|
||||
design.setPageType("business_block");
|
||||
design.setRoutePath("/admin/sales-dashboard");
|
||||
design.setLayoutJson("{\"canvas\":\"business-blocks-v1\",\"blocks\":["
|
||||
+ "{\"id\":\"admin_line_chart_001\",\"blockCode\":\"admin_line_chart\",\"name\":\"Sales Trend\",\"span\":6,"
|
||||
+ "\"dataset\":{\"schema\":\"single-table-aggregate-v1\",\"table\":\"shop_order\","
|
||||
+ "\"dimension\":{\"field\":\"createTime\",\"timeUnit\":\"day\"},"
|
||||
+ "\"metrics\":[{\"field\":\"totalAmount\",\"aggregate\":\"sum\",\"alias\":\"salesAmount\",\"label\":\"Sales\"}],"
|
||||
+ "\"filters\":[{\"field\":\"status\",\"operator\":\"eq\",\"value\":\"PAID\"}],"
|
||||
+ "\"sort\":{\"by\":\"dimension\",\"order\":\"asc\"},\"limit\":100},"
|
||||
+ "\"display\":{\"title\":\"Sales Trend\",\"smooth\":true}},"
|
||||
+ "{\"id\":\"admin_metric_chart_001\",\"blockCode\":\"admin_metric_chart\",\"name\":\"Order Count\",\"span\":4,"
|
||||
+ "\"dataset\":{\"schema\":\"single-table-aggregate-v1\",\"table\":\"shop_order\","
|
||||
+ "\"metrics\":[{\"field\":\"id\",\"aggregate\":\"count\",\"alias\":\"orderCount\",\"label\":\"Orders\"}],"
|
||||
+ "\"filters\":[],\"limit\":1},\"display\":{\"title\":\"Order Count\"}}"
|
||||
+ "]}");
|
||||
return design;
|
||||
}
|
||||
|
||||
private GenTable cartTable()
|
||||
{
|
||||
GenTable table = table(201L, "shop_cart", "ShopCart");
|
||||
@@ -460,4 +680,23 @@ public class BusinessBlockGenerationServiceTest
|
||||
column.setIsPk(isPk);
|
||||
return column;
|
||||
}
|
||||
|
||||
private GenTableColumn findColumn(GenProject project, String tableName, String columnName)
|
||||
{
|
||||
for (GenTable table : project.getTables())
|
||||
{
|
||||
if (!tableName.equals(table.getTableName()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (GenTableColumn column : table.getColumns())
|
||||
{
|
||||
if (columnName.equals(column.getColumnName()))
|
||||
{
|
||||
return column;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new AssertionError("Missing column " + tableName + "." + columnName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user