From 38eb9e5d23d1cf9e45d7c8d872861ef07258fb86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=A1=E4=BB=94?= <1271013637@qq.com>
Date: Thu, 30 Oct 2025 19:58:19 +0800
Subject: [PATCH] feat(mobile): :sparkles: added photo album feature on mobile;
added blank AI assistant page
---
src/layout/index.vue | 67 +++++++++-
src/mobile/components/ImagePreview.vue | 7 +-
src/mobile/components/MobileLayout.vue | 63 +++++++++-
src/mobile/views/chat-room/MediaViewer.vue | 3 +-
src/mobile/views/my/AiAssistant.vue | 26 ++++
src/mobile/views/my/MyAlbum.vue | 136 +++++++++++++++++++++
src/mobile/views/my/SimpleBio.vue | 35 +++++-
src/router/index.ts | 12 ++
src/stores/file.ts | 92 +++++++++++++-
9 files changed, 426 insertions(+), 15 deletions(-)
create mode 100644 src/mobile/views/my/AiAssistant.vue
create mode 100644 src/mobile/views/my/MyAlbum.vue
diff --git a/src/layout/index.vue b/src/layout/index.vue
index 2b8580a9..941760f9 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -36,14 +36,15 @@ import { useMitt } from '@/hooks/useMitt.ts'
import rustWebSocketClient from '@/services/webSocketRust'
import { useContactStore } from '@/stores/contacts.ts'
import { useGlobalStore } from '@/stores/global.ts'
-import { isWindows } from '@/utils/PlatformConstants'
-import { MittEnum, NotificationTypeEnum, TauriCommand } from '@/enums'
+import { isMobile, isWindows } from '@/utils/PlatformConstants'
+import { MittEnum, MsgEnum, NotificationTypeEnum, TauriCommand } from '@/enums'
import { clearListener, initListener, readCountQueue } from '@/utils/ReadCountQueue'
import { emitTo, listen } from '@tauri-apps/api/event'
import { UserAttentionType } from '@tauri-apps/api/window'
import type { MessageType } from '@/services/types.ts'
import { WsResponseMessageType } from '@/services/wsType.ts'
import { useChatStore } from '@/stores/chat'
+import { useFileStore } from '@/stores/file'
import { useUserStore } from '@/stores/user'
import { useSettingStore } from '@/stores/setting.ts'
import { invokeSilently } from '@/utils/TauriInvokeHandler'
@@ -53,6 +54,7 @@ import { audioManager } from '@/utils/AudioManager'
const route = useRoute()
const userStore = useUserStore()
const chatStore = useChatStore()
+const fileStore = useFileStore()
const settingStore = useSettingStore()
const userUid = computed(() => userStore.userInfo!.uid)
const appWindow = WebviewWindow.getCurrent()
@@ -169,6 +171,62 @@ const playMessageSound = async () => {
}
}
+/**
+ * 从消息中提取文件信息并添加到 file store
+ */
+const addFileToStore = (data: MessageType) => {
+ const { message } = data
+ const { type, body, roomId, id } = message
+
+ // 只处理图片和视频类型
+ if (type !== MsgEnum.IMAGE && type !== MsgEnum.VIDEO) {
+ return
+ }
+
+ // 提取文件信息
+ const fileUrl = body.url
+ if (!fileUrl) {
+ return
+ }
+
+ // 从 URL 中提取文件名
+ let fileName = ''
+ try {
+ const urlObj = new URL(fileUrl)
+ const pathname = urlObj.pathname
+ fileName = pathname.substring(pathname.lastIndexOf('/') + 1)
+ } catch (e) {
+ // 如果不是有效的 URL,直接使用消息 ID 作为文件名
+ fileName = `${id}.${type === MsgEnum.IMAGE ? 'jpg' : 'mp4'}`
+ }
+
+ // 从文件名中提取后缀
+ const suffix = fileName.includes('.')
+ ? fileName.substring(fileName.lastIndexOf('.') + 1)
+ : type === MsgEnum.IMAGE
+ ? 'jpg'
+ : 'mp4'
+
+ // 确定 MIME 类型
+ let mimeType = ''
+ if (type === MsgEnum.IMAGE) {
+ mimeType = `image/${suffix === 'jpg' ? 'jpeg' : suffix}`
+ } else if (type === MsgEnum.VIDEO) {
+ mimeType = `video/${suffix}`
+ }
+
+ // 添加到 file store
+ fileStore.addFile({
+ id,
+ roomId,
+ fileName,
+ type: type === MsgEnum.IMAGE ? 'image' : 'video',
+ url: fileUrl,
+ suffix,
+ mimeType
+ })
+}
+
useMitt.on(WsResponseMessageType.RECEIVE_MESSAGE, async (data: MessageType) => {
if (chatStore.checkMsgExist(data.message.roomId, data.message.id)) {
return
@@ -184,6 +242,11 @@ useMitt.on(WsResponseMessageType.RECEIVE_MESSAGE, async (data: MessageType) => {
data
})
+ // 如果是图片或视频消息,添加到 file store(仅移动端需要)
+ if (isMobile()) {
+ addFileToStore(data)
+ }
+
// 不是自己发的消息才通知
if (data.fromUser.uid !== userUid.value) {
// 获取该消息的会话信息
diff --git a/src/mobile/components/ImagePreview.vue b/src/mobile/components/ImagePreview.vue
index e78291d5..1cc75299 100644
--- a/src/mobile/components/ImagePreview.vue
+++ b/src/mobile/components/ImagePreview.vue
@@ -144,16 +144,21 @@ const handleSave = async () => {
// 保存文件信息到 file store
const roomId = getCurrentRoomId()
if (roomId) {
+ // 获取文件状态,使用相对路径(localPath)而不是绝对路径
+ const fileStatus = fileDownloadStore.getFileStatus(imageUrl)
+ const localPath = fileStatus.localPath || result
+
// 如果没有消息信息,手动创建文件信息
const fileInfo = {
id: props.message!.id, // 生成唯一ID
roomId,
fileName,
type: 'image' as const,
- url: result,
+ url: localPath, // 使用相对路径
suffix: fileName.split('.').pop()?.toLowerCase()
}
fileStore.addFile(fileInfo)
+ console.log('🔍 [ImagePreview Debug] 保存文件信息到 fileStore:', fileInfo)
}
}
} catch (e) {
diff --git a/src/mobile/components/MobileLayout.vue b/src/mobile/components/MobileLayout.vue
index 99398eb8..9895409e 100644
--- a/src/mobile/components/MobileLayout.vue
+++ b/src/mobile/components/MobileLayout.vue
@@ -22,11 +22,12 @@
+
+
diff --git a/src/mobile/views/my/MyAlbum.vue b/src/mobile/views/my/MyAlbum.vue
new file mode 100644
index 00000000..72120906
--- /dev/null
+++ b/src/mobile/views/my/MyAlbum.vue
@@ -0,0 +1,136 @@
+
+
+