feat: 新增开放接口,支持通过模板名称和项目名称生成文案
- 新增 HtmlUtils 工具类,支持 HTML 转纯文本 - 新增 selectTtCodeByCodeName 方法,支持按名称查询源码 - 新增 /office/copyTemplate/open/generate 开放接口 无需登录,参数:templateName(模板名称)、codeName(项目名称) 返回:填充占位符后的完整文案内容 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
|||||||
|
package com.ruoyi.common.utils;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML工具类
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class HtmlUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将HTML内容转换为纯文本
|
||||||
|
* 移除所有HTML标签,将 等转义字符转换为普通空格,合并多余空白符
|
||||||
|
*/
|
||||||
|
public static String htmlToText(String html) {
|
||||||
|
if (StringUtils.isEmpty(html)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String text = html;
|
||||||
|
// 移除script和style标签及其内容
|
||||||
|
text = Pattern.compile("<script[^>]*?>.*?</script>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE).matcher(text).replaceAll("");
|
||||||
|
text = Pattern.compile("<style[^>]*?>.*?</style>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE).matcher(text).replaceAll("");
|
||||||
|
// 移除HTML注释
|
||||||
|
text = Pattern.compile("<!--.*?-->", Pattern.DOTALL).matcher(text).replaceAll("");
|
||||||
|
// 移除所有HTML标签
|
||||||
|
text = Pattern.compile("<[^>]+>").matcher(text).replaceAll("");
|
||||||
|
// 转义字符转换
|
||||||
|
text = text.replaceAll(" ", " ");
|
||||||
|
text = text.replaceAll("&", "&");
|
||||||
|
text = text.replaceAll("<", "<");
|
||||||
|
text = text.replaceAll(">", ">");
|
||||||
|
text = text.replaceAll(""", "\"");
|
||||||
|
text = text.replaceAll("'", "'");
|
||||||
|
text = text.replaceAll("'", "'");
|
||||||
|
text = text.replaceAll("—", "—");
|
||||||
|
text = text.replaceAll("–", "–");
|
||||||
|
text = text.replaceAll("…", "…");
|
||||||
|
text = text.replaceAll("“", """);
|
||||||
|
text = text.replaceAll("”", """);
|
||||||
|
text = text.replaceAll("‘", "'");
|
||||||
|
text = text.replaceAll("’", "'");
|
||||||
|
text = text.replaceAll("\\r\\n", "\n");
|
||||||
|
text = text.replaceAll("\\r", "\n");
|
||||||
|
text = text.replaceAll("\\n\\n+", "\n\n");
|
||||||
|
// 合并每行首尾空白并移除全空行
|
||||||
|
String[] lines = text.split("\n");
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String line : lines) {
|
||||||
|
String trimmed = line.trim();
|
||||||
|
if (trimmed.length() > 0) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
sb.append(trimmed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,12 +11,18 @@ import org.springframework.web.bind.annotation.DeleteMapping;
|
|||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import com.ruoyi.common.utils.HtmlUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.office.domain.TtCode;
|
||||||
import com.ruoyi.office.domain.TtCopyTemplate;
|
import com.ruoyi.office.domain.TtCopyTemplate;
|
||||||
|
import com.ruoyi.office.service.ITtCodeService;
|
||||||
import com.ruoyi.office.service.ITtCopyTemplateService;
|
import com.ruoyi.office.service.ITtCopyTemplateService;
|
||||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
@@ -34,6 +40,9 @@ public class TtCopyTemplateController extends BaseController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ITtCopyTemplateService ttCopyTemplateService;
|
private ITtCopyTemplateService ttCopyTemplateService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ITtCodeService ttCodeService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询文案模板列表
|
* 查询文案模板列表
|
||||||
*/
|
*/
|
||||||
@@ -103,4 +112,71 @@ public class TtCopyTemplateController extends BaseController {
|
|||||||
public AjaxResult remove(@PathVariable Long[] templateIds) {
|
public AjaxResult remove(@PathVariable Long[] templateIds) {
|
||||||
return toAjax(ttCopyTemplateService.deleteTtCopyTemplateByTemplateIds(templateIds));
|
return toAjax(ttCopyTemplateService.deleteTtCopyTemplateByTemplateIds(templateIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放接口:通过文案模板名称和项目名称生成文案
|
||||||
|
* 无需登录,浏览器可直接访问
|
||||||
|
*/
|
||||||
|
@Anonymous
|
||||||
|
@GetMapping("/open/generate")
|
||||||
|
public AjaxResult generateByOpen(@RequestParam String templateName, @RequestParam String codeName) {
|
||||||
|
// 1. 查询模板
|
||||||
|
TtCopyTemplate template = ttCopyTemplateService.selectEnabledTemplates().stream()
|
||||||
|
.filter(t -> templateName.equals(t.getTemplateName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (template == null) {
|
||||||
|
return error("未找到名称为【" + templateName + "】的启用模板");
|
||||||
|
}
|
||||||
|
// 2. 查询源码
|
||||||
|
TtCode code = ttCodeService.selectTtCodeByCodeName(codeName);
|
||||||
|
if (code == null) {
|
||||||
|
return error("未找到名称为【" + codeName + "】的源码项目");
|
||||||
|
}
|
||||||
|
// 3. 提取变量
|
||||||
|
String fullCodeName = code.getCodeName() != null ? code.getCodeName() : "";
|
||||||
|
String projectCode = "";
|
||||||
|
String projectName = fullCodeName;
|
||||||
|
if (fullCodeName.length() > 0) {
|
||||||
|
java.util.regex.Matcher m = java.util.regex.Pattern.compile("【(.+?)】").matcher(fullCodeName);
|
||||||
|
if (m.find()) {
|
||||||
|
projectCode = m.group(1);
|
||||||
|
}
|
||||||
|
projectName = fullCodeName.replaceAll("【.+?】", "").trim();
|
||||||
|
if (projectName.startsWith("基于")) {
|
||||||
|
java.util.regex.Matcher nameMatcher = java.util.regex.Pattern.compile("实现的(.+?)$").matcher(projectName);
|
||||||
|
if (nameMatcher.find()) {
|
||||||
|
projectName = nameMatcher.group(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 4. 生成纯文本描述
|
||||||
|
String plainDesc = "";
|
||||||
|
if (StringUtils.isNotEmpty(code.getCodeDesc())) {
|
||||||
|
String codeDesc = code.getCodeDesc().replaceAll("</p>", "</p>\n");
|
||||||
|
plainDesc = HtmlUtils.htmlToText(codeDesc.trim());
|
||||||
|
}
|
||||||
|
// 5. 生成截图列表
|
||||||
|
String screenshots = "";
|
||||||
|
int idx = 0;
|
||||||
|
if (code.getFileList() != null && !code.getFileList().isEmpty()) {
|
||||||
|
for (var item : code.getFileList()) {
|
||||||
|
screenshots += (++idx) + "." + item.getFileName() + "\n + ")\n\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
screenshots = "请前往微信小程序:南音源码库。查看项目详情!\n\n";
|
||||||
|
}
|
||||||
|
// 6. 替换占位符
|
||||||
|
String content = template.getTemplateBody();
|
||||||
|
content = content.replace("{codeName}", fullCodeName);
|
||||||
|
content = content.replace("{projectCode}", projectCode);
|
||||||
|
content = content.replace("{projectName}", projectName);
|
||||||
|
content = content.replace("{codeDesc}", plainDesc);
|
||||||
|
content = content.replace("{codeEnvironment}", code.getCodeEnvironment() != null ? code.getCodeEnvironment() : "");
|
||||||
|
content = content.replace("{codeTechnology}", code.getCodeTechnology() != null ? code.getCodeTechnology() : "");
|
||||||
|
content = content.replace("{diskLink}", code.getDiskLink() != null ? code.getDiskLink() : "");
|
||||||
|
content = content.replace("{screenshots}", screenshots);
|
||||||
|
|
||||||
|
return success(content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,12 +13,20 @@ public interface TtCodeMapper
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 查询源码管理
|
* 查询源码管理
|
||||||
*
|
*
|
||||||
* @param codeId 源码管理主键
|
* @param codeId 源码管理主键
|
||||||
* @return 源码管理
|
* @return 源码管理
|
||||||
*/
|
*/
|
||||||
public TtCode selectTtCodeByCodeId(Long codeId);
|
public TtCode selectTtCodeByCodeId(Long codeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据项目名称查询源码管理
|
||||||
|
*
|
||||||
|
* @param codeName 项目名称
|
||||||
|
* @return 源码管理
|
||||||
|
*/
|
||||||
|
public TtCode selectTtCodeByCodeName(String codeName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询源码管理列表
|
* 查询源码管理列表
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ public interface ITtCodeService {
|
|||||||
*/
|
*/
|
||||||
public TtCode selectTtCodeByCodeId(Long codeId);
|
public TtCode selectTtCodeByCodeId(Long codeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据项目名称查询源码管理
|
||||||
|
*
|
||||||
|
* @param codeName 项目名称
|
||||||
|
* @return 源码管理
|
||||||
|
*/
|
||||||
|
public TtCode selectTtCodeByCodeName(String codeName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询源码管理列表
|
* 查询源码管理列表
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -58,6 +58,23 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
|||||||
return ttCode;
|
return ttCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据项目名称查询源码管理
|
||||||
|
*
|
||||||
|
* @param codeName 项目名称
|
||||||
|
* @return 源码管理
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TtCode selectTtCodeByCodeName(String codeName) {
|
||||||
|
TtCode ttCode = ttCodeMapper.selectTtCodeByCodeName(codeName);
|
||||||
|
if (ttCode != null) {
|
||||||
|
TtFile file = new TtFile();
|
||||||
|
file.setCodeName(ttCode.getCodeName());
|
||||||
|
ttCode.setFileList(fileMapper.selectTtFileList(file));
|
||||||
|
}
|
||||||
|
return ttCode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询源码管理列表
|
* 查询源码管理列表
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<include refid="selectTtCodeVo"/>
|
<include refid="selectTtCodeVo"/>
|
||||||
where code_id = #{codeId}
|
where code_id = #{codeId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectTtCodeByCodeName" parameterType="String" resultMap="TtCodeResult">
|
||||||
|
<include refid="selectTtCodeVo"/>
|
||||||
|
where code_name = #{codeName} limit 1
|
||||||
|
</select>
|
||||||
|
|
||||||
<insert id="insertTtCode" parameterType="TtCode">
|
<insert id="insertTtCode" parameterType="TtCode">
|
||||||
insert into tt_code
|
insert into tt_code
|
||||||
|
|||||||
Reference in New Issue
Block a user