Files
WeChatDataAnalysis/frontend/composables/useApi.js
2977094657 b422b3c55c feat(chat): 前端增加实时开关并自动刷新会话/消息
- 聊天页新增实时开关,自动探测 realtime 可用性

- 监听 /api/chat/realtime/stream,变更时触发增量同步并刷新会话/消息

- useApi 增加 realtime 接口,sessions/messages 支持 source 参数
2026-01-01 23:24:15 +08:00

302 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// API请求组合式函数
export const useApi = () => {
const config = useRuntimeConfig()
// 基础请求函数
const request = async (url, options = {}) => {
try {
// 在客户端使用完整的API路径
const baseURL = process.client ? 'http://localhost:8000/api' : '/api'
const response = await $fetch(url, {
baseURL,
...options,
onResponseError({ response }) {
if (response.status === 400) {
throw new Error(response._data?.detail || '请求参数错误')
} else if (response.status === 500) {
throw new Error('服务器错误,请稍后重试')
}
}
})
return response
} catch (error) {
console.error('API请求错误:', error)
throw error
}
}
// 微信检测API
const detectWechat = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.data_root_path) {
query.set('data_root_path', params.data_root_path)
}
const url = '/wechat-detection' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
// 检测当前登录账号API
const detectCurrentAccount = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.data_root_path) {
query.set('data_root_path', params.data_root_path)
}
const url = '/current-account' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
// 数据库解密API
const decryptDatabase = async (data) => {
return await request('/decrypt', {
method: 'POST',
body: data
})
}
// 健康检查API
const healthCheck = async () => {
return await request('/health')
}
const listChatAccounts = async () => {
return await request('/chat/accounts')
}
const listChatSessions = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.limit != null) query.set('limit', String(params.limit))
if (params && params.include_hidden != null) query.set('include_hidden', String(!!params.include_hidden))
if (params && params.include_official != null) query.set('include_official', String(!!params.include_official))
if (params && params.source) query.set('source', params.source)
const url = '/chat/sessions' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const listChatMessages = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.username) query.set('username', params.username)
if (params && params.limit != null) query.set('limit', String(params.limit))
if (params && params.offset != null) query.set('offset', String(params.offset))
if (params && params.order) query.set('order', params.order)
if (params && params.render_types) query.set('render_types', params.render_types)
if (params && params.source) query.set('source', params.source)
const url = '/chat/messages' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const getChatRealtimeStatus = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
const url = '/chat/realtime/status' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const syncChatRealtimeMessages = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.username) query.set('username', params.username)
if (params && params.max_scan != null) query.set('max_scan', String(params.max_scan))
const url = '/chat/realtime/sync' + (query.toString() ? `?${query.toString()}` : '')
return await request(url, { method: 'POST' })
}
const syncChatRealtimeAll = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.max_scan != null) query.set('max_scan', String(params.max_scan))
if (params && params.priority_username) query.set('priority_username', params.priority_username)
if (params && params.priority_max_scan != null) query.set('priority_max_scan', String(params.priority_max_scan))
if (params && params.include_hidden != null) query.set('include_hidden', String(!!params.include_hidden))
if (params && params.include_official != null) query.set('include_official', String(!!params.include_official))
const url = '/chat/realtime/sync_all' + (query.toString() ? `?${query.toString()}` : '')
return await request(url, { method: 'POST' })
}
const searchChatMessages = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.q) query.set('q', params.q)
if (params && params.username) query.set('username', params.username)
if (params && params.sender) query.set('sender', params.sender)
if (params && params.session_type) query.set('session_type', params.session_type)
if (params && params.limit != null) query.set('limit', String(params.limit))
if (params && params.offset != null) query.set('offset', String(params.offset))
if (params && params.start_time != null) query.set('start_time', String(params.start_time))
if (params && params.end_time != null) query.set('end_time', String(params.end_time))
if (params && params.render_types) query.set('render_types', params.render_types)
if (params && params.include_hidden != null) query.set('include_hidden', String(!!params.include_hidden))
if (params && params.include_official != null) query.set('include_official', String(!!params.include_official))
if (params && params.session_limit != null) query.set('session_limit', String(params.session_limit))
if (params && params.per_chat_scan != null) query.set('per_chat_scan', String(params.per_chat_scan))
if (params && params.scan_limit != null) query.set('scan_limit', String(params.scan_limit))
const url = '/chat/search' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const listChatSearchSenders = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.username) query.set('username', params.username)
if (params && params.session_type) query.set('session_type', params.session_type)
if (params && params.limit != null) query.set('limit', String(params.limit))
if (params && params.q) query.set('q', params.q)
if (params && params.message_q) query.set('message_q', params.message_q)
if (params && params.start_time != null) query.set('start_time', String(params.start_time))
if (params && params.end_time != null) query.set('end_time', String(params.end_time))
if (params && params.render_types) query.set('render_types', params.render_types)
if (params && params.include_hidden != null) query.set('include_hidden', String(!!params.include_hidden))
if (params && params.include_official != null) query.set('include_official', String(!!params.include_official))
const url = '/chat/search-index/senders' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const getChatSearchIndexStatus = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
const url = '/chat/search-index/status' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const buildChatSearchIndex = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.rebuild != null) query.set('rebuild', String(!!params.rebuild))
const url = '/chat/search-index/build' + (query.toString() ? `?${query.toString()}` : '')
return await request(url, { method: 'POST' })
}
const getChatMessagesAround = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.username) query.set('username', params.username)
if (params && params.anchor_id) query.set('anchor_id', params.anchor_id)
if (params && params.before != null) query.set('before', String(params.before))
if (params && params.after != null) query.set('after', String(params.after))
const url = '/chat/messages/around' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
const openChatMediaFolder = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
if (params && params.username) query.set('username', params.username)
if (params && params.kind) query.set('kind', params.kind)
if (params && params.md5) query.set('md5', params.md5)
if (params && params.file_id) query.set('file_id', params.file_id)
if (params && params.server_id != null) query.set('server_id', String(params.server_id))
const url = '/chat/media/open_folder' + (query.toString() ? `?${query.toString()}` : '')
return await request(url, { method: 'POST' })
}
const downloadChatEmoji = async (data = {}) => {
return await request('/chat/media/emoji/download', {
method: 'POST',
body: {
account: data.account || null,
md5: data.md5 || '',
emoji_url: data.emoji_url || '',
force: !!data.force
}
})
}
// 保存图片解密密钥
const saveMediaKeys = async (params = {}) => {
return await request('/media/keys', {
method: 'POST',
body: {
account: params.account || null,
xor_key: params.xor_key || '',
aes_key: params.aes_key || null
}
})
}
// 获取已保存的密钥(数据库密钥 + 图片密钥)
const getSavedKeys = async (params = {}) => {
const query = new URLSearchParams()
if (params && params.account) query.set('account', params.account)
const url = '/keys' + (query.toString() ? `?${query.toString()}` : '')
return await request(url)
}
// 批量解密所有图片
const decryptAllMedia = async (params = {}) => {
return await request('/media/decrypt_all', {
method: 'POST',
body: {
account: params.account || null,
xor_key: params.xor_key || null,
aes_key: params.aes_key || null
}
})
}
// 聊天记录导出离线zip
const createChatExport = async (data = {}) => {
return await request('/chat/exports', {
method: 'POST',
body: {
account: data.account || null,
scope: data.scope || 'selected',
usernames: Array.isArray(data.usernames) ? data.usernames : [],
format: data.format || 'json',
start_time: data.start_time != null ? Number(data.start_time) : null,
end_time: data.end_time != null ? Number(data.end_time) : null,
include_hidden: !!data.include_hidden,
include_official: !!data.include_official,
message_types: Array.isArray(data.message_types) ? data.message_types : [],
include_media: data.include_media == null ? true : !!data.include_media,
media_kinds: Array.isArray(data.media_kinds) ? data.media_kinds : ['image', 'emoji', 'video', 'video_thumb', 'voice', 'file'],
allow_process_key_extract: !!data.allow_process_key_extract,
privacy_mode: !!data.privacy_mode,
file_name: data.file_name || null
}
})
}
const getChatExport = async (exportId) => {
if (!exportId) throw new Error('Missing exportId')
return await request(`/chat/exports/${encodeURIComponent(String(exportId))}`)
}
const listChatExports = async () => {
return await request('/chat/exports')
}
const cancelChatExport = async (exportId) => {
if (!exportId) throw new Error('Missing exportId')
return await request(`/chat/exports/${encodeURIComponent(String(exportId))}`, { method: 'DELETE' })
}
return {
detectWechat,
detectCurrentAccount,
decryptDatabase,
healthCheck,
listChatAccounts,
listChatSessions,
listChatMessages,
getChatRealtimeStatus,
syncChatRealtimeMessages,
syncChatRealtimeAll,
searchChatMessages,
getChatSearchIndexStatus,
buildChatSearchIndex,
listChatSearchSenders,
getChatMessagesAround,
openChatMediaFolder,
downloadChatEmoji,
saveMediaKeys,
getSavedKeys,
decryptAllMedia,
createChatExport,
getChatExport,
listChatExports,
cancelChatExport
}
}