refactor(StyleSelector): simplify component by removing agent integration and using unified prompt list
Removed separate user prompts and favorite agents groups, replaced with a single unified list from /ai/user-prompt/my-list endpoint. Removed agent-related functionality including API calls, filtering logic, and type handling since the component now only works with user prompts. Simplified the UI structure and filtering mechanism to work with the new data model.
This commit is contained in:
@@ -1,904 +0,0 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onActivated, computed, watch } from 'vue'
|
||||
import { usePromptStore } from '@/stores/prompt'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { CommonService } from '@/api/common'
|
||||
import useVoiceText from '@/hooks/web/useVoiceText'
|
||||
import GmIcon from '@/components/icons/Icon.vue'
|
||||
import GradientButton from '@/components/GradientButton.vue'
|
||||
import PromptSelector from '@/components/PromptSelector.vue'
|
||||
import { copyToClipboard } from '@/utils/clipboard'
|
||||
import BasicLayout from '@/layouts/components/BasicLayout.vue'
|
||||
|
||||
const promptStore = usePromptStore()
|
||||
const userStore = useUserStore()
|
||||
const md = new MarkdownIt()
|
||||
|
||||
// 表单数据
|
||||
const form = ref({
|
||||
prompt: '',
|
||||
userInput: '',
|
||||
amplitude: 50
|
||||
})
|
||||
|
||||
// 生成的文案内容
|
||||
const generatedContent = ref('')
|
||||
|
||||
// 编辑模式相关
|
||||
const isEditMode = ref(false)
|
||||
const editableContent = ref('')
|
||||
const originalContent = ref('')
|
||||
|
||||
// 加载状态
|
||||
const isLoading = ref(false)
|
||||
const { getVoiceText } = useVoiceText()
|
||||
|
||||
// ===== 使用 Store 作为单一数据源 =====
|
||||
const selectedPromptId = ref(null)
|
||||
|
||||
// 处理提示词选择
|
||||
function handlePromptChange(prompt) {
|
||||
if (!prompt || !prompt.content) {
|
||||
message.warning('提示词内容为空')
|
||||
return
|
||||
}
|
||||
|
||||
selectedPromptId.value = prompt.id
|
||||
form.value.prompt = prompt.content
|
||||
promptStore.setPrompt(prompt.content, prompt)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化页面数据
|
||||
* 通过 Store 加载提示词(Store 会自动缓存)
|
||||
*/
|
||||
async function initializePage() {
|
||||
// 恢复之前保存的提示词
|
||||
if (promptStore.currentPrompt) {
|
||||
form.value.prompt = promptStore.currentPrompt
|
||||
}
|
||||
|
||||
// 加载提示词列表(自建 + 收藏,Store 会自动缓存)
|
||||
await promptStore.loadPromptList()
|
||||
|
||||
// 如果有选中的提示词,同步 ID
|
||||
if (promptStore.currentVideoInfo?.id) {
|
||||
selectedPromptId.value = promptStore.currentVideoInfo.id
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时初始化
|
||||
onMounted(() => {
|
||||
initializePage()
|
||||
})
|
||||
|
||||
// 生成文案(流式)
|
||||
async function generateCopywriting() {
|
||||
const inputContent = form.value.userInput || ''
|
||||
|
||||
if (!inputContent.trim()) {
|
||||
message.warning('请输入内容')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否选择了风格
|
||||
if (!form.value.prompt || !form.value.prompt.trim()) {
|
||||
message.warning('请先选择文案风格')
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedPromptId.value) {
|
||||
message.warning('请先选择文案风格')
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
generatedContent.value = '' // 清空之前的内容
|
||||
|
||||
try {
|
||||
// 如果看起来是视频/音频链接,先尝试转写;否则直接作为文本
|
||||
let userText = inputContent
|
||||
if (isLikelyUrl(inputContent)) {
|
||||
try {
|
||||
message.info('正在获取视频转写...')
|
||||
const transcriptions = await getVoiceText([{ audio_url: inputContent }])
|
||||
const transcript = Array.isArray(transcriptions) && transcriptions[0] ? (transcriptions[0].value || '') : ''
|
||||
if (transcript.trim()) {
|
||||
userText = transcript
|
||||
} else {
|
||||
message.warning('未从链接获取到可用的语音文本,将直接使用原始输入')
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('获取转写失败,使用原始输入:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 callWorkflow 流式 API
|
||||
const requestData = {
|
||||
audio_prompt: form.value.prompt || '', // 音频提示词
|
||||
user_text: userText, // 用户输入内容或由链接转写得到的文本
|
||||
amplitude: form.value.amplitude // 幅度,范围 0-100
|
||||
}
|
||||
|
||||
const ctrl = new AbortController()
|
||||
let fullText = ''
|
||||
let errorOccurred = false
|
||||
let isResolved = false
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
// 设置超时
|
||||
const timeout = setTimeout(() => {
|
||||
if (!isResolved) {
|
||||
ctrl.abort()
|
||||
reject(new Error('请求超时,请稍后重试'))
|
||||
}
|
||||
}, 180000) // 3分钟超时
|
||||
|
||||
CommonService.callWorkflowStream({
|
||||
data: requestData,
|
||||
ctrl,
|
||||
onMessage: (event) => {
|
||||
try {
|
||||
if (errorOccurred) return
|
||||
|
||||
const dataStr = event?.data || ''
|
||||
if (!dataStr) return
|
||||
|
||||
try {
|
||||
const obj = JSON.parse(dataStr)
|
||||
// 根据实际返回格式解析
|
||||
const piece = obj?.text || obj?.content || obj?.data || ''
|
||||
if (piece) {
|
||||
fullText += piece
|
||||
generatedContent.value = fullText
|
||||
}
|
||||
} catch (parseErr) {
|
||||
console.warn('解析流数据异常:', parseErr)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('解析流数据异常:', e)
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
clearTimeout(timeout)
|
||||
if (!isResolved) {
|
||||
errorOccurred = true
|
||||
ctrl.abort()
|
||||
|
||||
// 尝试解析错误中的状态码和业务码
|
||||
const status = err?.response?.status
|
||||
const data = err?.response?.data
|
||||
|
||||
const errorMsg = err?.message || '网络请求失败'
|
||||
console.error('SSE请求错误:', err)
|
||||
message.error(errorMsg)
|
||||
reject(new Error(errorMsg))
|
||||
}
|
||||
},
|
||||
onClose: () => {
|
||||
clearTimeout(timeout)
|
||||
if (!isResolved) {
|
||||
isResolved = true
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
generatedContent.value = fullText.trim()
|
||||
message.success('文案生成成功')
|
||||
} catch (error) {
|
||||
console.error('生成文案失败:', error)
|
||||
message.error('生成文案失败,请重试')
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 获取当前输入值
|
||||
function getCurrentInputValue() {
|
||||
return (form.value.userInput || '').trim()
|
||||
}
|
||||
|
||||
// 粗略判断是否为 URL(含常见平台域名或 http(s) 开头)
|
||||
function isLikelyUrl(value) {
|
||||
if (!value) return false
|
||||
const v = String(value).trim()
|
||||
if (/^https?:\/\//i.test(v)) return true
|
||||
return /(douyin\.com|bilibili\.com|youtube\.com|youtu\.be|tiktok\.com|ixigua\.com|v\.qq\.com)/i.test(v)
|
||||
}
|
||||
|
||||
// 切换编辑模式
|
||||
function toggleEditMode() {
|
||||
if (!isEditMode.value) {
|
||||
// 进入编辑模式
|
||||
originalContent.value = generatedContent.value
|
||||
editableContent.value = generatedContent.value
|
||||
}
|
||||
isEditMode.value = !isEditMode.value
|
||||
}
|
||||
|
||||
// 保存编辑
|
||||
function saveEdit() {
|
||||
generatedContent.value = editableContent.value
|
||||
isEditMode.value = false
|
||||
message.success('文案已保存')
|
||||
}
|
||||
|
||||
// 取消编辑
|
||||
function cancelEdit() {
|
||||
editableContent.value = originalContent.value
|
||||
isEditMode.value = false
|
||||
message.info('已取消编辑')
|
||||
}
|
||||
|
||||
// 复制内容(编辑模式复制编辑区,否则复制生成内容)
|
||||
async function copyContent() {
|
||||
const text = isEditMode.value ? (editableContent.value || '') : (generatedContent.value || '')
|
||||
if (!text.trim()) {
|
||||
message.warning('没有可复制的内容')
|
||||
return
|
||||
}
|
||||
|
||||
const success = await copyToClipboard(text)
|
||||
if (success) {
|
||||
message.success('文案已复制到剪贴板')
|
||||
} else {
|
||||
message.error('复制失败')
|
||||
}
|
||||
}
|
||||
|
||||
defineOptions({ name: 'ContentStyleCopywriting' })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicLayout title="AI 文案创作">
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-content">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="10" :md="24">
|
||||
<div class="form-section">
|
||||
<a-card class="form-card" :bordered="false" title="创作设置">
|
||||
<a-form :model="form" layout="vertical" class="form-container">
|
||||
<a-form-item class="form-item">
|
||||
<!-- 使用 PromptSelector 组件(数据来自 Store) -->
|
||||
<PromptSelector
|
||||
v-model="selectedPromptId"
|
||||
@change="handlePromptChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 统一输入:文本或视频链接 -->
|
||||
<a-form-item class="form-item">
|
||||
<template #label>
|
||||
输入内容
|
||||
<span class="form-tip-inline">输入要生成的主题/段落,或粘贴视频链接以自动转写</span>
|
||||
</template>
|
||||
<a-textarea
|
||||
v-model:value="form.userInput"
|
||||
placeholder="直接输入文字,或粘贴视频链接(抖音、B站、YouTube等)"
|
||||
:auto-size="{ minRows: 6, maxRows: 12 }"
|
||||
class="custom-textarea"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 幅度设置 -->
|
||||
<a-form-item class="form-item">
|
||||
<template #label>
|
||||
创作幅度
|
||||
<span class="form-tip-inline">调整创作幅度,数值越大创意性越强</span>
|
||||
</template>
|
||||
<div class="amplitude-row">
|
||||
<a-slider
|
||||
v-model:value="form.amplitude"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:tooltip-formatter="(value) => `${value}%`"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<a-input-number
|
||||
v-model:value="form.amplitude"
|
||||
:min="0"
|
||||
:max="100"
|
||||
style="width: 96px; margin-left: 12px;"
|
||||
/>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="form-item">
|
||||
<GradientButton
|
||||
text="生成文案"
|
||||
icon="icon-sparkle"
|
||||
:disabled="!getCurrentInputValue() || !selectedPromptId || isLoading"
|
||||
:loading="isLoading"
|
||||
loading-text="生成中..."
|
||||
size="large"
|
||||
:block="true"
|
||||
@click="generateCopywriting"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-col>
|
||||
|
||||
<a-col :lg="14" :md="24">
|
||||
<div class="result-section">
|
||||
<a-card class="result-card" :bordered="false" title="生成结果">
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-button v-if="generatedContent" @click="toggleEditMode" size="small" class="action-btn">
|
||||
<span class="btn-icon"><GmIcon :name="isEditMode ? 'icon-eye' : 'icon-edit'" :size="14" /></span>
|
||||
{{ isEditMode ? '预览' : '编辑' }}
|
||||
</a-button>
|
||||
<a-button v-if="generatedContent" @click="copyContent" size="small" class="action-btn copy-btn">
|
||||
<span class="btn-icon"><GmIcon name="icon-copy" :size="14" /></span>
|
||||
复制
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<div v-if="generatedContent" class="result-content">
|
||||
<!-- 编辑模式 -->
|
||||
<div v-if="isEditMode" class="edit-mode">
|
||||
<a-textarea
|
||||
v-model:value="editableContent"
|
||||
:auto-size="{ minRows: 15, maxRows: 30 }"
|
||||
placeholder="在这里编辑生成的文案内容..."
|
||||
class="edit-textarea"
|
||||
/>
|
||||
<div class="edit-actions">
|
||||
<a-space>
|
||||
<a-button @click="saveEdit" type="primary" size="small" class="save-btn">
|
||||
<span class="btn-icon"><GmIcon name="icon-save" :size="14" /></span>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button @click="cancelEdit" size="small" class="cancel-btn">
|
||||
<span class="btn-icon"><GmIcon name="icon-cancel" :size="14" /></span>
|
||||
取消
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预览模式 -->
|
||||
<div v-else class="generated-content" v-html="md.render(generatedContent)"></div>
|
||||
</div>
|
||||
|
||||
<div v-else class="custom-empty">
|
||||
<div class="empty-description">
|
||||
<div class="empty-icon"><GmIcon name="icon-empty-doc" :size="36" /></div>
|
||||
<div class="empty-title">等待生成文案</div>
|
||||
<div class="empty-desc">请选择内容类型并填写相关信息,然后点击"生成文案"按钮</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
|
||||
</BasicLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 主要内容区域 */
|
||||
.main-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 卡片样式 */
|
||||
.form-card,
|
||||
.result-card {
|
||||
background: var(--bg-primary);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border-color-base); /* Add a subtle border */
|
||||
box-shadow: var(--box-shadow-base); /* Add a subtle shadow for depth */
|
||||
}
|
||||
|
||||
.form-card :deep(.ant-card-head),
|
||||
.result-card :deep(.ant-card-head) {
|
||||
background: var(--bg-primary);
|
||||
border: none;
|
||||
padding: 20px 24px;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.form-card :deep(.ant-card-head-title),
|
||||
.result-card :deep(.ant-card-head-title) {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form-card :deep(.ant-card-body),
|
||||
.result-card :deep(.ant-card-body) {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
/* 表单容器 */
|
||||
.form-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.form-item :deep(.ant-form-item-label) {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.form-item :deep(.ant-form-item-label > label) {
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* 表单标签后的内联提示(不使用 emoji) */
|
||||
.form-tip-inline {
|
||||
margin-left: var(--space-2);
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* 自定义输入框样式 */
|
||||
.custom-input,
|
||||
.custom-textarea {
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--border-light);
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.custom-input:focus,
|
||||
.custom-textarea:focus {
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2); /* Subtle blue glow */
|
||||
}
|
||||
|
||||
.custom-input:hover,
|
||||
.custom-textarea:hover {
|
||||
border-color: var(--border-light-hover, #d9d9d9);
|
||||
}
|
||||
|
||||
.custom-textarea::placeholder {
|
||||
color: var(--text-disabled);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 已合并输入:移除单选组相关样式 */
|
||||
|
||||
/* 输入区域动画 */
|
||||
.input-section {
|
||||
animation: slideIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 旧的块级提示兼容(如他处已有复用时可沿用) */
|
||||
.form-tip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 生成按钮样式 - 已替换为 GradientButton 组件 */
|
||||
|
||||
/* 操作按钮样式 */
|
||||
.action-btn {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
padding: 4px 12px;
|
||||
height: 28px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
background: rgba(22, 119, 255, 0.15);
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
color: var(--primary-color, #1677ff);
|
||||
}
|
||||
|
||||
/* 幅度滑块样式 */
|
||||
.amplitude-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* 暗色下滑块可见性增强 */
|
||||
:deep(.ant-slider) {
|
||||
padding: 10px 0; /* 增加垂直留白,减少拥挤感 */
|
||||
}
|
||||
|
||||
:deep(.ant-slider-rail) {
|
||||
background-color: var(--color-gray-200);
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-slider-track) {
|
||||
background-color: var(--color-primary);
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-slider:hover .ant-slider-track) {
|
||||
background-color: var(--color-primary);
|
||||
}
|
||||
|
||||
:deep(.ant-slider-handle::after) {
|
||||
box-shadow: 0 0 0 2px var(--color-primary);
|
||||
}
|
||||
|
||||
:deep(.ant-slider-handle:focus-visible::after),
|
||||
:deep(.ant-slider-handle:hover::after),
|
||||
:deep(.ant-slider-handle:active::after) {
|
||||
box-shadow: 0 0 0 3px var(--color-primary-glow);
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.custom-empty {
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.empty-description {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-secondary);
|
||||
line-height: 1.6;
|
||||
max-width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 编辑模式样式 */
|
||||
.edit-mode {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.edit-textarea {
|
||||
margin-bottom: 12px;
|
||||
border-radius: 6px;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-light);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.edit-textarea:focus {
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2); /* Subtle blue glow */
|
||||
}
|
||||
|
||||
.edit-textarea:hover {
|
||||
border-color: var(--border-light-hover, #d9d9d9);
|
||||
}
|
||||
|
||||
.edit-textarea::placeholder {
|
||||
color: var(--text-disabled);
|
||||
}
|
||||
|
||||
.edit-actions {
|
||||
text-align: right;
|
||||
padding-top: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
background: var(--color-primary);
|
||||
border: 1px solid var(--color-primary);
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.save-btn:hover {
|
||||
background: var(--color-primary);
|
||||
filter: brightness(1.04);
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 生成内容样式 */
|
||||
.result-content {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.generated-content {
|
||||
padding: 20px;
|
||||
background: var(--bg-primary);
|
||||
border-radius: 6px;
|
||||
line-height: 1.8;
|
||||
color: var(--text-primary);
|
||||
min-height: 400px;
|
||||
font-size: 14px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.generated-content :deep(h1) {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
margin-bottom: var(--space-4);
|
||||
color: var(--text-primary);
|
||||
padding-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.generated-content :deep(h2) {
|
||||
font-size: 19px;
|
||||
font-weight: 600;
|
||||
margin: 22px 0 12px 0;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.generated-content :deep(h3) {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 18px 0 10px 0;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.generated-content :deep(p) {
|
||||
margin: 12px 0 14px 0;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.9;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.generated-content :deep(ul),
|
||||
.generated-content :deep(ol) {
|
||||
margin: 12px 0;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.generated-content :deep(li) {
|
||||
margin: 6px 0;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.9;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.generated-content :deep(strong) {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.generated-content :deep(code) {
|
||||
background: var(--bg-secondary);
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13.5px;
|
||||
color: var(--color-red-500);
|
||||
}
|
||||
|
||||
.generated-content :deep(pre) {
|
||||
background: var(--bg-secondary);
|
||||
padding: 16px 18px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.generated-content :deep(pre code) {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: var(--color-red-500);
|
||||
}
|
||||
|
||||
.generated-content :deep(blockquote) {
|
||||
margin: 16px 0;
|
||||
padding: 12px 16px;
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
border-radius: 0 6px 6px 0;
|
||||
font-style: italic;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* 提示词标签样式 */
|
||||
.prompt-tags-container {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.prompt-tags-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.prompt-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 14px;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border-light);
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.prompt-tag:hover {
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
}
|
||||
|
||||
.prompt-tag-selected {
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
background: var(--primary-color, #1677ff);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.prompt-tag-selected:hover {
|
||||
background: var(--primary-color, #1677ff);
|
||||
}
|
||||
|
||||
.prompt-tag-name {
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.prompt-empty {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.prompt-loading {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 更多提示词弹窗样式 */
|
||||
.all-prompts-modal {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.all-prompts-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.all-prompt-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 8px 16px;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border-light);
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.all-prompt-tag:hover {
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
}
|
||||
|
||||
.all-prompt-tag-selected {
|
||||
border-color: var(--primary-color, #1677ff);
|
||||
background: var(--primary-color, #1677ff);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.all-prompt-tag-selected:hover {
|
||||
background: var(--primary-color, #1677ff);
|
||||
}
|
||||
|
||||
.all-prompt-tag-name {
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
padding: 16px 0 24px 0;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 1.5rem;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 0 16px 24px 16px;
|
||||
}
|
||||
|
||||
.form-card,
|
||||
.result-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-card :deep(.ant-card-body),
|
||||
.result-card :deep(.ant-card-body) {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.radio-label {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.radio-icon {
|
||||
font-size: 1rem;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.generated-content {
|
||||
padding: 14px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.prompt-tags-grid {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.prompt-tag {
|
||||
font-size: 12px;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -44,16 +44,9 @@ const topicDetails = reactive({
|
||||
level: 50
|
||||
})
|
||||
|
||||
// 智能体列表
|
||||
const agentList = ref([])
|
||||
const loadingAgents = ref(false)
|
||||
|
||||
// 当前选中的智能体
|
||||
const selectedAgent = ref(null)
|
||||
|
||||
// 当前选中的风格类型
|
||||
const selectedStyleType = ref('agent')
|
||||
|
||||
// 工具函数
|
||||
function formatNumber(num) {
|
||||
if (!num) return '0'
|
||||
@@ -89,52 +82,20 @@ async function copyContent() {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载智能体列表(保留用于其他逻辑)
|
||||
async function loadAgentList() {
|
||||
loadingAgents.value = true
|
||||
try {
|
||||
const res = await getAgentList()
|
||||
if (res.code === 0 && res.data) {
|
||||
agentList.value = res.data.map(item => ({
|
||||
id: item.id,
|
||||
agentId: item.agentId,
|
||||
name: item.agentName,
|
||||
description: item.description,
|
||||
systemPrompt: item.systemPrompt,
|
||||
avatar: item.icon,
|
||||
categoryName: item.categoryName || '其他',
|
||||
isFavorite: item.isFavorite || false
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载智能体列表失败:', error)
|
||||
} finally {
|
||||
loadingAgents.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理风格选择变化
|
||||
function handleStyleChange(data) {
|
||||
if (!data) {
|
||||
selectedAgent.value = null
|
||||
selectedStyleType.value = null
|
||||
return
|
||||
}
|
||||
|
||||
const { id, type, item } = data
|
||||
selectedStyleType.value = type
|
||||
const { id, item } = data
|
||||
topicDetails.selectedAgentId = id
|
||||
|
||||
if (type === 'agent') {
|
||||
// 选择的是智能体
|
||||
selectedAgent.value = item
|
||||
} else if (type === 'prompt') {
|
||||
// 选择的是用户风格
|
||||
selectedAgent.value = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
systemPrompt: item.content
|
||||
}
|
||||
selectedAgent.value = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
systemPrompt: item.content
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,8 +343,6 @@ async function handleSearch() {
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// 加载智能体列表用于后续逻辑
|
||||
loadAgentList()
|
||||
pointsConfigStore.loadConfig()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user