优化调整
This commit is contained in:
+80
-80
@@ -46,95 +46,95 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
<style lang="scss">
|
||||
#app {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 自定义Ant Design样式 */
|
||||
.ant-btn {
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 自定义Ant Design样式 */
|
||||
.ant-btn {
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&.ant-btn-primary {
|
||||
background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #5ba0f2 0%, #6bb0ff 100%);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-btn-orange {
|
||||
background: linear-gradient(135deg, #ff7849 0%, #ff8859 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #ff8859 0%, #ff9869 100%);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-card {
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||
&.ant-btn-primary {
|
||||
background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input,
|
||||
.ant-input-affix-wrapper {
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e8e8e8;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.ant-input-affix-wrapper-focused {
|
||||
border-color: #4a90e2;
|
||||
box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-message {
|
||||
.ant-message-notice-content {
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #5ba0f2 0%, #6bb0ff 100%);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
/* 滚动条美化 */
|
||||
.ant-layout-content {
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
&.ant-btn-orange {
|
||||
background: linear-gradient(135deg, #ff7849 0%, #ff8859 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #ff8859 0%, #ff9869 100%);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
.ant-card {
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input,
|
||||
.ant-input-affix-wrapper {
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e8e8e8;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.ant-input-affix-wrapper-focused {
|
||||
border-color: #4a90e2;
|
||||
box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-message {
|
||||
.ant-message-notice-content {
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
/* 滚动条美化 */
|
||||
.ant-layout-content {
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,3 +1,4 @@
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
|
||||
|
||||
/* 全局重置 */
|
||||
|
||||
@@ -1 +1 @@
|
||||
/* 空文件 - 解决构建问题 */
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
@@ -26,7 +26,8 @@
|
||||
// 简化版Footer组件
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.app-footer {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.app-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
||||
@@ -110,15 +110,7 @@ const routes: RouteRecordRaw[] = [
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/token-test',
|
||||
name: 'TokenTest',
|
||||
component: () => import('@/views/TokenTest.vue'),
|
||||
meta: {
|
||||
title: 'Token测试',
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
|
||||
@@ -50,7 +50,7 @@ api.interceptors.response.use(
|
||||
window.location.href = '/login'
|
||||
}
|
||||
|
||||
const error = new Error(data.message || '请求失败')
|
||||
const error = new Error(data.message || '请求失败') as any
|
||||
error.response = response
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
@@ -166,13 +166,6 @@ export const useChatStore = defineStore('chat', () => {
|
||||
)
|
||||
}
|
||||
|
||||
// 分割AI回复为多条消息
|
||||
const splitAiReply = (content: string): string[] => {
|
||||
// 先按 \n\n 分割,再按 \n 分割
|
||||
const segments = content.split(/\n\n|\n/).filter(segment => segment.trim().length > 0)
|
||||
return segments
|
||||
}
|
||||
|
||||
// 添加AI回复消息(直接显示完整内容)
|
||||
const addAiReplyMessages = (content: string) => {
|
||||
// 停止输入状态
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface ChatMessage {
|
||||
sessionId?: string
|
||||
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'failed'
|
||||
error?: string
|
||||
sender?: string
|
||||
}
|
||||
|
||||
// 聊天会话类型
|
||||
|
||||
@@ -373,6 +373,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.chat-history-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<a-button type="text" @click="testAPI" class="action-btn" style="margin-right: 8px;">
|
||||
测试API
|
||||
</a-button>
|
||||
<a-button type="text" @click="openHistoryDrawer" class="action-btn">
|
||||
<HistoryOutlined />
|
||||
</a-button>
|
||||
@@ -444,7 +441,8 @@
|
||||
showEmotionSummaryResult(result)
|
||||
|
||||
} catch (error) {
|
||||
console.error('生成情绪记录时发生错误:', error)
|
||||
const err = error as any;
|
||||
console.error('生成情绪记录时发生错误:', err)
|
||||
alert('生成情绪记录失败,请检查网络连接')
|
||||
} finally {
|
||||
emotionSummaryLoading.value = false
|
||||
@@ -497,39 +495,7 @@
|
||||
loadHistoryMessages(1)
|
||||
}
|
||||
|
||||
// 测试API调用
|
||||
const testAPI = async () => {
|
||||
console.log('=== 开始测试API ===')
|
||||
|
||||
try {
|
||||
// 测试原始API调用
|
||||
console.log('1. 测试原始axios调用...')
|
||||
const token = localStorage.getItem('token')
|
||||
console.log('Token:', token ? `${token.substring(0, 20)}...` : 'null')
|
||||
|
||||
const response = await fetch('/api/message/user/page?current=1&size=5', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
console.log('原始响应状态:', response.status)
|
||||
const rawData = await response.json()
|
||||
console.log('原始响应数据:', rawData)
|
||||
|
||||
// 测试封装的API调用
|
||||
console.log('2. 测试封装的API调用...')
|
||||
const apiData = await messageApi.getUserMessages(1, 5)
|
||||
console.log('封装API返回数据:', apiData)
|
||||
|
||||
} catch (error) {
|
||||
console.error('API测试失败:', error)
|
||||
}
|
||||
|
||||
console.log('=== API测试完成 ===')
|
||||
}
|
||||
|
||||
// 加载历史记录
|
||||
const loadHistoryMessages = async (page = 1) => {
|
||||
@@ -577,22 +543,23 @@
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载历史记录时发生错误:', error)
|
||||
const err = error as any;
|
||||
console.error('加载历史记录时发生错误:', err)
|
||||
console.error('错误详情:', {
|
||||
message: error.message,
|
||||
response: error.response,
|
||||
status: error.response?.status,
|
||||
data: error.response?.data
|
||||
message: err.message,
|
||||
response: err.response,
|
||||
status: err.response?.status,
|
||||
data: err.response?.data
|
||||
})
|
||||
|
||||
// 显示用户友好的错误信息
|
||||
if (error.response?.status === 401) {
|
||||
if (err.response?.status === 401) {
|
||||
console.log('认证失败,可能需要重新登录')
|
||||
// 可以在这里添加跳转到登录页的逻辑
|
||||
} else if (error.response?.status === 500) {
|
||||
} else if (err.response?.status === 500) {
|
||||
console.log('服务器错误,请稍后重试')
|
||||
} else {
|
||||
console.log('未知错误:', error.message)
|
||||
console.log('未知错误:', err.message)
|
||||
}
|
||||
} finally {
|
||||
console.log('加载历史记录完成,设置 loading 为 false')
|
||||
@@ -625,10 +592,11 @@
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('搜索历史记录时发生错误:', error)
|
||||
const err = error as any;
|
||||
console.error('搜索历史记录时发生错误:', err)
|
||||
|
||||
// 显示用户友好的错误信息
|
||||
if (error.response?.status === 401) {
|
||||
if (err.response?.status === 401) {
|
||||
console.log('认证失败,搜索功能需要登录')
|
||||
}
|
||||
} finally {
|
||||
@@ -677,7 +645,7 @@
|
||||
// 将最近的消息添加到聊天记录中
|
||||
if (recentMessages && recentMessages.length > 0) {
|
||||
// 转换为聊天消息格式
|
||||
const chatMessages = recentMessages.map(msg => ({
|
||||
const chatMessages = recentMessages.map((msg: any) => ({
|
||||
id: msg.id,
|
||||
content: msg.content,
|
||||
sender: msg.sender === 'user' ? 'user' : 'ai',
|
||||
@@ -686,7 +654,7 @@
|
||||
}))
|
||||
|
||||
// 按时间顺序排列(最新的在最后)
|
||||
chatMessages.sort((a, b) => a.timestamp - b.timestamp)
|
||||
chatMessages.sort((a: any, b: any) => a.timestamp - b.timestamp)
|
||||
|
||||
// 添加到消息列表
|
||||
chatStore.messages.push(...chatMessages)
|
||||
@@ -694,7 +662,8 @@
|
||||
console.log('加载最近聊天记录成功:', chatMessages.length, '条')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载最近聊天记录失败:', error)
|
||||
const err = error as any;
|
||||
console.error('加载最近聊天记录失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,6 +685,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.chat-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -487,6 +487,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.dashboard-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -387,6 +387,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.diary-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
import AppFooter from '@/components/layout/AppFooter.vue'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.home-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
|
||||
@@ -513,6 +513,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.life-trajectory-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.login-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
|
||||
@@ -363,6 +363,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.messages-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.not-found-page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
|
||||
@@ -346,6 +346,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.profile-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
|
||||
@@ -203,6 +203,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.register-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
|
||||
@@ -406,6 +406,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.settings-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
<template>
|
||||
<div class="token-test">
|
||||
<a-card title="Token和身份验证测试">
|
||||
<div class="test-section">
|
||||
<h3>当前状态</h3>
|
||||
<a-descriptions :column="1" bordered>
|
||||
<a-descriptions-item label="登录状态">
|
||||
<a-tag :color="userStore.isLoggedIn ? 'green' : 'red'">
|
||||
{{ userStore.isLoggedIn ? '已登录' : '未登录' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="Token">
|
||||
<a-typography-text :code="true" :copyable="true">
|
||||
{{ userStore.token || '无' }}
|
||||
</a-typography-text>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="用户信息">
|
||||
<pre>{{ JSON.stringify(userStore.userInfo || userStore.user, null, 2) }}</pre>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="WebSocket状态">
|
||||
<a-tag :color="chatStore.wsConnected ? 'green' : 'red'">
|
||||
{{ chatStore.wsConnected ? '已连接' : '未连接' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="test-section">
|
||||
<h3>操作测试</h3>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-button type="primary" @click="testLogin" :loading="loginLoading">
|
||||
测试登录
|
||||
</a-button>
|
||||
<a-button @click="testWebSocketConnect" :loading="wsLoading">
|
||||
测试WebSocket连接
|
||||
</a-button>
|
||||
<a-button @click="testSendMessage" :disabled="!chatStore.wsConnected">
|
||||
发送测试消息
|
||||
</a-button>
|
||||
<a-button @click="checkLocalStorage">
|
||||
检查本地存储
|
||||
</a-button>
|
||||
<a-button @click="testApiCall" :loading="apiLoading">
|
||||
测试API调用
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<div class="test-section">
|
||||
<h3>测试结果</h3>
|
||||
<a-textarea
|
||||
v-model:value="testResults"
|
||||
:rows="10"
|
||||
readonly
|
||||
placeholder="测试结果将显示在这里..."
|
||||
/>
|
||||
<a-button @click="clearResults" style="margin-top: 8px">
|
||||
清空结果
|
||||
</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useUserStore, useChatStore } from '@/stores'
|
||||
import { request } from '@/services/api'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const chatStore = useChatStore()
|
||||
|
||||
const loginLoading = ref(false)
|
||||
const wsLoading = ref(false)
|
||||
const apiLoading = ref(false)
|
||||
const testResults = ref('')
|
||||
|
||||
const addResult = (message: string) => {
|
||||
const timestamp = new Date().toLocaleTimeString()
|
||||
testResults.value += `[${timestamp}] ${message}\n`
|
||||
}
|
||||
|
||||
const testLogin = async () => {
|
||||
loginLoading.value = true
|
||||
try {
|
||||
addResult('开始测试登录...')
|
||||
|
||||
const result = await userStore.loginWithAuth({
|
||||
account: 'test@example.com',
|
||||
password: '123456',
|
||||
captcha: '1234'
|
||||
})
|
||||
|
||||
addResult(`登录成功: ${JSON.stringify(result)}`)
|
||||
addResult(`Token: ${userStore.token}`)
|
||||
addResult(`用户信息: ${JSON.stringify(userStore.userInfo)}`)
|
||||
|
||||
} catch (error: any) {
|
||||
addResult(`登录失败: ${error.message}`)
|
||||
} finally {
|
||||
loginLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const testWebSocketConnect = async () => {
|
||||
wsLoading.value = true
|
||||
try {
|
||||
addResult('开始测试WebSocket连接...')
|
||||
|
||||
await chatStore.connectWebSocket()
|
||||
|
||||
addResult(`WebSocket连接状态: ${chatStore.wsConnected}`)
|
||||
addResult(`连接状态: ${chatStore.connectionStatus}`)
|
||||
|
||||
} catch (error: any) {
|
||||
addResult(`WebSocket连接失败: ${error.message}`)
|
||||
} finally {
|
||||
wsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const testSendMessage = async () => {
|
||||
try {
|
||||
addResult('发送测试消息...')
|
||||
|
||||
await chatStore.sendMessage('这是一条测试消息,用于验证用户身份识别')
|
||||
|
||||
addResult('消息发送成功')
|
||||
|
||||
} catch (error: any) {
|
||||
addResult(`消息发送失败: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
const checkLocalStorage = () => {
|
||||
addResult('检查本地存储...')
|
||||
addResult(`localStorage.token: ${localStorage.getItem('token')}`)
|
||||
addResult(`localStorage.userInfo: ${localStorage.getItem('userInfo')}`)
|
||||
}
|
||||
|
||||
const testApiCall = async () => {
|
||||
apiLoading.value = true
|
||||
try {
|
||||
addResult('测试API调用...')
|
||||
|
||||
const response = await request.get('/health')
|
||||
addResult(`API调用成功: ${JSON.stringify(response)}`)
|
||||
|
||||
} catch (error: any) {
|
||||
addResult(`API调用失败: ${error.message}`)
|
||||
} finally {
|
||||
apiLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const clearResults = () => {
|
||||
testResults.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.token-test {
|
||||
padding: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.test-section {
|
||||
margin-bottom: 24px;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 16px;
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #f5f5f5;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -468,6 +468,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/styles/variables.scss" as *;
|
||||
.topic-tracker-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
<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