mirror of
https://github.com/LifeArchiveProject/WeChatDataAnalysis.git
synced 2026-02-02 05:50:50 +08:00
- 导出弹窗支持范围/格式/时间范围/媒体开关/文件名等参数 - 批量会话列表展示头像,提供 全部/群聊/单聊 tab 与搜索 - 导出进度使用 SSE 实时更新(失败回退轮询),提供进度条展示 - 支持任务取消与 ZIP 下载 - 隐私模式下导出同步隐私策略,且 hover 不再保持模糊
197 lines
6.9 KiB
JavaScript
197 lines
6.9 KiB
JavaScript
// 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))
|
||
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)
|
||
const url = '/chat/messages' + (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 getMediaKeys = async (params = {}) => {
|
||
const query = new URLSearchParams()
|
||
if (params && params.account) query.set('account', params.account)
|
||
if (params && params.force_extract) query.set('force_extract', 'true')
|
||
const url = '/media/keys' + (query.toString() ? `?${query.toString()}` : '')
|
||
return await request(url)
|
||
}
|
||
|
||
// 保存图片解密密钥
|
||
const saveMediaKeys = async (params = {}) => {
|
||
const query = new URLSearchParams()
|
||
if (params && params.account) query.set('account', params.account)
|
||
if (params && params.xor_key) query.set('xor_key', params.xor_key)
|
||
if (params && params.aes_key) query.set('aes_key', params.aes_key)
|
||
const url = '/media/keys' + (query.toString() ? `?${query.toString()}` : '')
|
||
return await request(url, { method: 'POST', body: { account: params.account, force_extract: false } })
|
||
}
|
||
|
||
// 批量解密所有图片
|
||
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,
|
||
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,
|
||
openChatMediaFolder,
|
||
downloadChatEmoji,
|
||
getMediaKeys,
|
||
saveMediaKeys,
|
||
decryptAllMedia,
|
||
createChatExport,
|
||
getChatExport,
|
||
listChatExports,
|
||
cancelChatExport
|
||
}
|
||
}
|