290 lines
8.3 KiB
Vue
290 lines
8.3 KiB
Vue
<template>
|
||
<div class="prompt-config-container">
|
||
<el-card class="box-card">
|
||
<div slot="header" class="clearfix">
|
||
<span class="card-title">
|
||
<i class="el-icon-setting"></i>
|
||
DS提示词模板配置
|
||
</span>
|
||
<el-button
|
||
style="float: right; padding: 3px 0"
|
||
type="text"
|
||
@click="showHelp = !showHelp">
|
||
{{ showHelp ? '隐藏帮助' : '显示帮助' }}
|
||
</el-button>
|
||
</div>
|
||
|
||
<!-- 帮助说明 -->
|
||
<el-collapse-transition>
|
||
<div v-show="showHelp" class="help-section">
|
||
<el-alert
|
||
title="使用说明"
|
||
type="info"
|
||
:closable="false"
|
||
show-icon>
|
||
<div slot="default">
|
||
<p><strong>功能说明:</strong></p>
|
||
<ul>
|
||
<li>配置DS(DeepSeek)AI的提示词模板,用于生成关键词和文案</li>
|
||
<li>模板存储在Redis中,修改后立即生效</li>
|
||
<li>支持占位符:%s 用于替换实际内容</li>
|
||
<li>删除模板将恢复为系统默认模板</li>
|
||
</ul>
|
||
<p><strong>模板类型:</strong></p>
|
||
<ul>
|
||
<li><strong>关键词提取模板</strong>:用于提取商品关键词,占位符:%s = 商品名称</li>
|
||
<li><strong>小红书文案模板</strong>:用于生成小红书风格文案,占位符:%s = 商品名称,%s = 价格信息,%s = 关键词</li>
|
||
<li><strong>抖音文案模板</strong>:用于生成抖音风格文案,占位符:%s = 商品名称,%s = 价格信息,%s = 关键词</li>
|
||
<li><strong>通用文案模板</strong>:用于生成通用风格文案,占位符:%s = 商品名称,%s = 价格信息,%s = 关键词</li>
|
||
</ul>
|
||
</div>
|
||
</el-alert>
|
||
</div>
|
||
</el-collapse-transition>
|
||
|
||
<!-- 模板列表 -->
|
||
<div class="template-list">
|
||
<el-tabs v-model="activeTab" type="border-card">
|
||
<el-tab-pane
|
||
v-for="(template, key) in templates"
|
||
:key="key"
|
||
:label="getTemplateLabel(key)"
|
||
:name="key">
|
||
<div class="template-editor">
|
||
<div class="template-info">
|
||
<el-alert
|
||
:title="template.description"
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
style="margin-bottom: 15px;">
|
||
</el-alert>
|
||
|
||
<div class="template-status">
|
||
<el-tag :type="template.isDefault ? 'info' : 'success'" size="small">
|
||
{{ template.isDefault ? '使用默认模板' : '使用自定义模板' }}
|
||
</el-tag>
|
||
<el-button
|
||
v-if="!template.isDefault"
|
||
type="text"
|
||
size="small"
|
||
icon="el-icon-refresh-left"
|
||
@click="handleResetTemplate(key)"
|
||
style="margin-left: 10px;">
|
||
恢复默认
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-input
|
||
v-model="template.template"
|
||
type="textarea"
|
||
:rows="12"
|
||
placeholder="请输入提示词模板..."
|
||
class="template-textarea">
|
||
</el-input>
|
||
|
||
<div class="template-actions">
|
||
<el-button
|
||
type="primary"
|
||
icon="el-icon-check"
|
||
@click="handleSaveTemplate(key)"
|
||
:loading="saving[key]">
|
||
保存模板
|
||
</el-button>
|
||
<el-button
|
||
icon="el-icon-refresh"
|
||
@click="handleLoadTemplate(key)">
|
||
重新加载
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { listPromptTemplates, getPromptTemplate, savePromptTemplate, deletePromptTemplate } from '@/api/jarvis/socialMediaPrompt'
|
||
|
||
export default {
|
||
name: 'SocialMediaPromptConfig',
|
||
data() {
|
||
return {
|
||
showHelp: false,
|
||
activeTab: 'keywords',
|
||
templates: {},
|
||
saving: {}
|
||
}
|
||
},
|
||
mounted() {
|
||
this.loadTemplates()
|
||
},
|
||
methods: {
|
||
/** 加载所有模板 */
|
||
async loadTemplates() {
|
||
try {
|
||
const res = await listPromptTemplates()
|
||
if (res.code === 200 && res.data) {
|
||
this.templates = res.data
|
||
// 初始化保存状态
|
||
Object.keys(this.templates).forEach(key => {
|
||
this.$set(this.saving, key, false)
|
||
})
|
||
} else {
|
||
this.$message.error(res.msg || '加载模板失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('加载模板失败', error)
|
||
this.$message.error('加载模板失败:' + (error.message || '未知错误'))
|
||
}
|
||
},
|
||
|
||
/** 加载单个模板 */
|
||
async handleLoadTemplate(key) {
|
||
try {
|
||
const res = await getPromptTemplate(key)
|
||
if (res.code === 200 && res.data) {
|
||
this.$set(this.templates, key, res.data)
|
||
this.$message.success('重新加载成功')
|
||
} else {
|
||
this.$message.error(res.msg || '加载失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('加载模板失败', error)
|
||
this.$message.error('加载失败:' + (error.message || '未知错误'))
|
||
}
|
||
},
|
||
|
||
/** 保存模板 */
|
||
async handleSaveTemplate(key) {
|
||
const template = this.templates[key]
|
||
if (!template || !template.template || template.template.trim() === '') {
|
||
this.$message.warning('模板内容不能为空')
|
||
return
|
||
}
|
||
|
||
this.$set(this.saving, key, true)
|
||
try {
|
||
const res = await savePromptTemplate({
|
||
key: key,
|
||
template: template.template.trim()
|
||
})
|
||
|
||
if (res.code === 200) {
|
||
this.$message.success('保存成功!')
|
||
// 更新状态
|
||
this.$set(template, 'isDefault', false)
|
||
// 重新加载以确认
|
||
await this.handleLoadTemplate(key)
|
||
} else {
|
||
this.$message.error(res.msg || '保存失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('保存模板失败', error)
|
||
this.$message.error('保存失败:' + (error.message || '未知错误'))
|
||
} finally {
|
||
this.$set(this.saving, key, false)
|
||
}
|
||
},
|
||
|
||
/** 恢复默认模板 */
|
||
async handleResetTemplate(key) {
|
||
try {
|
||
await this.$confirm('确定要恢复默认模板吗?自定义模板将被删除。', '提示', {
|
||
type: 'warning'
|
||
})
|
||
|
||
const res = await deletePromptTemplate(key)
|
||
if (res.code === 200) {
|
||
this.$message.success('已恢复默认模板')
|
||
// 重新加载
|
||
await this.handleLoadTemplate(key)
|
||
} else {
|
||
this.$message.error(res.msg || '恢复失败')
|
||
}
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('恢复默认模板失败', error)
|
||
this.$message.error('恢复失败:' + (error.message || '未知错误'))
|
||
}
|
||
}
|
||
},
|
||
|
||
/** 获取模板标签 */
|
||
getTemplateLabel(key) {
|
||
const labels = {
|
||
'keywords': '关键词提取',
|
||
'content:xhs': '小红书文案',
|
||
'content:douyin': '抖音文案',
|
||
'content:both': '通用文案'
|
||
}
|
||
return labels[key] || key
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.prompt-config-container {
|
||
padding: 20px;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.help-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.help-section ul {
|
||
margin: 10px 0;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
.help-section li {
|
||
margin: 5px 0;
|
||
}
|
||
|
||
.template-list {
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.template-editor {
|
||
padding: 20px;
|
||
}
|
||
|
||
.template-info {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.template-status {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.template-textarea {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.template-textarea >>> .el-textarea__inner {
|
||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.template-actions {
|
||
text-align: right;
|
||
}
|
||
|
||
.template-actions .el-button {
|
||
margin-left: 10px;
|
||
}
|
||
</style>
|
||
|