feat(optimize): 重构优化面板,整合提示词类型选择器

- 将原有的输入面板和优化结果区域替换为新的优化面板组件 OptimizePanelUI,提升代码可维护性
- 在优化面板中集成提示词类型选择器,优化用户交互体验
- 更新相关的状态管理逻辑,确保提示词和优化结果的正确传递
- 修改国际化文件,确保新组件的文本支持多语言
- 更新测试用例,验证新功能的正确性和稳定性
This commit is contained in:
linshen committed 2025-06-18 22:25:02 +08:00
1 parent ebf4d2730b
commit 1237fa4e5e
7 files changed
+137 -211

No files matched your search

+58 -132
View File
@@ -43,65 +43,22 @@
<!-- 主要内容插槽 -->
<!-- 提示词区 -->
<ContentCardUI>
<!-- 输入区域 -->
<div class="flex-none">
<InputPanelUI
v-model="prompt"
v-model:selectedModel="selectedOptimizeModel"
:label="$t('promptOptimizer.originalPrompt')"
:placeholder="$t('promptOptimizer.inputPlaceholder')"
:model-label="$t('promptOptimizer.optimizeModel')"
:template-label="$t('promptOptimizer.templateLabel')"
:button-text="$t('promptOptimizer.optimize')"
:loading-text="$t('common.loading')"
:loading="isOptimizing"
:disabled="isOptimizing"
@submit="handleOptimizePrompt"
@configModel="showConfig = true"
>
<template #model-select>
<ModelSelectUI
ref="optimizeModelSelect"
:modelValue="selectedOptimizeModel"
@update:modelValue="selectedOptimizeModel = $event"
:disabled="isOptimizing"
@config="showConfig = true"
/>
</template>
<template #template-select>
<TemplateSelectUI
v-model="selectedOptimizeTemplate"
type="optimize"
@manage="openTemplateManager('optimize')"
@select="handleTemplateSelect"
/>
</template>
</InputPanelUI>
</div>
<!-- 优化结果区域 -->
<div class="flex-1 min-h-0 overflow-y-auto">
<PromptPanelUI
v-model:optimized-prompt="optimizedPrompt"
:original-prompt="prompt"
:is-iterating="isIterating"
v-model:selected-iterate-template="selectedIterateTemplate"
:versions="currentVersions"
:current-version-id="currentVersionId"
@iterate="handleIteratePrompt"
@openTemplateManager="openTemplateManager"
@switchVersion="handleSwitchVersion"
@templateSelect="handleTemplateSelect"
/>
</div>
</ContentCardUI>
<OptimizePanelUI
ref="optimizePanel"
:model-manager="modelManager"
:template-manager="templateManager"
:history-manager="historyManager"
:prompt-service="promptServiceRef"
@showConfig="showConfig = true"
@openTemplateManager="openTemplateManager"
/>
<!-- 测试区域 -->
<TestPanelUI
:prompt-service="promptServiceRef"
:original-prompt="prompt"
:optimized-prompt="optimizedPrompt"
:prompt-type="selectedPromptType"
v-model="selectedTestModel"
@showConfig="showConfig = true"
/>
@@ -123,8 +80,9 @@
<TemplateManagerUI
v-if="showTemplates"
:template-type="currentType"
:selected-optimize-template="selectedOptimizeTemplate"
:selected-iterate-template="selectedIterateTemplate"
:prompt-type="selectedPromptType"
:selected-optimize-template="optimizePanel?.selectedOptimizeTemplate"
:selected-iterate-template="optimizePanel?.selectedIterateTemplate"
@close="handleTemplateManagerClose"
@select="handleTemplateSelect"
/>
@@ -150,31 +108,24 @@
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { onMounted, ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import {
// UI组件
ToastUI,
ModelManagerUI,
ThemeToggleUI,
OutputPanelUI,
PromptPanelUI,
TemplateManagerUI,
TemplateSelectUI,
ModelSelectUI,
HistoryDrawerUI,
InputPanelUI,
MainLayoutUI,
ContentCardUI,
ActionButtonUI,
TestPanelUI,
LanguageSwitchUI,
DataManagerUI,
OptimizePanelUI,
// composables
usePromptOptimizer,
usePromptTester,
useToast,
usePromptHistory,
useServiceInitializer,
useTemplateManager,
useModelManager,
@@ -208,6 +159,9 @@ const toast = useToast()
// 初始化国际化
const { t } = useI18n()
// OptimizePanel 引用
const optimizePanel = ref(null)
// 初始化服务
const {
promptServiceRef
@@ -233,79 +187,51 @@ const {
testModelSelect
})
// 初始化组合式函数
const {
prompt,
optimizedPrompt,
isOptimizing,
isIterating,
selectedOptimizeTemplate,
selectedIterateTemplate,
currentVersions,
currentVersionId,
currentChainId,
handleOptimizePrompt,
handleIteratePrompt,
handleSwitchVersion,
saveTemplateSelection
} = usePromptOptimizer(
modelManager,
templateManager,
historyManager,
promptServiceRef,
selectedOptimizeModel,
selectedTestModel
)
// 通过 OptimizePanel 获取状态
const prompt = computed(() => optimizePanel.value?.prompt || '')
const optimizedPrompt = computed(() => optimizePanel.value?.optimizedPrompt || '')
const selectedPromptType = computed(() => optimizePanel.value?.selectedPromptType || 'system')
// 初始化历史记录管理器
const {
history,
handleSelectHistory: handleSelectHistoryBase,
handleClearHistory: handleClearHistoryBase,
handleDeleteChain: handleDeleteChainBase
} = usePromptHistory(
historyManager,
prompt,
optimizedPrompt,
currentChainId,
currentVersions,
currentVersionId
)
// 历史记录管理
const showHistory = ref(false)
const history = computed(() => historyManager.getHistory())
// 初始化历史记录管理器UI
const {
showHistory,
handleSelectHistory,
handleClearHistory,
handleDeleteChain
} = useHistoryManager(
historyManager,
prompt,
optimizedPrompt,
currentChainId,
currentVersions,
currentVersionId,
handleSelectHistoryBase,
handleClearHistoryBase,
handleDeleteChainBase
)
const handleSelectHistory = (record) => {
if (optimizePanel.value) {
optimizePanel.value.handleSelectHistory(record)
}
}
// 初始化模板管理器
const {
showTemplates,
currentType,
handleTemplateSelect,
openTemplateManager,
handleTemplateManagerClose
} = useTemplateManager({
selectedOptimizeTemplate,
selectedIterateTemplate,
saveTemplateSelection,
templateManager
})
const handleClearHistory = () => {
historyManager.clearHistory()
toast.success(t('history.cleared'))
}
const handleDeleteChain = (chainId) => {
historyManager.deleteChain(chainId)
toast.success(t('history.chainDeleted'))
}
// 模板管理器
const showTemplates = ref(false)
const currentType = ref('optimize')
const openTemplateManager = (type) => {
currentType.value = type
showTemplates.value = true
}
const handleTemplateManagerClose = () => {
showTemplates.value = false
}
const handleTemplateSelect = (template, type) => {
if (optimizePanel.value) {
optimizePanel.value.handleTemplateSelect(template, type)
}
}
// 数据管理器
import { ref } from 'vue'
const showDataManager = ref(false)
const handleDataManagerClose = () => {
+3 -2
View File
@@ -2,9 +2,10 @@
<template>
<div class="space-y-3">
<!-- 标题 -->
<div class="flex justify-between items-center">
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-2">
<label class="block text-lg theme-label">{{ label }}</label>
<div class="flex items-center space-x-2">
<div class="flex items-center space-x-3">
<slot name="prompt-type-selector"></slot>
<button
@click="openFullscreen"
class="px-3 py-1.5 theme-button-secondary flex items-center space-x-2"
+22 -14
View File
@@ -1,15 +1,5 @@
<template>
<ContentCardUI>
<!-- 提示词类型选择器 -->
<div class="flex-none mb-4">
<PromptTypeSelectorUI
v-model="selectedPromptType"
@change="handlePromptTypeChange"
/>
</div>
<!-- 输入区域 -->
<div class="flex-none">
<InputPanelUI
@@ -26,6 +16,12 @@
@submit="handleOptimizePrompt"
@configModel="$emit('showConfig')"
>
<template #prompt-type-selector>
<PromptTypeSelectorUI
v-model="selectedPromptType"
@change="handlePromptTypeChange"
/>
</template>
<template #model-select>
<ModelSelectUI
ref="optimizeModelSelect"
@@ -38,9 +34,9 @@
<template #template-select>
<TemplateSelectUI
v-model="selectedOptimizeTemplate"
type="optimize"
:type="selectedPromptType === 'system' ? 'optimize' : 'userOptimize'"
:prompt-type="selectedPromptType"
@manage="$emit('openTemplateManager', 'optimize')"
@manage="$emit('openTemplateManager', selectedPromptType === 'system' ? 'optimize' : 'userOptimize')"
@select="handleTemplateSelect"
/>
</template>
@@ -162,6 +158,18 @@ defineExpose({
initModelSelection,
loadModels,
saveTemplateSelection,
selectedPromptType
selectedPromptType,
selectedOptimizeTemplate,
selectedIterateTemplate,
handleTemplateSelect,
handleSelectHistory: (record) => {
// 处理历史记录选择
prompt.value = record.originalPrompt
optimizedPrompt.value = record.optimizedPrompt
}
})
</script>
</script>
<style scoped>
/* OptimizePanel 样式 */
</style>
@@ -1,41 +1,36 @@
<!-- 提示词类型选择器组件 - 简化版 -->
<template>
<div class="prompt-type-selector">
<div class="flex items-center gap-2">
<span class="text-xs text-gray-500 dark:text-gray-400">
{{ t('promptOptimizer.promptType') }}:
</span>
<div class="inline-flex bg-gray-50 dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-600 text-xs">
<button
@click="updatePromptType('system')"
:class="[
'px-2 py-1 transition-colors duration-150 rounded-l',
'focus:outline-none focus:ring-1 focus:ring-blue-400',
modelValue === 'system'
? 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
: 'text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-75 dark:hover:bg-gray-750'
]"
:aria-pressed="modelValue === 'system'"
:title="t('promptOptimizer.systemPromptHelp')"
>
{{ t('promptOptimizer.systemPrompt') }}
</button>
<div class="w-px bg-gray-200 dark:bg-gray-600"></div>
<button
@click="updatePromptType('user')"
:class="[
'px-2 py-1 transition-colors duration-150 rounded-r',
'focus:outline-none focus:ring-1 focus:ring-blue-400',
modelValue === 'user'
? 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
: 'text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-75 dark:hover:bg-gray-750'
]"
:aria-pressed="modelValue === 'user'"
:title="t('promptOptimizer.userPromptHelp')"
>
{{ t('promptOptimizer.userPrompt') }}
</button>
</div>
<div class="inline-flex bg-gray-50 dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-600 text-[10px]">
<button
@click="updatePromptType('system')"
:class="[
'px-1.5 py-0.5 transition-colors duration-150 rounded-l',
'focus:outline-none focus:ring-1 focus:ring-blue-400',
modelValue === 'system'
? 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
: 'text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-75 dark:hover:bg-gray-750'
]"
:aria-pressed="modelValue === 'system'"
:title="t('promptOptimizer.systemPromptHelp')"
>
{{ t('promptOptimizer.systemPrompt') }}
</button>
<div class="w-px bg-gray-200 dark:bg-gray-600"></div>
<button
@click="updatePromptType('user')"
:class="[
'px-1.5 py-0.5 transition-colors duration-150 rounded-r',
'focus:outline-none focus:ring-1 focus:ring-blue-400',
modelValue === 'user'
? 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
: 'text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-75 dark:hover:bg-gray-750'
]"
:aria-pressed="modelValue === 'user'"
:title="t('promptOptimizer.userPromptHelp')"
>
{{ t('promptOptimizer.userPrompt') }}
</button>
</div>
</div>
</template>
+2 -1
View File
@@ -1,4 +1,4 @@
// 导入样式
// 导入样式
import 'element-plus/dist/index.css'
import './styles/index.css'
import './styles/scrollbar.css'
@@ -32,6 +32,7 @@ export { default as LanguageSwitchUI } from './components/LanguageSwitch.vue'
export { default as BuiltinTemplateLanguageSwitchUi } from './components/BuiltinTemplateLanguageSwitch.vue'
export { default as DataManagerUI } from './components/DataManager.vue'
export { default as PromptTypeSelectorUI } from './components/PromptTypeSelector.vue'
export { default as OptimizePanelUI } from './components/OptimizePanel.vue'
// 导出指令
export { clickOutside } from './directives/clickOutside'
@@ -35,7 +35,7 @@ describe('PromptTypeSelector', () => {
})
expect(wrapper.find('.prompt-type-selector').exists()).toBe(true)
expect(wrapper.text()).toContain('Prompt Type')
// 移除了"优化模式:"标签前缀,只显示按钮
expect(wrapper.text()).toContain('System Prompt')
expect(wrapper.text()).toContain('User Prompt')
})
@@ -162,11 +162,11 @@ describe('PromptTypeSelector', () => {
}
})
// Should show prompt type label and buttons, but no help text
expect(wrapper.text()).toContain('Prompt Type')
// Should show buttons but no label prefix or help text (simplified design)
expect(wrapper.text()).toContain('System Prompt')
expect(wrapper.text()).toContain('User Prompt')
// Should not contain help text (simplified design)
// Should not contain label prefix or help text (simplified design)
expect(wrapper.text()).not.toContain('Prompt Type')
expect(wrapper.text()).not.toContain('Optimize system prompts to define AI assistant role')
})
@@ -180,11 +180,11 @@ describe('PromptTypeSelector', () => {
}
})
// Should show compact design without help text
expect(wrapper.text()).toContain('Prompt Type')
// Should show compact design without label prefix or help text
expect(wrapper.text()).toContain('System Prompt')
expect(wrapper.text()).toContain('User Prompt')
// Should not contain help text (simplified design)
// Should not contain label prefix or help text (simplified design)
expect(wrapper.text()).not.toContain('Prompt Type')
expect(wrapper.text()).not.toContain('Optimize user prompts to improve AI interaction')
})
+15 -20
View File
@@ -44,16 +44,6 @@
<!-- 主要内容插槽 -->
<!-- 提示词区 -->
<ContentCardUI>
<!-- 提示词类型选择器 -->
<div class="flex-none mb-4">
<PromptTypeSelectorUI
v-model="selectedPromptType"
@change="handlePromptTypeChange"
/>
</div>
<!-- 输入区域 -->
<div class="flex-none">
<InputPanelUI
@@ -70,6 +60,12 @@
@submit="handleOptimizePrompt"
@configModel="showConfig = true"
>
<template #prompt-type-selector>
<PromptTypeSelectorUI
v-model="selectedPromptType"
@change="handlePromptTypeChange"
/>
</template>
<template #model-select>
<ModelSelectUI
ref="optimizeModelSelect"
@@ -92,7 +88,7 @@
<!-- 优化结果区域 -->
<div class="flex-1 min-h-0 overflow-y-auto">
<PromptPanelUI
<PromptPanelUI
v-model:optimized-prompt="optimizedPrompt"
:original-prompt="prompt"
:is-iterating="isIterating"
@@ -169,20 +165,19 @@ import {
ToastUI,
ModelManagerUI,
ThemeToggleUI,
OutputPanelUI,
PromptPanelUI,
TemplateManagerUI,
TemplateSelectUI,
ModelSelectUI,
HistoryDrawerUI,
InputPanelUI,
MainLayoutUI,
ContentCardUI,
ActionButtonUI,
TestPanelUI,
LanguageSwitchUI,
DataManagerUI,
InputPanelUI,
PromptPanelUI,
PromptTypeSelectorUI,
ModelSelectUI,
TemplateSelectUI,
ContentCardUI,
// composables
usePromptOptimizer,
usePromptTester,
@@ -287,9 +282,9 @@ const {
templateManager,
historyManager,
promptServiceRef,
selectedPromptType, // 新增:提示词类型
selectedOptimizeModel, // 新增:优化模型选择
selectedTestModel // 新增:测试模型选择
selectedPromptType,
selectedOptimizeModel,
selectedTestModel
)
// 初始化历史记录管理器