@@ -399,34 +399,127 @@ <h5 class="mb-0">
399399}
400400
401401// 导出结果
402- function exportResults ( ) {
403- if ( currentResults . length === 0 ) {
402+ // 导出结果 - 修复版本
403+ async function exportResults ( ) {
404+ if ( ! currentResults || currentResults . length === 0 ) {
404405 showToast ( '暂无数据可导出' , 'warning' ) ;
405406 return ;
406407 }
407408
408- // 创建CSV内容
409- let csvContent = "data:text/csv;charset=utf-8," ;
410- csvContent += "时间,方向,账号,用户ID,群组ID,消息内容\n" ;
409+ const exportButton = document . querySelector ( 'button[onclick="exportResults()"]' ) ;
410+ const originalText = exportButton . innerHTML ;
411411
412- currentResults . forEach ( message => {
413- const time = new Date ( message . timestamp * 1000 ) . toLocaleString ( 'zh-CN' ) ;
414- const direction = message . direction === 'SEND' ? '发送' : '接收' ;
415- const content = ( message . message_content || message . raw_message ) . replace ( / " / g , '""' ) ;
412+ try {
413+ // 显示导出中状态
414+ exportButton . disabled = true ;
415+ exportButton . innerHTML = '<i class="bi bi-hourglass-split"></i> 导出中...' ;
416416
417- csvContent += `"${ time } ","${ direction } ","${ message . self_id } ","${ message . user_id || '' } ","${ message . group_id || '' } ","${ content } "\n` ;
418- } ) ;
419-
420- // 下载文件
421- const encodedUri = encodeURI ( csvContent ) ;
422- const link = document . createElement ( "a" ) ;
423- link . setAttribute ( "href" , encodedUri ) ;
424- link . setAttribute ( "download" , `message_query_${ new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] } .csv` ) ;
425- document . body . appendChild ( link ) ;
426- link . click ( ) ;
427- document . body . removeChild ( link ) ;
428-
429- showToast ( '查询结果已导出' , 'success' ) ;
417+ // 获取完整的查询结果(如果总数大于当前结果数)
418+ let allResults = currentResults ;
419+
420+ if ( totalCount > currentResults . length ) {
421+ // 需要获取完整数据
422+ const form = document . getElementById ( 'queryForm' ) ;
423+ const formData = new FormData ( form ) ;
424+ const params = new URLSearchParams ( ) ;
425+
426+ // 构建查询参数(与performQuery函数中的逻辑一致)
427+ for ( let [ key , value ] of formData . entries ( ) ) {
428+ const trimmedValue = value . trim ( ) ;
429+ if ( trimmedValue ) {
430+ if ( key === 'keywords' && trimmedValue . includes ( ',' ) ) {
431+ const keywords = trimmedValue . split ( / [ , , ] / ) . map ( k => k . trim ( ) ) . filter ( k => k ) ;
432+ keywords . forEach ( keyword => params . append ( 'keywords' , keyword ) ) ;
433+ } else if ( key === 'start_time' || key === 'end_time' ) {
434+ const timestamp = Math . floor ( new Date ( trimmedValue ) . getTime ( ) / 1000 ) ;
435+ params . append ( key , timestamp ) ;
436+ } else {
437+ params . append ( key , trimmedValue ) ;
438+ }
439+ }
440+ }
441+
442+ // 设置大的limit以获取所有结果
443+ params . set ( 'limit' , '10000' ) ;
444+ params . set ( 'offset' , '0' ) ;
445+
446+ // 重新查询获取完整数据
447+ const response = await apiRequest ( `/api/query_messages?${ params . toString ( ) } ` ) ;
448+ allResults = response . messages || [ ] ;
449+ }
450+
451+ if ( allResults . length === 0 ) {
452+ showToast ( '没有数据可导出' , 'warning' ) ;
453+ return ;
454+ }
455+
456+ // 创建CSV内容
457+ const csvRows = [ ] ;
458+ csvRows . push ( [ '时间' , '方向' , '机器人账号' , '用户ID' , '用户名' , '群组ID' , '消息内容' ] ) ;
459+
460+ allResults . forEach ( message => {
461+ const time = new Date ( message . timestamp * 1000 ) . toLocaleString ( 'zh-CN' ) ;
462+ const direction = message . direction === 'SEND' ? '发送' : '接收' ;
463+
464+ // 解析发送者信息
465+ let senderName = '' ;
466+ try {
467+ const sender = message . sender_info || { } ;
468+ senderName = sender . nickname || sender . card || '' ;
469+ } catch {
470+ senderName = '' ;
471+ }
472+
473+ const content = ( message . message_content || message . raw_message || '' ) . replace ( / " / g, '""' ) ;
474+
475+ csvRows . push ( [
476+ time ,
477+ direction ,
478+ message . self_id || '' ,
479+ message . user_id || '' ,
480+ senderName ,
481+ message . group_id || '' ,
482+ content
483+ ] ) ;
484+ } ) ;
485+
486+ // 转换为CSV格式
487+ const csvContent = csvRows . map ( row =>
488+ row . map ( field => `"${ field } "` ) . join ( ',' )
489+ ) . join ( '\n' ) ;
490+
491+ // 创建Blob并下载
492+ const blob = new Blob ( [ '\ufeff' + csvContent ] , { type : 'text/csv;charset=utf-8' } ) ;
493+ const url = window . URL . createObjectURL ( blob ) ;
494+ const link = document . createElement ( 'a' ) ;
495+
496+ // 生成文件名
497+ const now = new Date ( ) ;
498+ const dateStr = now . toISOString ( ) . split ( 'T' ) [ 0 ] ;
499+ const timeStr = now . toTimeString ( ) . split ( ' ' ) [ 0 ] . replace ( / : / g, '' ) ;
500+ const filename = `消息查询结果_${ dateStr } _${ timeStr } .csv` ;
501+
502+ link . href = url ;
503+ link . download = filename ;
504+ link . style . display = 'none' ;
505+
506+ document . body . appendChild ( link ) ;
507+ link . click ( ) ;
508+ document . body . removeChild ( link ) ;
509+
510+ // 释放URL对象
511+ window . URL . revokeObjectURL ( url ) ;
512+
513+ showToast ( `成功导出 ${ allResults . length } 条消息记录` , 'success' ) ;
514+
515+ } catch ( error ) {
516+ console . error ( '导出失败:' , error ) ;
517+ showToast ( '导出失败: ' + error . message , 'danger' ) ;
518+ } finally {
519+ // 恢复按钮状态
520+ exportButton . disabled = false ;
521+ exportButton . innerHTML = originalText ;
522+ }
430523}
431524
432525// HTML转义函数
0 commit comments