Files
api-box/frontend/src/components/ChatPanel.vue
T

289 lines
6.7 KiB
Vue
Raw Normal View History

2025-10-05 18:12:51 +08:00
<template>
<div class="chat-panel">
<!-- 厂商选择器 -->
<div class="form-group">
<label for="chat-platform">选择厂商</label>
<select id="chat-platform" v-model="selectedPlatform" :disabled="!configuredPlatforms.length">
<option value="">请选择厂商</option>
<option v-for="platform in configuredPlatforms" :key="platform.id" :value="platform.id">
{{ platform.name }}
</option>
</select>
</div>
<!-- 对话输入框 -->
<div class="form-group">
<label for="user-input">输入问题</label>
<textarea
id="user-input"
v-model="userInput"
placeholder="请输入您的问题..."
:disabled="!selectedPlatform || isSending"
rows="4"
></textarea>
</div>
<!-- 发送按钮 -->
<div class="form-group">
<button @click="sendMessage" :disabled="!canSend || isSending" class="send-btn">
{{ isSending ? '发送中...' : '发送' }}
</button>
</div>
<!-- 响应显示区域 -->
<div v-if="responseMessage" class="response-area">
<h3>AI 响应</h3>
<div class="response-content" v-html="responseMessage"></div>
</div>
<!-- 错误信息显示 -->
<div v-if="errorMessage" class="error-message">
{{ errorMessage }}
</div>
<!-- 提示信息 -->
<div v-if="!configuredPlatforms.length" class="info-message">
<p>请先在配置页面添加厂商配置</p>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
// 响应式数据
const userInput = ref('')
const selectedPlatform = ref('')
const responseMessage = ref('')
const errorMessage = ref('')
const isSending = ref(false)
const configuredPlatforms = ref([])
// 计算属性
const canSend = computed(() => {
return selectedPlatform.value && userInput.value.trim() !== ''
})
// 从localStorage加载已配置的厂商
const loadConfiguredPlatforms = () => {
try {
const stored = localStorage.getItem('ai-api-configs')
if (stored) {
const configs = JSON.parse(stored)
configuredPlatforms.value = configs.map(config => {
// 这里需要根据实际的平台配置来构建完整信息
// 为简化实现,我们只保留必要的信息
return {
id: config.id,
name: getPlatformName(config.id)
}
})
}
} catch (error) {
console.error('加载配置失败:', error)
}
}
// 获取平台名称
const getPlatformName = (platformId) => {
const platforms = [
{ id: 'openai', name: 'OpenAI' },
2025-10-06 00:54:47 +08:00
{ id: 'zhipu', name: '智谱' },
{ id: 'deepseek', name: 'DeepSeek' },
{ id: 'qwen', name: '通义千问' },
{ id: 'siliconflow', name: '硅基流动' }
2025-10-05 18:12:51 +08:00
]
const platform = platforms.find(p => p.id === platformId)
return platform ? platform.name : platformId
}
// 发送消息
const sendMessage = async () => {
if (!canSend.value) return
isSending.value = true
responseMessage.value = ''
errorMessage.value = ''
try {
// 获取选中的平台配置
const platformConfig = configuredPlatforms.value.find(p => p.id === selectedPlatform.value)
if (!platformConfig) {
throw new Error('未找到厂商配置')
}
// 从localStorage获取密钥
const stored = localStorage.getItem('ai-api-configs')
if (!stored) {
throw new Error('未找到厂商配置')
}
const configs = JSON.parse(stored)
const config = configs.find(c => c.id === selectedPlatform.value)
if (!config) {
throw new Error('未找到厂商配置')
}
2025-10-06 01:13:37 +08:00
// 将配置信息和用户消息发送给后端处理
const result = await callAIPlatform(selectedPlatform.value, config.apiKey, config.endpoint, userInput.value)
2025-10-05 18:12:51 +08:00
// 显示响应
responseMessage.value = result
} catch (error) {
console.error('发送消息失败:', error)
errorMessage.value = error.message || '发送消息失败,请重试'
} finally {
isSending.value = false
}
}
// 调用AI平台API
2025-10-06 01:13:37 +08:00
// TODO 这里需要调用实际后端API接口
2025-10-05 18:12:51 +08:00
const callAIPlatform = async (platformId, apiKey, endpoint, message) => {
2025-10-06 01:13:37 +08:00
try {
// 发送请求到后端API
2025-10-06 13:50:08 +08:00
// console.log(JSON.stringify({
// platformId,
// apiKey,
// endpoint,
// message
// }))
const response = await fetch('http://localhost:8080/api/chat', {
2025-10-06 01:13:37 +08:00
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
platformId,
apiKey,
endpoint,
message
})
2025-10-06 13:50:08 +08:00
}
)
2025-10-06 01:13:37 +08:00
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.json()
return data.response
} catch (error) {
console.error('调用AI平台API失败:', error)
throw new Error('调用AI平台API失败: ' + error.message)
}
2025-10-05 18:12:51 +08:00
}
// 初始化
onMounted(() => {
loadConfiguredPlatforms()
2025-10-06 01:13:37 +08:00
// 监听配置保存事件,以便刷新数据
const handleConfigSaved = () => {
loadConfiguredPlatforms()
}
window.addEventListener('config-saved', handleConfigSaved)
// 组件卸载时移除事件监听器
onUnmounted(() => {
window.removeEventListener('config-saved', handleConfigSaved)
})
2025-10-05 18:12:51 +08:00
})
</script>
<style scoped>
.chat-panel {
display: flex;
flex-direction: column;
gap: 20px;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-group label {
margin-bottom: 5px;
font-weight: bold;
color: #333;
}
.form-group input,
.form-group select,
.form-group textarea {
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.form-group input:disabled,
.form-group select:disabled,
.form-group textarea:disabled {
background-color: #f5f5f5;
cursor: not-allowed;
}
.send-btn {
padding: 12px 20px;
background-color: #28a745;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
.send-btn:hover:not(:disabled) {
background-color: #218838;
}
.send-btn:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.response-area {
margin-top: 20px;
padding: 15px;
background-color: #f8f9fa;
border-radius: 4px;
border-left: 4px solid #007bff;
}
.response-area h3 {
margin-top: 0;
color: #333;
}
.response-content {
white-space: pre-wrap;
line-height: 1.5;
}
.error-message {
padding: 10px;
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
border-radius: 4px;
margin-top: 10px;
}
.info-message {
padding: 15px;
background-color: #e7f3ff;
color: #004085;
border: 1px solid #b8daff;
border-radius: 4px;
text-align: center;
}
.info-message p {
margin: 0;
}
2025-10-06 01:13:37 +08:00
</style>