feat: 新增文案模板管理功能,源码明细页按钮支持动态配置

- 新增 tt_copy_template 表及 CRUD 后端接口
- 新增文案模板管理页面,支持 {变量} 占位符动态替换
- 源码明细页复制按钮由硬编码改为数据库驱动
- 支持占位符:codeName、projectCode、projectName、codeDesc、codeEnvironment、codeTechnology、diskLink、screenshots

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
王鹏
2026-04-10 19:20:32 +08:00
parent 5e7bbe6c9d
commit 6940541216
10 changed files with 1033 additions and 343 deletions

View File

@@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询文案模板列表
export function listCopyTemplate(query) {
return request({
url: '/office/copyTemplate/list',
method: 'get',
params: query
})
}
// 查询所有启用的文案模板(源码明细页按钮用)
export function listEnabledTemplates() {
return request({
url: '/office/copyTemplate/enabled',
method: 'get'
})
}
// 查询文案模板详细
export function getCopyTemplate(templateId) {
return request({
url: '/office/copyTemplate/' + templateId,
method: 'get'
})
}
// 新增文案模板
export function addCopyTemplate(data) {
return request({
url: '/office/copyTemplate',
method: 'post',
data: data
})
}
// 修改文案模板
export function updateCopyTemplate(data) {
return request({
url: '/office/copyTemplate',
method: 'put',
data: data
})
}
// 删除文案模板
export function delCopyTemplate(templateId) {
return request({
url: '/office/copyTemplate/' + templateId,
method: 'delete'
})
}

View File

@@ -308,13 +308,13 @@
</el-descriptions>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="copySiteTextToClipboard">复制网站文案</el-button>
<el-button type="primary" @click="copyXianyuTextToClipboard">复制闲鱼文案</el-button>
<el-button type="primary" @click="copyXianyuTextToClipboard1">复制闲鱼文案1</el-button>
<el-button type="primary" @click="copyOtherTextToClipboard">复制抖音视频号小红书文案</el-button>
<el-button type="primary" @click="copyTextToClipboard">FeastCoding</el-button>
<el-button type="primary" @click="copyTextToClipboard1">南音</el-button>
<el-button @click="cancel"> </el-button>
<el-button
v-for="tpl in copyTemplates"
:key="tpl.templateId"
type="primary"
@click="copyByTemplate(tpl)"
>{{ tpl.templateName }}</el-button>
<el-button @click="cancelDetail"> </el-button>
</div>
</el-dialog>
@@ -335,6 +335,7 @@
<script>
import {listCode, getCode, delCode, addCode, updateCode, transToArticle, transToArticle1} from "@/api/office/code";
import {listEnabledTemplates} from "@/api/office/copyTemplate";
import {html2Text} from "../../../utils";
import {getToken} from "@/utils/auth";
import request from '@/utils/request';
@@ -389,11 +390,14 @@
coverImageUrl: '',
previewBlob: null,
currentFileName: '',
currentRow: ''
currentRow: '',
// 文案模板列表(动态按钮)
copyTemplates: []
};
},
created() {
this.getList();
this.loadCopyTemplates();
},
computed: {
previewList() {
@@ -435,359 +439,69 @@
};
this.resetForm("form");
},
copyTextToClipboard() {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n\n');
// 先转换为纯文本
let plainText = html2Text(codeDesc.trimEnd());
// 处理纯文本中包含"角色"关键词的行添加####前缀
plainText = plainText.replace(/^(.*)个角色(.*)$/gm, '#### $&');
plainText = plainText.replace(/^(.*)角色:(.*)$/gm, '#### $&');
// 提取项目名称(去掉编号部分)
let projectName = this.form.codeName;
copyByTemplate(tpl) {
// 从数据库模板中提取并替换占位符
let codeName = this.form.codeName || '';
let projectCode = '';
let backendTech = '';
let frontendTech = '';
let projectName = codeName;
if (projectName) {
// 提取项目编号 【A075】
const codeMatch = projectName.match(/【(.+?)】/);
if (codeMatch && codeMatch[1]) {
projectCode = codeMatch[1];
}
// 去掉编号部分,提取项目名称
projectName = projectName.replace(/【.+?】/, '').trim();
if (projectName.startsWith('基于')) {
const nameMatch = projectName.match(/实现的(.+?)$/);
if (nameMatch && nameMatch[1]) {
projectName = nameMatch[1];
}
// 提取项目编号 【A075】
const codeMatch = codeName.match(/【(.+?)】/);
if (codeMatch && codeMatch[1]) {
projectCode = codeMatch[1];
}
// 去掉编号部分,提取纯项目名称
projectName = codeName.replace(/【.+?】/, '').trim();
if (projectName.startsWith('基于')) {
const nameMatch = projectName.match(/实现的(.+?)$/);
if (nameMatch && nameMatch[1]) {
projectName = nameMatch[1];
}
}
console.log('项目编号:', projectCode);
console.log('后端技术:', backendTech);
console.log('前端技术:', frontendTech);
console.log('项目名称:', projectName);
// 项目描述转纯文本
let plainDesc = '';
if (this.form.codeDesc) {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n');
plainDesc = html2Text(codeDesc.trimEnd());
}
let content = '![](https://img.yidaima.cn/weicome.gif)\n# 项目描述\n#### 视频演示\n' + plainText
+ '\n\n# 技术选型'
+ '\n* 开发工具Idea + Vscode'
+ '\n* 运行环境JDK 1.8 + Maven + MySQL 5.7以上 + Node.js 14'
+ '\n* 服务端技术SpringBoot + Mybatis-Plus + Maven'
+ '\n* 前端技术Vue3 + Axios + Element-UI'
+ '\n\n# 系统截图\n';
let index = 0
if(this.form.fileList && this.form.fileList.length > 0){
// 生成截图列表
let screenshots = '';
let index = 0;
if (this.form.fileList && this.form.fileList.length > 0) {
for (let item of this.form.fileList) {
content = content + ++index + '.' + item.fileName
+ '\n' + '![](' + item.fileUrl + ')' + '\n\n';
screenshots = screenshots + ++index + '.' + item.fileName + '\n![](' + item.fileUrl + ')\n\n';
}
} else {
content = content + '请前往微信小程序:南音源码库。查看项目详情!\n\n'
screenshots = '请前往微信小程序:南音源码库。查看项目详情!\n\n';
}
content = content + '# 运行步骤'
+ '\n### 准备环境'
+ '\n 安装JDK 1.8、Maven、Node.js 14 和 MySQL 5.7以上'
+ '\n\n### 创建数据库'
+ '\n 使用Navicat工具创建数据库并导入SQL脚本'
+ '\n\n### 配置后端'
+ '\n 修改`application.yml`中的数据库连接信息(用户名/密码/库名)'
+ '\n\n### 启动后端服务'
+ '\n 进入后端项目(`/server_code` 执行:'
+ '\n ```'
+ '\n mvn clean install'
+ '\n mvn spring-boot:run'
+ '\n ```'
+ '\n\n### 前端依赖安装'
+ '\n 进入前端目录(`/manage_code`或者`/client_code`,执行安装命令:'
+ '\n ```'
+ '\n npm install'
+ '\n ```'
+ '\n '
+ '\n### 启动前端服务'
+ '\n 执行启动命令:'
+ '\n ```'
+ '\n npm run serve '
+ '\n ```'
+ '\n\n### 访问系统'
+ '\n - 后端接口系统访问地址:'
+ '\n `http://localhost:8080`'
+ '\n - 后台系统前端访问地址:'
+ '\n `http://localhost:8081`'
+ '\n - 前台系统前端访问地址:'
+ '\n `http://localhost:8082`'
+ '\n\n### 常见问题'
+ '\n#### 端口冲突'
+ '\n - 修改后端配置文件`application.yml`'
+ '\n - 修改前端配置文件`vue.config.js` '
+ '\n\n#### 前端安装依赖失败'
+ '\n - 删除node_modules、package-lock.json文件'
+ '\n ```'
+ '\n rm -rf node_modules package-lock.json'
+ '\n ```'
+ '\n - 清除缓存'
+ '\n ```'
+ '\n npm cache clean --force'
+ '\n ```'
+ '\n - 切换npm镜像源'
+ '\n ```'
+ '\n npm config set registry https://registry.npmmirror.com'
+ '\n ```'
+ '\n\n# 推荐阅读'
+ '\n- [基于Springboot + vue3实现的果树系统](https://mp.weixin.qq.com/s/F7mO-9ENdfKqa89InlPUlg)'
+ '\n- [基于Springboot + vue3实现的个人健康管理系统](https://mp.weixin.qq.com/s/UUUh4S2KfOnRKnLKZLlS3Q)'
+ '\n- [基于Springboot + vue3实现的旅游网站系统](https://mp.weixin.qq.com/s/EY6XVtJXyY5FThfn0PoOew)'
+ '\n- [基于Springboot + vue3实现的房屋租售系统](https://mp.weixin.qq.com/s/tbDCa5504JwOt-ECt3t_Yg)'
+ '\n\n# 其他说明'
+ '\n>* 1、本系统源码由**南音工作室**精心收集整理,并经过严格测试验证,确保运行稳定可靠。'
+ '\n>* 2、**南音工作室**开始招募合伙人,有兴趣一起搞钱的小伙伴,可以在公众号后台回复关键词【**合伙人**】查看详细介绍。'
+ '\n>* 3、如需获取详细运行教程欢迎在公众号后台回复关键词【**运行教程**】,即可自助领取完整指导文档。'
+ '\n>* 4、我们已为您整理上万套优质源码项目资源回复【**源码搜索**】即可快速查找您需要的源码资源。'
+ '\n>* 5、为了回馈粉丝特意整理了海量福利资源免费分享回复【**免费资源**】即可领取。'
+ '\n>* 6、创作不易如果觉得内容有帮助别忘了**点赞/推荐/分享/收藏**支持我们,您的鼓励是我们持续更新的最大动力!'
+ '\n\n# 源码获取'
+ '\n\n<center>'
+ '\n <img src="https://img.yidaima.cn/qrcode.jpg" style="width: 100px;">'
+ '\n <br>'
+ '\n <span>长按小程序码,打开小程序搜索 "<Strong style="color:var(--md-primary-color);">' + projectCode + '</Strong>" 即可获取资源</span>'
+ '\n</center>';
// 替换模板中的占位符
let content = tpl.templateBody || '';
content = content.replace(/{codeName}/g, codeName);
content = content.replace(/{projectCode}/g, projectCode);
content = content.replace(/{projectName}/g, projectName);
content = content.replace(/{codeDesc}/g, plainDesc);
content = content.replace(/{codeEnvironment}/g, this.form.codeEnvironment || '');
content = content.replace(/{codeTechnology}/g, this.form.codeTechnology || '');
content = content.replace(/{diskLink}/g, this.form.diskLink || '');
content = content.replace(/{screenshots}/g, screenshots);
navigator.clipboard.writeText(content).then(() => {
this.$message({
message: '复制成功',
type: 'success'
});
this.$message({ message: '复制成功', type: 'success' });
}).catch(err => {
this.$message({
message: '复制失败: ' + err,
type: 'error'
});
this.$message({ message: '复制失败: ' + err, type: 'error' });
});
},
copyTextToClipboard1() {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n\n');
// 先转换为纯文本
let plainText = html2Text(codeDesc.trimEnd());
// 提取项目名称(去掉编号部分)
let projectCode = 'A081'; // 默认编号
if (this.form.codeName) {
const match = this.form.codeName.match(/【(.+?)】/);
if (match && match[1]) {
projectCode = match[1];
}
}
let content = '![](https://img.yidaima.cn/weicome.gif)\n### 项目描述\n##### 视频演示\n' + plainText
+ '\n\n### 技术选型'
+ '\n**开发工具**Idea + Vscode'
+ '\n**运行环境**JDK 1.8 + Maven + MySQL 5.7以上 + Node.js 14'
+ '\n**服务端技术**SpringBoot + Mybatis-Plus + Maven'
+ '\n**前端技术**Vue3 + Axios + Element-UI'
+ '\n\n### 系统截图\n';
let index = 0
if(this.form.fileList && this.form.fileList.length > 0){
for (let item of this.form.fileList) {
content = content + ++index + '.' + item.fileName
+ '\n' + '![](' + item.fileUrl + ')' + '\n\n';
}
} else {
content = content + '请前往微信小程序:南音源码库。查看项目详情!\n\n'
}
content = content + '### 运行步骤'
+ '\n##### 准备环境'
+ '\n 安装JDK 1.8、Maven、Node.js 14 和 MySQL 5.7以上'
+ '\n\n##### 创建数据库'
+ '\n 使用Navicat工具创建数据库并导入SQL脚本'
+ '\n\n##### 配置后端'
+ '\n 修改`application.yml`中的数据库连接信息(用户名/密码/库名)'
+ '\n\n##### 启动后端服务'
+ '\n 进入后端项目(`/server_code` 执行:'
+ '\n ```'
+ '\n mvn clean install'
+ '\n mvn spring-boot:run'
+ '\n ```'
+ '\n\n##### 前端依赖安装'
+ '\n 进入前端目录(`/manage_code`或者`/client_code`, 执行安装命令:'
+ '\n ```'
+ '\n npm install'
+ '\n ```'
+ '\n '
+ '\n##### 启动前端服务'
+ '\n 执行启动命令:'
+ '\n ```'
+ '\n npm run serve '
+ '\n ```'
+ '\n\n##### 访问系统'
+ '\n - 后端接口系统访问地址:`http://localhost:8080`'
+ '\n - 后台系统前端访问地址:`http://localhost:8081`'
+ '\n - 前台系统前端访问地址:`http://localhost:8082`'
+ '\n\n##### 常见问题'
+ '\n###### 端口冲突'
+ '\n - 修改后端配置文件`application.yml`'
+ '\n - 修改前端配置文件`vue.config.js` '
+ '\n\n###### 前端安装依赖失败'
+ '\n - 删除node_modules、package-lock.json文件'
+ '\n ```'
+ '\n rm -rf node_modules package-lock.json'
+ '\n ```'
+ '\n - 清除缓存'
+ '\n ```'
+ '\n npm cache clean --force'
+ '\n ```'
+ '\n - 切换npm镜像源'
+ '\n ```'
+ '\n npm config set registry https://registry.npmmirror.com'
+ '\n ```'
+ '\n\n### 推荐阅读'
+ '\n- [基于Springboot + vue3实现的果树系统](https://mp.weixin.qq.com/s/F7mO-9ENdfKqa89InlPUlg)'
+ '\n- [基于Springboot + vue3实现的个人健康管理系统](https://mp.weixin.qq.com/s/UUUh4S2KfOnRKnLKZLlS3Q)'
+ '\n- [基于Springboot + vue3实现的旅游网站系统](https://mp.weixin.qq.com/s/EY6XVtJXyY5FThfn0PoOew)'
+ '\n- [基于Springboot + vue3实现的房屋租售系统](https://mp.weixin.qq.com/s/tbDCa5504JwOt-ECt3t_Yg)'
+ '\n\n### 其他说明'
+ '\n>1、本系统源码由**程序员南音**精心收集整理,并经过严格测试验证,确保运行稳定可靠。'
+ '\n>2、创作不易如果觉得内容有帮助别忘了**点赞/推荐/分享/收藏**支持我们,您的鼓励是我们持续更新的最大动力!'
+ '\n>3、温馨提示系统可能存在少量待完善功能欢迎有技术热情的小伙伴共同参与优化改进。'
+ '\n\n# 源码获取'
+ '\n\n<center>'
+ '\n <img src="https://img.yidaima.cn/qrcode.jpg" style="width: 100px;">'
+ '\n <br>'
+ '\n <span>长按小程序码,打开小程序搜索 "<Strong style="color:var(--md-primary-color);">' + projectCode + '</Strong>" 即可获取资源</span>'
+ '\n</center>';
navigator.clipboard.writeText(content).then(() => {
this.$message({
message: '复制成功',
type: 'success'
});
}).catch(err => {
this.$message({
message: '复制失败: ' + err,
type: 'error'
});
loadCopyTemplates() {
listEnabledTemplates().then(response => {
this.copyTemplates = response.data || [];
});
},
copyXianyuTextToClipboard() {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n');
let content = this.form.codeName + '\n\n' + '### 项目描述' + '\n' + html2Text(codeDesc.trimEnd())
+ '\n\n' + '### 运行环境' + '\n' + this.form.codeEnvironment
+ '\n\n' + '### 项目技术' + '\n' + this.form.codeTechnology
+ '\n\n标价包含项目源码+数据库脚本+文档,没有调试解答,由于此商品的可复制性,发货后,不退不换,介意勿拍';
navigator.clipboard.writeText(content).then(() => {
this.$message({
message: '复制成功',
type: 'success'
});
}).catch(err => {
this.$message({
message: '复制失败: ' + err,
type: 'error'
});
});
},
copyXianyuTextToClipboard1() {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n');
// 提取纯文本描述作为功能部分
let functionDesc = html2Text(codeDesc.trimEnd());
// 分离项目编号、后端技术和前端技术
let projectName = this.form.codeName;
let projectCode = '';
let backendTech = '';
let frontendTech = '';
if (projectName) {
// 提取项目编号 【A075】
const codeMatch = projectName.match(/【(.+?)】/);
if (codeMatch && codeMatch[1]) {
projectCode = codeMatch[1];
}
// 去掉编号部分,提取项目名称
projectName = projectName.replace(/【.+?】/, '').trim();
if (projectName.startsWith('基于')) {
const nameMatch = projectName.match(/实现的(.+?)$/);
if (nameMatch && nameMatch[1]) {
projectName = nameMatch[1];
}
}
}
let content = projectName + 'Vue3JavaSpringBoot前后端分离可提供远程调试项目编号'+projectCode
+ '\n\n重要‼项目源码+环境部署教程+软件安装破解教程+项目运行教程'
+ '\n\n技术'
+ '\n①架构: B/S、MVC'
+ '\n②系统环境Windows/Mac'
+ '\n③开发环境' + this.form.codeEnvironment
+ '\n④技术栈' + this.form.codeTechnology
+ '\n\n功能'
+ '\n' + functionDesc;
navigator.clipboard.writeText(content).then(() => {
this.$message({
message: '复制成功',
type: 'success'
});
}).catch(err => {
this.$message({
message: '复制失败: ' + err,
type: 'error'
});
});
},
copyOtherTextToClipboard() {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n');
let content = this.form.codeName + '\n\n' + '### 项目描述' + '\n' + html2Text(codeDesc.trimEnd())
+ '\n\n' + '### 运行环境' + '\n' + this.form.codeEnvironment
+ '\n\n' + '### 项目技术' + '\n' + this.form.codeTechnology
+ '\n\n获取项目源码资源\\/X小CX南音源码库';
navigator.clipboard.writeText(content).then(() => {
this.$message({
message: '复制成功',
type: 'success'
});
}).catch(err => {
this.$message({
message: '复制失败: ' + err,
type: 'error'
});
});
},
copySiteTextToClipboard() {
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n\n');
let content = this.form.codeName + '\n\n' + '#### 项目描述' + '\n' + html2Text(codeDesc.trimEnd())
+ '\n\n' + '#### 运行环境' + '\n' + this.form.codeEnvironment
+ '\n\n' + '#### 项目技术' + '\n' + this.form.codeTechnology
+ '\n\n' + '#### 项目截图' + '\n';
let index = 0
if(this.form.fileList.length > 0){
for (let item of this.form.fileList) {
content = content + ++index + '.' + item.fileName
+ '\n' + '![](' + item.fileUrl + ')' + '\n\n';
}
} else {
content = content + '请前往微信小程序:南音源码库。查看项目详情!\n\n'
}
content = content + '#### 资源下载' + '\n' + '![](https://img.yidaima.cn/qrcode.jpg)' + '\n\n' + '请打开微信扫描上面小程序码,打开小程序搜索 "**项目编号**" 即可下载资源';
navigator.clipboard.writeText(content).then(() => {
this.$message({
message: '复制成功',
type: 'success'
});
}).catch(err => {
this.$message({
message: '复制失败: ' + err,
type: 'error'
});
});
cancelDetail() {
this.openDetail = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {

View File

@@ -0,0 +1,232 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="按钮名称" prop="templateName">
<el-input
v-model="queryParams.templateName"
placeholder="请输入按钮名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option label="正常" value="0" />
<el-option label="停用" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['office:copyTemplate:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['office:copyTemplate:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['office:copyTemplate:remove']">删除</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="templateList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="按钮名称" align="center" prop="templateName" width="160" />
<el-table-column label="排序" align="center" prop="sortNum" width="80" />
<el-table-column label="状态" align="center" prop="status" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">
{{ scope.row.status === '0' ? '正常' : '停用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="模板内容(预览)" align="left" prop="templateBody" show-overflow-tooltip />
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['office:copyTemplate:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['office:copyTemplate:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<!-- 新增或修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-form-item label="按钮名称" prop="templateName">
<el-input v-model="form.templateName" placeholder="请输入按钮显示名称,例如:复制网站文案" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="排序" prop="sortNum">
<el-input-number v-model="form.sortNum" :min="0" :max="999" style="width:100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="0">正常</el-radio>
<el-radio label="1">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="模板内容" prop="templateBody">
<el-input
v-model="form.templateBody"
type="textarea"
:rows="20"
placeholder="请输入文案模板内容,支持以下占位符:
{codeName} 项目名称(完整)
{projectCode} 项目编号(如 A075
{projectName} 纯项目名(去掉编号和基于...实现的前缀)
{codeDesc} 项目描述(纯文本)
{codeEnvironment} 运行环境
{codeTechnology} 项目技术
{diskLink} 网盘地址
{screenshots} 截图列表(自动生成 markdown 格式)"
/>
</el-form-item>
<el-alert type="info" :closable="false" style="margin-bottom:0">
<template slot="title">
<strong>支持的占位符</strong>
<code>{codeName}</code> 项目名称 &nbsp;
<code>{projectCode}</code> 项目编号 &nbsp;
<code>{projectName}</code> 纯项目名 &nbsp;
<code>{codeDesc}</code> 描述(纯文本) &nbsp;
<code>{codeEnvironment}</code> 运行环境 &nbsp;
<code>{codeTechnology}</code> 项目技术 &nbsp;
<code>{diskLink}</code> 网盘地址 &nbsp;
<code>{screenshots}</code> 截图列表
</template>
</el-alert>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listCopyTemplate, getCopyTemplate, addCopyTemplate, updateCopyTemplate, delCopyTemplate } from "@/api/office/copyTemplate";
export default {
name: "CopyTemplate",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
templateList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
templateName: null,
status: null
},
form: {},
rules: {
templateName: [{ required: true, message: "按钮名称不能为空", trigger: "blur" }],
templateBody: [{ required: true, message: "模板内容不能为空", trigger: "blur" }],
sortNum: [{ required: true, message: "排序不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listCopyTemplate(this.queryParams).then(response => {
this.templateList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
templateId: null,
templateName: null,
templateBody: null,
sortNum: 0,
status: "0"
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.templateId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "新增文案模板";
},
handleUpdate(row) {
this.reset();
const templateId = row.templateId || this.ids;
getCopyTemplate(templateId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改文案模板";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.templateId != null) {
updateCopyTemplate(this.form).then(() => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addCopyTemplate(this.form).then(() => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const templateIds = row.templateId || this.ids;
this.$modal.confirm('是否确认删除文案模板"' + (row.templateName || '') + '"').then(() => {
return delCopyTemplate(templateIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
}
};
</script>