重命名前端项目目录:web-flowith -> web
- 将前端项目目录从 web-flowith 重命名为 web,使目录结构更简洁 - 保持所有前端代码和配置文件不变 - 统一项目目录命名规范
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<div class="websocket-test">
|
||||
<div class="test-container">
|
||||
<h1>WebSocket连接测试</h1>
|
||||
|
||||
<!-- 连接状态 -->
|
||||
<div class="status-section">
|
||||
<h3>连接状态</h3>
|
||||
<div class="status-info">
|
||||
<span class="status-label">状态:</span>
|
||||
<span
|
||||
class="status-value"
|
||||
:class="{
|
||||
'connected': chatStore.wsConnected,
|
||||
'connecting': chatStore.connectionStatus === 'CONNECTING',
|
||||
'disconnected': !chatStore.wsConnected
|
||||
}"
|
||||
>
|
||||
{{ getConnectionStatusText() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="status-actions">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="chatStore.connectWebSocket()"
|
||||
:loading="chatStore.connectionStatus === 'CONNECTING'"
|
||||
:disabled="chatStore.wsConnected"
|
||||
>
|
||||
连接
|
||||
</a-button>
|
||||
<a-button
|
||||
@click="chatStore.disconnectWebSocket()"
|
||||
:disabled="!chatStore.wsConnected"
|
||||
>
|
||||
断开
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 消息测试 -->
|
||||
<div class="message-section">
|
||||
<h3>消息测试</h3>
|
||||
<div class="message-input">
|
||||
<a-input
|
||||
v-model:value="testMessage"
|
||||
placeholder="输入测试消息..."
|
||||
@press-enter="sendTestMessage"
|
||||
:disabled="!chatStore.wsConnected"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="sendTestMessage"
|
||||
:disabled="!chatStore.wsConnected || !testMessage.trim()"
|
||||
>
|
||||
发送
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 消息历史 -->
|
||||
<div class="messages-section">
|
||||
<h3>消息历史</h3>
|
||||
<div class="messages-list">
|
||||
<div
|
||||
v-for="message in messages"
|
||||
:key="message.id"
|
||||
class="message-item"
|
||||
:class="{ 'user': message.type === 'user', 'ai': message.type === 'ai' }"
|
||||
>
|
||||
<div class="message-header">
|
||||
<span class="message-sender">{{ message.type === 'user' ? '用户' : 'AI' }}</span>
|
||||
<span class="message-time">{{ formatTime(message.timestamp) }}</span>
|
||||
</div>
|
||||
<div class="message-content">{{ message.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="messages-actions">
|
||||
<a-button @click="clearMessages">清空消息</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 配置信息 -->
|
||||
<div class="config-section">
|
||||
<h3>配置信息</h3>
|
||||
<div class="config-info">
|
||||
<div class="config-item">
|
||||
<span class="config-label">WebSocket URL:</span>
|
||||
<span class="config-value">{{ wsUrl }}</span>
|
||||
</div>
|
||||
<div class="config-item">
|
||||
<span class="config-label">用户ID:</span>
|
||||
<span class="config-value">{{ userId }}</span>
|
||||
</div>
|
||||
<div class="config-item">
|
||||
<span class="config-label">会话ID:</span>
|
||||
<span class="config-value">{{ chatStore.currentSession?.id || '未设置' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useChatStore } from '@/stores/chat'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const chatStore = useChatStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const testMessage = ref('')
|
||||
const messages = ref<Array<{
|
||||
id: string
|
||||
type: 'user' | 'ai'
|
||||
content: string
|
||||
timestamp: number
|
||||
}>>([])
|
||||
|
||||
const wsUrl = computed(() => import.meta.env.VITE_WS_URL)
|
||||
const userId = computed(() => userStore.user?.id || `guest_${Date.now()}`)
|
||||
|
||||
// 获取连接状态文本
|
||||
const getConnectionStatusText = () => {
|
||||
switch (chatStore.connectionStatus) {
|
||||
case 'CONNECTED':
|
||||
return '已连接'
|
||||
case 'CONNECTING':
|
||||
return '连接中...'
|
||||
case 'DISCONNECTED':
|
||||
return '已断开'
|
||||
case 'ERROR':
|
||||
return '连接错误'
|
||||
default:
|
||||
return '未知状态'
|
||||
}
|
||||
}
|
||||
|
||||
// 发送测试消息
|
||||
const sendTestMessage = () => {
|
||||
if (!testMessage.value.trim() || !chatStore.wsConnected) return
|
||||
|
||||
const message = {
|
||||
id: Date.now().toString(),
|
||||
type: 'user' as const,
|
||||
content: testMessage.value.trim(),
|
||||
timestamp: Date.now()
|
||||
}
|
||||
|
||||
messages.value.push(message)
|
||||
chatStore.sendMessage(testMessage.value.trim())
|
||||
testMessage.value = ''
|
||||
}
|
||||
|
||||
// 清空消息
|
||||
const clearMessages = () => {
|
||||
messages.value = []
|
||||
chatStore.clearMessages()
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (timestamp: number) => {
|
||||
return dayjs(timestamp).format('HH:mm:ss')
|
||||
}
|
||||
|
||||
// 监听AI回复
|
||||
const handleAiMessage = (content: string) => {
|
||||
const message = {
|
||||
id: Date.now().toString(),
|
||||
type: 'ai' as const,
|
||||
content,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
messages.value.push(message)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 监听聊天store中的消息变化
|
||||
chatStore.$subscribe((mutation, state) => {
|
||||
if (mutation.events && Array.isArray(mutation.events)) {
|
||||
mutation.events.forEach((event: any) => {
|
||||
if (event.key === 'messages' && event.type === 'add') {
|
||||
const newMessage = event.newValue
|
||||
if (newMessage && newMessage.type === 'ai') {
|
||||
handleAiMessage(newMessage.content)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
chatStore.disconnectWebSocket()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.websocket-test {
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.test-container {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.status-section,
|
||||
.message-section,
|
||||
.messages-section,
|
||||
.config-section {
|
||||
margin-bottom: 32px;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 16px;
|
||||
color: #1890ff;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.status-info {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.status-label {
|
||||
font-weight: 500;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
|
||||
&.connected {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
border: 1px solid #b7eb8f;
|
||||
}
|
||||
|
||||
&.connecting {
|
||||
background: #fffbe6;
|
||||
color: #faad14;
|
||||
border: 1px solid #ffe58f;
|
||||
}
|
||||
|
||||
&.disconnected {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
border: 1px solid #ffccc7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.ant-input {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.messages-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.message-item {
|
||||
margin-bottom: 12px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
&.user {
|
||||
background: #e6f7ff;
|
||||
border-left: 3px solid #1890ff;
|
||||
}
|
||||
|
||||
&.ai {
|
||||
background: #f6ffed;
|
||||
border-left: 3px solid #52c41a;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
|
||||
.message-sender {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.message-content {
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-info {
|
||||
.config-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.config-label {
|
||||
font-weight: 500;
|
||||
min-width: 120px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.config-value {
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user