feat: 优化文案模板分组与复制预览
This commit is contained in:
@@ -21,6 +21,10 @@ public class TtCopyTemplate extends BaseEntity {
|
||||
@Excel(name = "按钮名称")
|
||||
private String templateName;
|
||||
|
||||
/** 模板分组 */
|
||||
@Excel(name = "模板分组")
|
||||
private String templateGroup;
|
||||
|
||||
/** 文案模板内容,支持 {变量} 占位符 */
|
||||
@Excel(name = "模板内容")
|
||||
private String templateBody;
|
||||
@@ -49,6 +53,14 @@ public class TtCopyTemplate extends BaseEntity {
|
||||
return templateName;
|
||||
}
|
||||
|
||||
public void setTemplateGroup(String templateGroup) {
|
||||
this.templateGroup = templateGroup;
|
||||
}
|
||||
|
||||
public String getTemplateGroup() {
|
||||
return templateGroup;
|
||||
}
|
||||
|
||||
public void setTemplateBody(String templateBody) {
|
||||
this.templateBody = templateBody;
|
||||
}
|
||||
@@ -78,6 +90,7 @@ public class TtCopyTemplate extends BaseEntity {
|
||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("templateId", getTemplateId())
|
||||
.append("templateName", getTemplateName())
|
||||
.append("templateGroup", getTemplateGroup())
|
||||
.append("templateBody", getTemplateBody())
|
||||
.append("sortNum", getSortNum())
|
||||
.append("status", getStatus())
|
||||
@@ -85,4 +98,4 @@ public class TtCopyTemplate extends BaseEntity {
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<resultMap type="TtCopyTemplate" id="TtCopyTemplateResult">
|
||||
<result property="templateId" column="template_id" />
|
||||
<result property="templateName" column="template_name" />
|
||||
<result property="templateGroup" column="template_group" />
|
||||
<result property="templateBody" column="template_body" />
|
||||
<result property="sortNum" column="sort_num" />
|
||||
<result property="status" column="status" />
|
||||
@@ -15,7 +16,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectTtCopyTemplateVo">
|
||||
select template_id, template_name, template_body, sort_num, status, create_time, update_time
|
||||
select template_id, template_name, template_group, template_body, sort_num, status, create_time, update_time
|
||||
from tt_copy_template
|
||||
</sql>
|
||||
|
||||
@@ -23,6 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<include refid="selectTtCopyTemplateVo"/>
|
||||
<where>
|
||||
<if test="templateName != null and templateName != ''"> and template_name like concat('%', #{templateName}, '%')</if>
|
||||
<if test="templateGroup != null and templateGroup != ''"> and template_group like concat('%', #{templateGroup}, '%')</if>
|
||||
<if test="status != null and status != ''"> and status = #{status}</if>
|
||||
</where>
|
||||
order by sort_num asc, create_time asc
|
||||
@@ -43,6 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
insert into tt_copy_template
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="templateName != null and templateName != ''">template_name,</if>
|
||||
<if test="templateGroup != null and templateGroup != ''">template_group,</if>
|
||||
<if test="templateBody != null">template_body,</if>
|
||||
<if test="sortNum != null">sort_num,</if>
|
||||
<if test="status != null and status != ''">status,</if>
|
||||
@@ -51,6 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="templateName != null and templateName != ''">#{templateName},</if>
|
||||
<if test="templateGroup != null and templateGroup != ''">#{templateGroup},</if>
|
||||
<if test="templateBody != null">#{templateBody},</if>
|
||||
<if test="sortNum != null">#{sortNum},</if>
|
||||
<if test="status != null and status != ''">#{status},</if>
|
||||
@@ -63,6 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
update tt_copy_template
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="templateName != null and templateName != ''">template_name = #{templateName},</if>
|
||||
<if test="templateGroup != null and templateGroup != ''">template_group = #{templateGroup},</if>
|
||||
<if test="templateBody != null">template_body = #{templateBody},</if>
|
||||
<if test="sortNum != null">sort_num = #{sortNum},</if>
|
||||
<if test="status != null and status != ''">status = #{status},</if>
|
||||
@@ -82,4 +87,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
||||
@@ -154,6 +154,14 @@
|
||||
v-hasPermi="['office:code:query']"
|
||||
>查看
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-document"
|
||||
@click="handleCopywriting(scope.row)"
|
||||
v-hasPermi="['office:code:query']"
|
||||
>文案
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
@@ -275,6 +283,90 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 文案预览对话框 -->
|
||||
<el-dialog
|
||||
:visible.sync="copywritingDialogVisible"
|
||||
width="92%"
|
||||
custom-class="copywriting-dialog-window"
|
||||
append-to-body
|
||||
@closed="resetCopywritingDialog"
|
||||
>
|
||||
<template slot="title">
|
||||
<div class="copywriting-dialog-title">
|
||||
<span>文案:</span>
|
||||
<span
|
||||
class="copywriting-project-name"
|
||||
:title="copywritingProject.codeName || ''"
|
||||
>{{ copywritingProject.codeName || '' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-loading="copywritingLoading" class="copywriting-shell">
|
||||
<el-radio-group
|
||||
v-if="groupedCopyTemplates.length"
|
||||
v-model="copywritingGroupName"
|
||||
size="small"
|
||||
class="copywriting-group-tabs"
|
||||
@change="handleCopywritingGroupChange"
|
||||
>
|
||||
<el-radio-button
|
||||
v-for="group in groupedCopyTemplates"
|
||||
:key="group.name"
|
||||
:label="group.name"
|
||||
>
|
||||
{{ group.name }}
|
||||
<span class="copywriting-group-count">{{ group.templates.length }}</span>
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
||||
<div v-if="groupedCopyTemplates.length" class="copywriting-layout">
|
||||
<div class="copywriting-template-panel">
|
||||
<div class="copywriting-panel-title">模板列表</div>
|
||||
<div v-if="activeCopywritingTemplates.length" class="copywriting-template-list">
|
||||
<button
|
||||
v-for="tpl in activeCopywritingTemplates"
|
||||
:key="tpl.templateId"
|
||||
type="button"
|
||||
class="copywriting-template-item"
|
||||
:class="{ 'is-active': tpl.templateId === copywritingTemplateId }"
|
||||
@click="selectCopywritingTemplate(tpl)"
|
||||
>
|
||||
<span>{{ tpl.templateName }}</span>
|
||||
<i
|
||||
v-if="tpl.templateId === copywritingTemplateId"
|
||||
class="el-icon-check"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="copywriting-empty">暂无启用的文案模板</div>
|
||||
</div>
|
||||
|
||||
<div class="copywriting-preview-panel">
|
||||
<div class="copywriting-panel-title">文案预览</div>
|
||||
<pre class="copywriting-preview">{{ copywritingContent }}</pre>
|
||||
<div class="copywriting-preview-footer">
|
||||
<span>字数:{{ copywritingContent.length }}</span>
|
||||
<div>
|
||||
<el-button
|
||||
:disabled="!copywritingTemplateId"
|
||||
@click="copyCurrentWriting(true)"
|
||||
>复制并关闭</el-button>
|
||||
<el-button
|
||||
:type="copywritingCopied ? 'success' : 'primary'"
|
||||
:icon="copywritingCopied ? 'el-icon-check' : 'el-icon-document-copy'"
|
||||
:disabled="!copywritingTemplateId"
|
||||
@click="copyCurrentWriting(false)"
|
||||
>{{ copywritingCopied ? '已复制' : '复制文案' }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="copywriting-empty-state">
|
||||
暂无启用的文案模板
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 封面预览对话框 -->
|
||||
<el-dialog :title="'封面预览'" :visible.sync="coverDialogVisible" width="500px" append-to-body>
|
||||
<el-form label-width="80px">
|
||||
@@ -340,6 +432,14 @@
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
openDetail: false,
|
||||
// 文案预览弹窗
|
||||
copywritingDialogVisible: false,
|
||||
copywritingLoading: false,
|
||||
copywritingProject: {},
|
||||
copywritingTemplateId: null,
|
||||
copywritingGroupName: '',
|
||||
copywritingCopied: false,
|
||||
copywritingCopyTimer: null,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
@@ -383,11 +483,36 @@
|
||||
this.getList();
|
||||
this.loadCopyTemplates();
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.copywritingCopyTimer) {
|
||||
clearTimeout(this.copywritingCopyTimer);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
previewList() {
|
||||
return this.form.fileList.map(i => {
|
||||
return i.fileUrl
|
||||
})
|
||||
},
|
||||
copywritingContent() {
|
||||
const template = this.copyTemplates.find(item => item.templateId === this.copywritingTemplateId);
|
||||
return template ? this.renderCopyTemplate(template, this.copywritingProject) : '';
|
||||
},
|
||||
groupedCopyTemplates() {
|
||||
return this.copyTemplates.reduce((groups, template) => {
|
||||
const groupName = (template.templateGroup || '').trim() || '默认分组';
|
||||
let group = groups.find(item => item.name === groupName);
|
||||
if (!group) {
|
||||
group = { name: groupName, templates: [] };
|
||||
groups.push(group);
|
||||
}
|
||||
group.templates.push(template);
|
||||
return groups;
|
||||
}, []);
|
||||
},
|
||||
activeCopywritingTemplates() {
|
||||
const group = this.groupedCopyTemplates.find(item => item.name === this.copywritingGroupName);
|
||||
return group ? group.templates : [];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -426,9 +551,10 @@
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
copyByTemplate(tpl) {
|
||||
renderCopyTemplate(tpl, source) {
|
||||
// 从数据库模板中提取并替换占位符
|
||||
let codeName = this.form.codeName || '';
|
||||
const code = source || {};
|
||||
let codeName = code.codeName || '';
|
||||
let projectCode = '';
|
||||
let projectName = codeName;
|
||||
|
||||
@@ -448,16 +574,16 @@
|
||||
|
||||
// 项目描述转纯文本
|
||||
let plainDesc = '';
|
||||
if (this.form.codeDesc) {
|
||||
let codeDesc = this.form.codeDesc.replace(/<\/p>/g, '</p>\n');
|
||||
if (code.codeDesc) {
|
||||
let codeDesc = code.codeDesc.replace(/<\/p>/g, '</p>\n');
|
||||
plainDesc = html2Text(codeDesc.trimEnd());
|
||||
}
|
||||
|
||||
// 生成截图列表
|
||||
let screenshots = '';
|
||||
let index = 0;
|
||||
if (this.form.fileList && this.form.fileList.length > 0) {
|
||||
for (let item of this.form.fileList) {
|
||||
if (code.fileList && code.fileList.length > 0) {
|
||||
for (let item of code.fileList) {
|
||||
screenshots = screenshots + ++index + '.' + item.fileName + '\n\n\n';
|
||||
}
|
||||
} else {
|
||||
@@ -470,13 +596,17 @@
|
||||
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(/{frontendTechnology}/g, this.form.frontendTechnology || '');
|
||||
content = content.replace(/{backendTechnology}/g, this.form.backendTechnology || '');
|
||||
content = content.replace(/{databaseTechnology}/g, this.form.databaseTechnology || '');
|
||||
content = content.replace(/{codeTechnology}/g, this.form.codeTechnology || '');
|
||||
content = content.replace(/{diskLink}/g, this.form.diskLink || '');
|
||||
content = content.replace(/{codeEnvironment}/g, code.codeEnvironment || '');
|
||||
content = content.replace(/{frontendTechnology}/g, code.frontendTechnology || '');
|
||||
content = content.replace(/{backendTechnology}/g, code.backendTechnology || '');
|
||||
content = content.replace(/{databaseTechnology}/g, code.databaseTechnology || '');
|
||||
content = content.replace(/{codeTechnology}/g, code.codeTechnology || '');
|
||||
content = content.replace(/{diskLink}/g, code.diskLink || '');
|
||||
content = content.replace(/{screenshots}/g, screenshots);
|
||||
return content;
|
||||
},
|
||||
copyByTemplate(tpl) {
|
||||
const content = this.renderCopyTemplate(tpl, this.form);
|
||||
|
||||
navigator.clipboard.writeText(content).then(() => {
|
||||
this.$message({ message: '复制成功', type: 'success' });
|
||||
@@ -488,8 +618,49 @@
|
||||
listEnabledTemplates().then(response => {
|
||||
this.copyTemplates = response.data || [];
|
||||
this.selectDefaultArticleTemplate();
|
||||
this.selectDefaultCopywritingTemplate();
|
||||
});
|
||||
},
|
||||
selectDefaultCopywritingTemplate() {
|
||||
if (!this.copyTemplates.length) {
|
||||
this.copywritingTemplateId = null;
|
||||
this.copywritingGroupName = '';
|
||||
return;
|
||||
}
|
||||
let selectedTemplate = this.copyTemplates.find(tpl => tpl.templateId === this.copywritingTemplateId);
|
||||
if (!selectedTemplate) {
|
||||
let lastTemplateId = '';
|
||||
try {
|
||||
lastTemplateId = window.localStorage.getItem('officeCopywritingTemplateId') || '';
|
||||
} catch (error) {
|
||||
lastTemplateId = '';
|
||||
}
|
||||
selectedTemplate = this.copyTemplates.find(tpl => String(tpl.templateId) === lastTemplateId)
|
||||
|| this.copyTemplates[0];
|
||||
}
|
||||
this.selectCopywritingTemplate(selectedTemplate);
|
||||
},
|
||||
getCopywritingGroupName(template) {
|
||||
return ((template && template.templateGroup) || '').trim() || '默认分组';
|
||||
},
|
||||
selectCopywritingTemplate(template) {
|
||||
if (!template) {
|
||||
return;
|
||||
}
|
||||
this.copywritingTemplateId = template.templateId;
|
||||
this.copywritingGroupName = this.getCopywritingGroupName(template);
|
||||
this.copywritingCopied = false;
|
||||
try {
|
||||
window.localStorage.setItem('officeCopywritingTemplateId', String(template.templateId));
|
||||
} catch (error) {
|
||||
}
|
||||
},
|
||||
handleCopywritingGroupChange(groupName) {
|
||||
const group = this.groupedCopyTemplates.find(item => item.name === groupName);
|
||||
if (group && group.templates.length) {
|
||||
this.selectCopywritingTemplate(group.templates[0]);
|
||||
}
|
||||
},
|
||||
selectDefaultArticleTemplate() {
|
||||
if (!this.copyTemplates.length) {
|
||||
this.articleTemplateId = null;
|
||||
@@ -584,6 +755,57 @@
|
||||
this.title = "查看源码信息";
|
||||
});
|
||||
},
|
||||
/** 文案预览按钮操作 */
|
||||
handleCopywriting(row) {
|
||||
this.copywritingLoading = true;
|
||||
this.copywritingProject = {};
|
||||
this.copywritingTemplateId = null;
|
||||
this.copywritingGroupName = '';
|
||||
this.copywritingCopied = false;
|
||||
this.copywritingDialogVisible = true;
|
||||
this.selectDefaultCopywritingTemplate();
|
||||
getCode(row.codeId).then(response => {
|
||||
this.copywritingProject = response.data || {};
|
||||
}).catch(() => {
|
||||
this.copywritingDialogVisible = false;
|
||||
}).finally(() => {
|
||||
this.copywritingLoading = false;
|
||||
});
|
||||
},
|
||||
resetCopywritingDialog() {
|
||||
if (this.copywritingCopyTimer) {
|
||||
clearTimeout(this.copywritingCopyTimer);
|
||||
this.copywritingCopyTimer = null;
|
||||
}
|
||||
this.copywritingProject = {};
|
||||
this.copywritingTemplateId = null;
|
||||
this.copywritingGroupName = '';
|
||||
this.copywritingCopied = false;
|
||||
this.copywritingLoading = false;
|
||||
},
|
||||
copyCurrentWriting(closeAfterCopy) {
|
||||
if (!this.copywritingTemplateId) {
|
||||
this.$modal.msgError('请选择文案模板');
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(this.copywritingContent).then(() => {
|
||||
if (closeAfterCopy) {
|
||||
this.copywritingDialogVisible = false;
|
||||
this.$modal.msgSuccess('文案复制成功');
|
||||
return;
|
||||
}
|
||||
this.copywritingCopied = true;
|
||||
if (this.copywritingCopyTimer) {
|
||||
clearTimeout(this.copywritingCopyTimer);
|
||||
}
|
||||
this.copywritingCopyTimer = setTimeout(() => {
|
||||
this.copywritingCopied = false;
|
||||
this.copywritingCopyTimer = null;
|
||||
}, 1800);
|
||||
}).catch(error => {
|
||||
this.$modal.msgError('复制失败:' + error);
|
||||
});
|
||||
},
|
||||
showCoverDialog(row) {
|
||||
this.currentRow = row
|
||||
this.selectDefaultArticleTemplate()
|
||||
@@ -702,3 +924,198 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.copywriting-dialog-window {
|
||||
max-width: 1180px;
|
||||
}
|
||||
|
||||
.copywriting-dialog-title {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
padding-right: 40px;
|
||||
color: #303133;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.copywriting-project-name {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.copywriting-shell {
|
||||
min-height: 420px;
|
||||
}
|
||||
|
||||
.copywriting-group-tabs {
|
||||
display: flex;
|
||||
max-width: 100%;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 4px;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.copywriting-group-count {
|
||||
display: inline-block;
|
||||
min-width: 18px;
|
||||
margin-left: 4px;
|
||||
padding: 0 5px;
|
||||
border-radius: 9px;
|
||||
background: rgba(144, 147, 153, 0.16);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.copywriting-layout {
|
||||
display: flex;
|
||||
height: 62vh;
|
||||
min-height: 420px;
|
||||
max-height: 620px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.copywriting-template-panel {
|
||||
flex: 0 0 240px;
|
||||
padding: 18px 14px;
|
||||
border-right: 1px solid #dcdfe6;
|
||||
background: #fafafa;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.copywriting-preview-panel {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 20px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.copywriting-panel-title {
|
||||
margin-bottom: 14px;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.copywriting-template-list {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.copywriting-template-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
padding: 11px 12px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.copywriting-template-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.copywriting-template-item:hover {
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.copywriting-template-item.is-active {
|
||||
border-color: #b3d8ff;
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.copywriting-template-item span {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.copywriting-template-item i {
|
||||
flex: none;
|
||||
margin-left: 8px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.copywriting-empty {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.copywriting-empty-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 420px;
|
||||
border: 1px solid #ebeef5;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.copywriting-preview {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
background: #fafafa;
|
||||
color: #303133;
|
||||
font-family: Consolas, "Courier New", monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.copywriting-preview-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-top: 16px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.copywriting-layout {
|
||||
height: 68vh;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.copywriting-template-panel {
|
||||
flex: 0 0 auto;
|
||||
max-height: 180px;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.copywriting-preview-panel {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.copywriting-preview-footer {
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板分组" prop="templateGroup">
|
||||
<el-input
|
||||
v-model="queryParams.templateGroup"
|
||||
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" />
|
||||
@@ -37,6 +45,7 @@
|
||||
<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="templateGroup" width="140" />
|
||||
<el-table-column label="排序" align="center" prop="sortNum" width="80" />
|
||||
<el-table-column label="状态" align="center" prop="status" width="100">
|
||||
<template slot-scope="scope">
|
||||
@@ -63,6 +72,9 @@
|
||||
<el-form-item label="按钮名称" prop="templateName">
|
||||
<el-input v-model="form.templateName" placeholder="请输入按钮显示名称,例如:复制网站文案" />
|
||||
</el-form-item>
|
||||
<el-form-item label="模板分组" prop="templateGroup">
|
||||
<el-input v-model="form.templateGroup" placeholder="请输入模板分组,例如:闲鱼、公众号" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="排序" prop="sortNum">
|
||||
@@ -142,11 +154,13 @@ export default {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
templateName: null,
|
||||
templateGroup: null,
|
||||
status: null
|
||||
},
|
||||
form: {},
|
||||
rules: {
|
||||
templateName: [{ required: true, message: "按钮名称不能为空", trigger: "blur" }],
|
||||
templateGroup: [{ required: true, message: "模板分组不能为空", trigger: "blur" }],
|
||||
templateBody: [{ required: true, message: "模板内容不能为空", trigger: "blur" }],
|
||||
sortNum: [{ required: true, message: "排序不能为空", trigger: "blur" }]
|
||||
}
|
||||
@@ -172,6 +186,7 @@ export default {
|
||||
this.form = {
|
||||
templateId: null,
|
||||
templateName: null,
|
||||
templateGroup: "默认分组",
|
||||
templateBody: null,
|
||||
sortNum: 0,
|
||||
status: "0"
|
||||
|
||||
@@ -5,6 +5,7 @@ DROP TABLE IF EXISTS tt_copy_template;
|
||||
CREATE TABLE tt_copy_template (
|
||||
template_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '模板ID',
|
||||
template_name VARCHAR(100) NOT NULL COMMENT '按钮显示名称',
|
||||
template_group VARCHAR(100) NOT NULL DEFAULT '默认分组' COMMENT '模板分组',
|
||||
template_body LONGTEXT NOT NULL COMMENT '文案模板内容,支持 {变量} 占位符',
|
||||
sort_num INT DEFAULT 0 COMMENT '排序号',
|
||||
status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
|
||||
8
sql/copy_template_group.sql
Normal file
8
sql/copy_template_group.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- 文案模板增加分组字段(已有数据库升级脚本)
|
||||
ALTER TABLE `tt_copy_template`
|
||||
ADD COLUMN `template_group` VARCHAR(100) NOT NULL DEFAULT '默认分组' COMMENT '模板分组' AFTER `template_name`;
|
||||
|
||||
-- 兼容历史空数据
|
||||
UPDATE `tt_copy_template`
|
||||
SET `template_group` = '默认分组'
|
||||
WHERE `template_group` IS NULL OR TRIM(`template_group`) = '';
|
||||
Reference in New Issue
Block a user