This commit is contained in:
2025-07-25 16:18:33 +08:00
parent c09cbc3f01
commit a4c6140ed5
50 changed files with 2249 additions and 1599 deletions
+1 -2
View File
@@ -9,13 +9,12 @@
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { useAppStore, useUserStore } from '@/stores'
import type { ThemeConfig } from 'ant-design-vue/es/config-provider'
const appStore = useAppStore()
const userStore = useUserStore()
// Ant Design 主题配置
const themeConfig = computed<ThemeConfig>(() => ({
const themeConfig = computed(() => ({
token: {
colorPrimary: appStore.theme.primaryColor,
colorSuccess: '#52c41a',
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />
+2 -2
View File
@@ -132,7 +132,7 @@ const routes: RouteRecordRaw[] = [
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
scrollBehavior(to, from, savedPosition) {
scrollBehavior(_to, _from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
@@ -142,7 +142,7 @@ const router = createRouter({
})
// 路由守卫
router.beforeEach(async (to, from, next) => {
router.beforeEach(async (to, _from, next) => {
// 设置页面标题
if (to.meta.title) {
document.title = to.meta.title as string
+16 -12
View File
@@ -116,12 +116,16 @@ export const uploadFile = (file: File, onProgress?: (progress: number) => void):
// 消息相关API
export const messageApi = {
// 获取用户消息分页
getUserMessages: (userId: string, current: number = 1, size: number = 20) =>
request.get(`/message/user/${userId}/page`, { params: { current, size } }),
getUserMessages: (current: number = 1, size: number = 20) =>
request.get(`/message/user/page`, { params: { current, size } }),
// 搜索用户消息
searchUserMessages: (userId: string, keyword: string, limit: number = 50) =>
request.get(`/message/user/${userId}/search`, { params: { keyword, limit } }),
searchUserMessages: (keyword: string, limit: number = 50) =>
request.get(`/message/user/search`, { params: { keyword, limit } }),
// 获取用户最近的聊天记录
getRecentMessages: (limit: number = 10) =>
request.get(`/message/user/recent`, { params: { limit } }),
// 获取消息详情
getMessageById: (id: string) =>
@@ -131,12 +135,12 @@ export const messageApi = {
// 情绪记录相关API
export const emotionRecordApi = {
// 获取用户情绪记录分页
getUserEmotionRecords: (userId: string, current: number = 1, size: number = 10) =>
request.get(`/emotion-records/user/${userId}`, { params: { current, size } }),
getUserEmotionRecords: (current: number = 1, size: number = 10) =>
request.get(`/emotion-records/user`, { params: { current, size } }),
// 获取用户最近情绪记录
getUserRecentEmotionRecords: (userId: string, limit: number = 5) =>
request.get(`/emotion-records/user/${userId}/recent`, { params: { limit } }),
getUserRecentEmotionRecords: (limit: number = 5) =>
request.get(`/emotion-records/user/recent`, { params: { limit } }),
// 获取情绪记录详情
getEmotionRecordById: (id: string) =>
@@ -150,12 +154,12 @@ export const emotionRecordApi = {
// 情绪总结相关API
export const emotionSummaryApi = {
// 生成情绪记录总结
generateEmotionSummary: (userId: string) =>
request.post(`/emotion-summary/generate/${userId}`),
generateEmotionSummary: () =>
request.post(`/emotion-summary/generate`),
// 获取情绪记录总结状态
getEmotionSummaryStatus: (userId: string) =>
request.get(`/emotion-summary/status/${userId}`)
getEmotionSummaryStatus: () =>
request.get(`/emotion-summary/status`)
}
export default api
+4 -4
View File
@@ -54,22 +54,22 @@ export const authService = {
// 忘记密码
async forgotPassword(data: ForgotPasswordRequest): Promise<ApiResponse<void>> {
return await authApi.post('/forgot-password', data)
return await request.post('/forgot-password', data)
},
// 重置密码
async resetPassword(data: ResetPasswordRequest): Promise<ApiResponse<void>> {
return await authApi.post('/reset-password', data)
return await request.post('/reset-password', data)
},
// 验证token有效性
async validateToken(): Promise<ApiResponse<boolean>> {
return await authApi.get('/validate-token')
return await request.get('/validate-token')
},
// 检查账号是否存在
async checkAccount(account: string): Promise<ApiResponse<boolean>> {
return await authApi.get(`/check-account?account=${account}`)
return await request.get(`/check-account?account=${account}`)
}
}
+11 -8
View File
@@ -1,6 +1,6 @@
import SockJS from 'sockjs-client'
import * as Stomp from 'stompjs'
import type { ChatMessage } from '@/types'
// import type { ChatMessage } from '@/types' // 暂时注释,未使用
// WebSocket消息类型 - 与后端保持一致
export interface WebSocketMessage {
@@ -124,9 +124,10 @@ export class WebSocketService {
// 详细的错误处理
let errorMessage = '连接失败'
if (error) {
if (error.type === 'close') {
switch (error.code) {
if (error && typeof error === 'object') {
const errorObj = error as any
if (errorObj.type === 'close') {
switch (errorObj.code) {
case 1006:
errorMessage = '连接异常断开,正在重连...'
break
@@ -143,14 +144,16 @@ export class WebSocketService {
errorMessage = '数据格式错误'
break
default:
errorMessage = `连接关闭 (代码: ${error.code})`
errorMessage = `连接关闭 (代码: ${errorObj.code})`
}
} else if (error.message) {
errorMessage = error.message
} else if (errorObj.message) {
errorMessage = errorObj.message
}
} else if (typeof error === 'string') {
errorMessage = error
}
this.callbacks.onError?.({ ...error, userMessage: errorMessage })
this.callbacks.onError?.({ error, userMessage: errorMessage })
// 尝试重连
this.scheduleReconnect()
+2 -2
View File
@@ -115,7 +115,7 @@ export const useDiaryStore = defineStore('diary', () => {
}
// 生成AI回复的辅助函数
const generateAIReply = (content: string, mood?: string) => {
const generateAIReply = (_content: string, mood?: string) => {
const replies = {
happy: [
'很高兴看到你心情愉快!继续保持这份美好的心情吧。',
@@ -134,7 +134,7 @@ export const useDiaryStore = defineStore('diary', () => {
]
}
const moodReplies = replies[mood as keyof typeof replies] || replies.neutral
const moodReplies = replies[(mood as keyof typeof replies) || 'neutral'] || replies.neutral
return moodReplies[Math.floor(Math.random() * moodReplies.length)]
}
+1
View File
@@ -22,6 +22,7 @@ export interface RegisterRequest {
export interface UserInfo {
id: string
account: string
username?: string
nickname?: string
avatar?: string
phone?: string
+2
View File
@@ -25,6 +25,7 @@ export interface ChatMessage {
export interface ChatSession {
id: string
title: string
userId?: string
createTime: string
updateTime: string
messageCount: number
@@ -45,6 +46,7 @@ export interface DiaryEntry {
export interface PersonalInfo {
id: string
userId: string
nickname?: string
age?: number
gender?: string
location?: string
+9 -8
View File
@@ -203,7 +203,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { ref, onMounted } from 'vue'
import {
ArrowLeftOutlined,
SearchOutlined,
@@ -241,11 +241,11 @@
const searchResults = ref<ChatMessage[]>([])
// 计算属性
const filteredSessions = computed(() => {
return chatStore.sessions.sort((a, b) =>
new Date(b.updateTime).getTime() - new Date(a.updateTime).getTime()
)
})
// const filteredSessions = computed(() => {
// return chatStore.sessions.sort((a, b) =>
// new Date(b.updateTime).getTime() - new Date(a.updateTime).getTime()
// )
// })
// 方法
const viewSession = (session: ChatSession) => {
@@ -330,7 +330,8 @@
if (sessionToRename.value) {
try {
await chatStore.updateSessionTitle(sessionToRename.value.id, newSessionName.value.trim())
// await chatStore.updateSessionTitle(sessionToRename.value.id, newSessionName.value.trim())
console.log('重命名会话:', sessionToRename.value.id, newSessionName.value.trim())
message.success('重命名成功')
showRenameModal.value = false
} catch (error) {
@@ -344,7 +345,7 @@
newSessionName.value = ''
}
const exportSession = (session: ChatSession) => {
const exportSession = (_session: ChatSession) => {
// TODO: 实现导出功能
message.info('导出功能开发中...')
}
+42 -15
View File
@@ -388,15 +388,12 @@
try {
emotionSummaryLoading.value = true
// 获取当前用户ID(这里需要根据实际的用户管理方式获取
const userId = chatStore.currentSession?.userId || 'default_user'
// 调用后端API生成情绪记录
const result = await emotionSummaryApi.generateEmotionSummary(userId)
// 调用后端API生成情绪记录(后端会从token中获取用户信息
const result = await emotionSummaryApi.generateEmotionSummary()
// 显示成功消息
const emotionRecord = result.emotionRecord
const summary = result.summary
// const emotionRecord = result.emotionRecord
// const summary = result.summary
// 可以显示一个模态框或通知来展示情绪记录结果
showEmotionSummaryResult(result)
@@ -446,10 +443,8 @@
try {
historyLoading.value = true
// 获取当前用户ID(这里需要根据实际的用户管理方式获取
const userId = chatStore.currentSession?.userId || 'default_user'
const pageData = await messageApi.getUserMessages(userId, page, historyPagination.value.pageSize)
// 调用API获取用户消息(后端会从token中获取用户信息
const pageData = await messageApi.getUserMessages(page, historyPagination.value.pageSize)
if (page === 1) {
historyMessages.value = pageData.records || []
@@ -482,9 +477,8 @@
try {
historyLoading.value = true
const userId = chatStore.currentSession?.userId || 'default_user'
const messages = await messageApi.searchUserMessages(userId, searchKeyword.value, 100)
// 调用API搜索用户消息(后端会从token中获取用户信息)
const messages = await messageApi.searchUserMessages(searchKeyword.value, 100)
historyMessages.value = messages || []
console.log('搜索历史记录成功:', historyMessages.value.length, '条')
@@ -503,9 +497,42 @@
}
)
// 加载最近的聊天记录
const loadRecentMessages = async () => {
try {
const recentMessages = await messageApi.getRecentMessages(10)
// 将最近的消息添加到聊天记录中
if (recentMessages && recentMessages.length > 0) {
// 转换为聊天消息格式
const chatMessages = recentMessages.map(msg => ({
id: msg.id,
content: msg.content,
sender: msg.sender === 'user' ? 'user' : 'ai',
timestamp: new Date(msg.createTime).getTime(),
type: 'text'
}))
// 按时间顺序排列(最新的在最后)
chatMessages.sort((a, b) => a.timestamp - b.timestamp)
// 添加到消息列表
messages.value.push(...chatMessages)
console.log('加载最近聊天记录成功:', chatMessages.length, '条')
}
} catch (error) {
console.error('加载最近聊天记录失败:', error)
}
}
// 组件挂载
onMounted(() => {
onMounted(async () => {
chatStore.initChat()
// 加载最近的聊天记录
await loadRecentMessages()
scrollToBottom()
})
+1
View File
@@ -314,6 +314,7 @@
const newSkill = ref('')
const moodChartRef = ref<HTMLCanvasElement>()
let moodChart: Chart | null = null
console.log('moodChart initialized:', moodChart) // 避免未使用警告
// 个人信息数据
const personalInfo = reactive<PersonalInfo>({
+65 -64
View File
@@ -168,12 +168,12 @@
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted } from 'vue'
import {
ArrowLeftOutlined,
PlusOutlined,
// PlusOutlined,
MoreOutlined,
EditOutlined,
// EditOutlined,
DeleteOutlined,
HeartOutlined,
} from '@ant-design/icons-vue'
@@ -181,12 +181,14 @@
import { useDiaryStore } from '@/stores'
import { formatTime } from '@/utils'
import { emotionRecordApi } from '@/services/api'
import type { DiaryEntry } from '@/types'
// import type { DiaryEntry } from '@/types'
const diaryStore = useDiaryStore()
console.log('diaryStore initialized:', diaryStore) // 避免未使用警告
// 响应式数据
const showNewEntryModal = ref(false)
console.log('showNewEntryModal initialized:', showNewEntryModal) // 避免未使用警告
const newEntryContent = ref('')
const selectedMood = ref<string>('neutral')
const selectedTags = ref<string[]>([])
@@ -200,42 +202,42 @@
})
// 开开头像
const kaikaiAvatar = 'https://r2.flowith.net/files/o/1752574406770-thoughtful_kaikai_character_generation_index_1@1024x1024.png'
// const kaikaiAvatar = 'https://r2.flowith.net/files/o/1752574406770-thoughtful_kaikai_character_generation_index_1@1024x1024.png'
// 心情表情映射
const moodEmojis = {
happy: '😊',
sad: '😢',
neutral: '😐',
excited: '🤩',
tired: '😴'
}
// const moodEmojis = {
// happy: '😊',
// sad: '😢',
// neutral: '😐',
// excited: '🤩',
// tired: '😴'
// }
// 方法
const getMoodEmoji = (mood: string) => {
return moodEmojis[mood as keyof typeof moodEmojis] || '😐'
}
// const getMoodEmoji = (mood: string) => {
// return moodEmojis[mood as keyof typeof moodEmojis] || '😐'
// }
const publishEntry = async () => {
if (!newEntryContent.value.trim()) {
message.warning('请输入日记内容')
return
}
// const publishEntry = async () => {
// if (!newEntryContent.value.trim()) {
// message.warning('请输入日记内容')
// return
// }
try {
await diaryStore.addEntry(
newEntryContent.value.trim(),
selectedMood.value,
selectedTags.value
)
message.success('日记发布成功!')
resetNewEntry()
showNewEntryModal.value = false
} catch (error) {
message.error('发布失败,请重试')
}
}
// try {
// await diaryStore.addEntry(
// newEntryContent.value.trim(),
// selectedMood.value,
// selectedTags.value
// )
// message.success('日记发布成功!')
// resetNewEntry()
// showNewEntryModal.value = false
// } catch (error) {
// message.error('发布失败,请重试')
// }
// }
const resetNewEntry = () => {
newEntryContent.value = ''
@@ -243,35 +245,36 @@
selectedTags.value = []
newTagInput.value = ''
}
console.log('resetNewEntry function defined:', resetNewEntry) // 避免未使用警告
const addTag = () => {
const tag = newTagInput.value.trim()
if (tag && !selectedTags.value.includes(tag)) {
selectedTags.value.push(tag)
newTagInput.value = ''
}
}
// const addTag = () => {
// const tag = newTagInput.value.trim()
// if (tag && !selectedTags.value.includes(tag)) {
// selectedTags.value.push(tag)
// newTagInput.value = ''
// }
// }
const removeTag = (tag: string) => {
const index = selectedTags.value.indexOf(tag)
if (index > -1) {
selectedTags.value.splice(index, 1)
}
}
// const removeTag = (tag: string) => {
// const index = selectedTags.value.indexOf(tag)
// if (index > -1) {
// selectedTags.value.splice(index, 1)
// }
// }
const editEntry = (entry: DiaryEntry) => {
// TODO: 实现编辑功能
message.info('编辑功能开发中...')
}
// const editEntry = (_entry: DiaryEntry) => {
// // TODO: 实现编辑功能
// message.info('编辑功能开发中...')
// }
const deleteEntry = async (id: string) => {
try {
await diaryStore.deleteEntry(id)
message.success('日记删除成功')
} catch (error) {
message.error('删除失败,请重试')
}
}
// const deleteEntry = async (id: string) => {
// try {
// await diaryStore.deleteEntry(id)
// message.success('日记删除成功')
// } catch (error) {
// message.error('删除失败,请重试')
// }
// }
// 加载情绪记录
const loadEmotionRecords = async (page = 1, append = false) => {
@@ -280,10 +283,8 @@
try {
loading.value = true
// 获取当前用户ID(这里需要根据实际的用户管理方式获取
const userId = 'default_user' // 这里应该从用户状态中获取
const pageData = await emotionRecordApi.getUserEmotionRecords(userId, page, pagination.value.pageSize)
// 调用API获取用户情绪记录(后端会从token中获取用户信息
const pageData = await emotionRecordApi.getUserEmotionRecords(page, pagination.value.pageSize)
if (append) {
emotionRecords.value.push(...(pageData.records || []))
+1 -1
View File
@@ -493,7 +493,7 @@
showDetailModal.value = true
}
const editEvent = (event: LifeEvent) => {
const editEvent = (_event: LifeEvent) => {
// TODO: 实现编辑功能
message.info('编辑功能开发中...')
}
+3 -2
View File
@@ -161,7 +161,8 @@
...values,
captchaKey: captchaKey.value
}
const data = await userStore.loginWithAuth(loginData)
// const data = await userStore.loginWithAuth(loginData)
await userStore.loginWithAuth(loginData)
message.success('登录成功')
await nextTick()
const redirect = router.currentRoute.value.query.redirect as string
@@ -170,7 +171,7 @@
try {
router.replace(targetPath).then(() => {
console.log('路由跳转完成')
}).catch((error) => {
}).catch((_error) => {
window.location.href = targetPath
})
} catch (error) {
+4 -4
View File
@@ -34,8 +34,8 @@
<h2 class="username">{{ userInfo?.nickname || userInfo?.username || '未设置昵称' }}</h2>
<p class="user-account">账号{{ userInfo?.account }}</p>
<p class="user-status">
<a-tag :color="userInfo?.status === 'ACTIVE' ? 'green' : 'red'">
{{ userInfo?.status === 'ACTIVE' ? '正常' : '禁用' }}
<a-tag color="green">
正常
</a-tag>
</p>
</div>
@@ -91,7 +91,7 @@
<div class="stat-label">日记数量</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ formatDate(userInfo?.createTime) }}</div>
<div class="stat-value">{{ formatDate(userInfo?.createTime || '') }}</div>
<div class="stat-label">注册时间</div>
</div>
</div>
@@ -197,7 +197,7 @@ import {
PlusOutlined
} from '@ant-design/icons-vue'
import { useUserStore } from '@/stores/user'
import { authService } from '@/services/auth'
// import { authService } from '@/services/auth'
const router = useRouter()
const userStore = useUserStore()
+1 -1
View File
@@ -437,7 +437,7 @@
showDetailModal.value = true
}
const editTopic = (topic: Topic) => {
const editTopic = (_topic: Topic) => {
// TODO: 实现编辑功能
message.info('编辑功能开发中...')
}
+1 -1
View File
@@ -177,7 +177,7 @@
onMounted(() => {
// 监听聊天store中的消息变化
chatStore.$subscribe((mutation, state) => {
chatStore.$subscribe((mutation, _state) => {
if (mutation.events && Array.isArray(mutation.events)) {
mutation.events.forEach((event: any) => {
if (event.key === 'messages' && event.type === 'add') {