feat(cms): 支持注册时选择初始化示例数据功能

- 在 CmsWebsite 实体添加 initDemoData 字段,支持标记是否初始化示例数据
- 根据 initDemoData 字段区分三种站点初始化流程:生成示例内容、空白骨架、克隆模板内容
- 新增 initDemoData 选中时的标准示例数据填充逻辑,包含导航栏目、关于我们单页、产品、案例和新闻资讯
- 保留历史默认行为,未传 initDemoData 时按模板克隆栏目与文章
- 删除历史复制栏目与文章业务,改用条件分支实现灵活初始化
- 详细实现示例数据的栏目构建、内容填充及关联逻辑,提升新站点用户体验
This commit is contained in:
2026-08-11 00:21:35 +08:00
parent 975ec6758b
commit babd3b5aa0
2 changed files with 237 additions and 55 deletions
@@ -117,6 +117,10 @@ public class CmsWebsite implements Serializable {
@TableField(exist = false)
private String templateName;
@Schema(description = "是否初始化示例数据(仅 create 入参使用,不落库;true=生成标准示例栏目与内容,false=空白骨架,null=沿用模板克隆历史行为)")
@TableField(exist = false)
private Boolean initDemoData;
@Schema(description = "行业类型(父级)")
private String industryParent;
@@ -19,7 +19,9 @@ import com.gxwebsoft.shop.vo.ShopVo;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -69,6 +71,12 @@ public class CmsWebsiteServiceImpl extends ServiceImpl<CmsWebsiteMapper, CmsWebs
@Resource
private CmsArticleContentService cmsArticleContentService;
@Resource
private CmsProductService cmsProductService;
@Resource
private CmsCaseService cmsCaseService;
@Resource
private CmsPageService cmsPageService;
@Resource
private CmsWebsiteMapper cmsWebsiteMapper;
@Resource
private ProjectService projectService;
@@ -279,61 +287,17 @@ public class CmsWebsiteServiceImpl extends ServiceImpl<CmsWebsiteMapper, CmsWebs
});
cmsLinkService.saveBatch(links);
// TODO 复制栏目和文章、文章内容
CmsNavigationParam cmsNavigationParam = new CmsNavigationParam();
cmsNavigationParam.setWebsiteUserId(websiteUserId);
cmsNavigationParam.setParentId(0);
final List<CmsNavigation> parents = cmsNavigationMapper.selectListAllRel(cmsNavigationParam);
parents.forEach(d -> {
Integer navigationId = d.getNavigationId();
// 复制顶级栏目
d.setTenantId(loginUser.getTenantId());
d.setUserId(loginUser.getUserId());
if (cmsNavigationService.save(d)) {
cmsNavigationService.saveAsync(d);
// 复制栏目文章
CmsArticleParam cmsArticleParam = new CmsArticleParam();
cmsArticleParam.setWebsiteUserId(websiteUserId);
cmsArticleParam.setCategoryId(navigationId);
final List<CmsArticle> articles = cmsArticleMapper.selectListAllRel(cmsArticleParam);
articles.forEach(a -> {
a.setCategoryId(d.getNavigationId());
a.setUserId(loginUser.getUserId());
a.setTenantId(loginUser.getTenantId());
if (cmsArticleService.save(a)) {
final CmsArticleContent content = new CmsArticleContent();
content.setArticleId(a.getArticleId());
content.setContent(a.getContent());
cmsArticleContentService.save(content);
// 栏目与内容初始化:按 initDemoData 决定分支
if (Boolean.TRUE.equals(website.getInitDemoData())) {
// 注册流程勾选「填充示例内容」:生成标准示例栏目与内容(不克隆模板,避免千篇一律)
initDemoData(website, loginUser);
} else if (Boolean.FALSE.equals(website.getInitDemoData())) {
// 注册流程明确不勾选:仅保留基础配置克隆,跳过栏目与文章,站点保持空白骨架
log.info("initDemoData=false,跳过示例内容生成,站点保持空白骨架, tenantId={}", loginUser.getTenantId());
} else {
// 历史行为(后台手动建站等未传 initDemoData):克隆模板栏目与文章
cloneTemplateContent(website, loginUser, websiteUserId);
}
});
// 复制子栏目
cmsNavigationParam.setParentId(navigationId);
final List<CmsNavigation> navigations = cmsNavigationMapper.selectListAllRel(cmsNavigationParam);
navigations.forEach(c -> {
cmsArticleParam.setCategoryId(c.getNavigationId());
c.setParentId(d.getNavigationId());
c.setTenantId(loginUser.getTenantId());
c.setUserId(loginUser.getUserId());
cmsNavigationService.save(c);
cmsNavigationService.saveAsync(c);
// 复制子栏目文章
final List<CmsArticle> articles2 = cmsArticleMapper.selectListAllRel(cmsArticleParam);
articles2.forEach(a2 -> {
a2.setCategoryId(c.getNavigationId());
a2.setParentId(c.getParentId());
a2.setUserId(loginUser.getUserId());
a2.setTenantId(loginUser.getTenantId());
if (cmsArticleService.save(a2)) {
final CmsArticleContent content = new CmsArticleContent();
content.setArticleId(a2.getArticleId());
content.setContent(a2.getContent());
cmsArticleContentService.save(content);
}
});
});
}
});
} else {
log.warn("没有有效的模板ID,跳过复制操作");
}
@@ -608,4 +572,218 @@ public class CmsWebsiteServiceImpl extends ServiceImpl<CmsWebsiteMapper, CmsWebs
}
return candidate;
}
// ===== 注册「填充示例内容」:标准示例数据初始化 =====
/** 产品示例数据:{ 产品名称, 简介 } */
private static final String[][] PRODUCT_DEMO = {
{"智能营销云平台", "一站式营销自动化工具,覆盖获客、培育、转化全链路,让增长可度量。"},
{"企业协同办公系统", "打通沟通、文档与流程,让团队协作更高效、信息不丢失。"},
{"数据可视化大屏", "多源数据接入,实时呈现业务全景,辅助经营决策。"},
{"客户关系管理 CRM", "沉淀客户资产,提升销售转化与复购,驱动业绩增长。"},
{"在线教育解决方案", "直播、录播、互动作业一体化的在线教学平台。"},
{"电商直播中台", "从商品到直播到交易,构建私域增长闭环。"}
};
/** 客户案例示例数据:{ 案例名称, 简介, 客户名称, 所属行业 } */
private static final String[][] CASE_DEMO = {
{"某制造业集团数字化转型", "以数字化中台打通生产与供应链,交付周期显著缩短。", "制造业集团", "制造业"},
{"连锁零售智慧门店升级", "门店数字化运营,会员复购率与坪效双提升。", "连锁零售企业", "零售"},
{"教育机构在线课堂改造", "线上线下融合教学,覆盖更多学员,扩大营收半径。", "教育科技公司", "教育"},
{"医疗机构患者服务中台", "统一预约、问诊与随访,患者满意度明显提升。", "三甲医院", "医疗"},
{"物流企业运输调度系统", "智能调度与轨迹监控,运力利用率大幅提高。", "物流企业", "物流"},
{"金融企业数据中台建设", "统一数据资产,风控与营销决策更加敏捷。", "城商银行", "金融"}
};
/** 新闻资讯示例数据:{ 标题, 摘要 }(标题支持 {company} 占位符,替换为注册企业名) */
private static final String[][] NEWS_DEMO = {
{"{company} 荣获年度数字化服务创新奖", "{company}凭借在企业官网与数字化服务领域的持续创新,荣获年度数字化服务创新奖。"},
{"企业官网建设的核心要素解析", "从品牌定位、信息架构到视觉体验,拆解一个高转化企业官网的关键要素。"},
{"如何选择适合自己的官网模板", "结合行业、预算与运营目标,教你快速匹配最合适的官网模板。"},
{"提升网站转化率的 5 个技巧", "落地页、CTA、信任背书、加载速度与内容策略,五招提升转化。"},
{"SEO 优化入门指南", "关键词、结构、内容与外链,新手也能上手的 SEO 基础框架。"},
{"品牌视觉设计与用户体验", "一致的视觉语言与顺畅的交互,是建立品牌信任的第一步。"}
};
/**
* 生成标准示例栏目与内容(注册流程勾选「填充示例内容」时调用)。
* 创建 5 个顶部导航栏目 + 关于我们单页 + 6 产品 + 6 案例 + 6 新闻。
* 不克隆模板内容,避免新站点千篇一律。
*/
private void initDemoData(CmsWebsite website, User loginUser) {
Integer tenantId = loginUser.getTenantId();
Integer userId = loginUser.getUserId();
final String companyName = StrUtil.isNotBlank(website.getWebsiteName()) ? website.getWebsiteName() : "贵公司";
// 1. 导航栏目:首页 / 关于我们 / 产品展示 / 客户案例 / 新闻资讯
CmsNavigation home = buildNav("首页", "page", "/", 1, 0, tenantId, userId);
CmsNavigation about = buildNav("关于我们", "page", "/about", 2, 1, tenantId, userId);
CmsNavigation productNav = buildNav("产品展示", "product", "/product", 3, 0, tenantId, userId);
CmsNavigation caseNav = buildNav("客户案例", "case", "/case", 4, 0, tenantId, userId);
CmsNavigation newsNav = buildNav("新闻资讯", "article", "/article", 5, 0, tenantId, userId);
for (CmsNavigation nav : Arrays.asList(home, about, productNav, caseNav, newsNav)) {
cmsNavigationService.save(nav);
}
// 2. 关于我们单页(path=aboutstatus=1 已发布)
CmsPage aboutPage = new CmsPage();
aboutPage.setTitle("关于我们");
aboutPage.setPath("about");
aboutPage.setContent(buildAboutContent(companyName));
aboutPage.setDescription("了解" + companyName + "的发展历程、业务能力与核心价值观。");
aboutPage.setKeywords(companyName + ",关于我们,企业简介");
aboutPage.setStatus(1);
aboutPage.setTenantId(tenantId);
cmsPageService.save(aboutPage);
// 关联导航栏目(便于后台「单页管理」定位)
about.setPageId(aboutPage.getPageId());
cmsNavigationService.updateById(about);
// 3. 产品展示(6 条,categoryId = 产品栏目 navigationIdstatus=0 可见)
int pSort = 1;
for (String[] p : PRODUCT_DEMO) {
CmsProduct product = new CmsProduct();
product.setProductName(p[0]);
product.setSummary(p[1]);
product.setDescription(p[1]);
product.setCategoryId(productNav.getNavigationId());
product.setCategoryName(productNav.getTitle());
product.setPrice(BigDecimal.ZERO);
product.setOriginalPrice(BigDecimal.ZERO);
product.setUnit("");
product.setStatus(0);
product.setSortNumber(pSort);
product.setTop(pSort <= 3 ? 1 : 0);
product.setTenantId(tenantId);
product.setUserId(userId);
cmsProductService.save(product);
pSort++;
}
// 4. 客户案例(6 个,categoryId = 案例栏目 navigationIdstatus=0 可见)
int cSort = 1;
for (String[] c : CASE_DEMO) {
CmsCase cmsCase = new CmsCase();
cmsCase.setCaseName(c[0]);
cmsCase.setSummary(c[1]);
cmsCase.setContent(c[1]);
cmsCase.setCustomer(c[2]);
cmsCase.setIndustry(c[3]);
cmsCase.setCategoryId(caseNav.getNavigationId());
cmsCase.setCategoryName(caseNav.getTitle());
cmsCase.setStatus(0);
cmsCase.setSortNumber(cSort);
cmsCase.setTenantId(tenantId);
cmsCaseService.save(cmsCase);
cSort++;
}
// 5. 新闻资讯(6 篇,categoryId = 资讯栏目 navigationIdstatus=0 已发布)
int aSort = 1;
for (String[] a : NEWS_DEMO) {
CmsArticle article = new CmsArticle();
article.setTitle(a[0].replace("{company}", companyName));
article.setModel("article");
article.setCategoryId(newsNav.getNavigationId());
article.setOverview(a[1].replace("{company}", companyName));
article.setStatus(0);
article.setSortNumber(aSort);
article.setUserId(userId);
article.setTenantId(tenantId);
article.setAuthor(companyName);
if (cmsArticleService.save(article)) {
CmsArticleContent content = new CmsArticleContent();
content.setArticleId(article.getArticleId());
content.setContent(a[1].replace("{company}", companyName));
content.setTenantId(tenantId);
cmsArticleContentService.save(content);
}
aSort++;
}
}
/**
* 克隆模板站点的栏目与文章(历史默认行为,未传 initDemoData 时走此分支,兼容后台手动建站等场景)。
*/
private void cloneTemplateContent(CmsWebsite website, User loginUser, Integer websiteUserId) {
CmsNavigationParam cmsNavigationParam = new CmsNavigationParam();
cmsNavigationParam.setWebsiteUserId(websiteUserId);
cmsNavigationParam.setParentId(0);
final List<CmsNavigation> parents = cmsNavigationMapper.selectListAllRel(cmsNavigationParam);
parents.forEach(d -> {
Integer navigationId = d.getNavigationId();
d.setTenantId(loginUser.getTenantId());
d.setUserId(loginUser.getUserId());
if (cmsNavigationService.save(d)) {
cmsNavigationService.saveAsync(d);
CmsArticleParam cmsArticleParam = new CmsArticleParam();
cmsArticleParam.setWebsiteUserId(websiteUserId);
cmsArticleParam.setCategoryId(navigationId);
final List<CmsArticle> articles = cmsArticleMapper.selectListAllRel(cmsArticleParam);
articles.forEach(a -> {
a.setCategoryId(d.getNavigationId());
a.setUserId(loginUser.getUserId());
a.setTenantId(loginUser.getTenantId());
if (cmsArticleService.save(a)) {
CmsArticleContent content = new CmsArticleContent();
content.setArticleId(a.getArticleId());
content.setContent(a.getContent());
cmsArticleContentService.save(content);
}
});
cmsNavigationParam.setParentId(navigationId);
final List<CmsNavigation> navigations = cmsNavigationMapper.selectListAllRel(cmsNavigationParam);
navigations.forEach(c -> {
cmsArticleParam.setCategoryId(c.getNavigationId());
c.setParentId(d.getNavigationId());
c.setTenantId(loginUser.getTenantId());
c.setUserId(loginUser.getUserId());
cmsNavigationService.save(c);
cmsNavigationService.saveAsync(c);
final List<CmsArticle> articles2 = cmsArticleMapper.selectListAllRel(cmsArticleParam);
articles2.forEach(a2 -> {
a2.setCategoryId(c.getNavigationId());
a2.setParentId(c.getParentId());
a2.setUserId(loginUser.getUserId());
a2.setTenantId(loginUser.getTenantId());
if (cmsArticleService.save(a2)) {
CmsArticleContent content = new CmsArticleContent();
content.setArticleId(a2.getArticleId());
content.setContent(a2.getContent());
cmsArticleContentService.save(content);
}
});
});
}
});
}
/** 构造一个顶部导航栏目 */
private CmsNavigation buildNav(String title, String model, String path, int sort, int type,
Integer tenantId, Integer userId) {
CmsNavigation nav = new CmsNavigation();
nav.setTitle(title);
nav.setModel(model);
nav.setPath(path);
nav.setType(type);
nav.setParentId(0);
nav.setTop(1);
nav.setBottom(0);
nav.setPosition(1);
nav.setHide(0);
nav.setStatus(0);
nav.setSortNumber(sort);
nav.setTenantId(tenantId);
nav.setUserId(userId);
return nav;
}
/** 生成关于我们单页正文(富文本 HTML) */
private String buildAboutContent(String companyName) {
return "<p>欢迎来到 <strong>" + companyName + "</strong>!我们是一家专注于为企业提供数字化解决方案的服务商。</p>"
+ "<p>自成立以来," + companyName + "始终以客户成功为中心,围绕官网建设、内容管理与营销增长等场景,"
+ "提供从咨询、设计到落地运营的一站式服务。</p>"
+ "<p>我们的团队由资深产品、设计与技术专家组成,已为众多行业客户交付稳定可靠的数字平台。"
+ "期待与您携手,共创更大价值。</p>";
}
}