Initial open source release

This commit is contained in:
joeseesun
2026-05-24 13:42:56 +08:00
commit 8abb29e13e
75 changed files with 13298 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
import { NextRequest, NextResponse } from 'next/server';
import { todayStr } from '@/lib/range';
import { db } from '@/lib/db';
import { listMessagesForDate, getSyncState, listAllSyncedDates } from '@/lib/messages-store';
import { wxSessions } from '@/lib/wx';
export const dynamic = 'force-dynamic';
interface DailyHistoryRow {
date: string;
total: number;
}
export async function GET(
req: NextRequest,
ctx: { params: Promise<{ id: string }> },
) {
const { id } = await ctx.params;
const chatroomId = decodeURIComponent(id);
const url = new URL(req.url);
const date = url.searchParams.get('date') ?? todayStr();
const limit = Math.min(Number(url.searchParams.get('limit') ?? 1000), 5000);
// 拉群名(从 wx sessions
let chatName = chatroomId;
try {
const sessions = await wxSessions(500);
const found = sessions.find((s) => s.username === chatroomId);
if (found) chatName = found.chat;
} catch {}
// 当日消息
const messages = listMessagesForDate(chatroomId, date, limit);
// 当日聚合统计
const total = messages.length;
const senderMap = new Map<string, number>();
const typeMap = new Map<string, number>();
const hours = new Array(24).fill(0) as number[];
for (const m of messages) {
senderMap.set(m.sender, (senderMap.get(m.sender) ?? 0) + 1);
typeMap.set(m.type, (typeMap.get(m.type) ?? 0) + 1);
if (m.timestamp) {
const h = new Date(m.timestamp * 1000).getHours();
if (h >= 0 && h < 24) hours[h]++;
}
}
const stats = {
chat: chatName,
total,
by_hour: hours.map((count, hour) => ({ hour, count })),
by_type: Array.from(typeMap.entries())
.map(([type, count]) => ({ type, count }))
.sort((a, b) => b.count - a.count),
top_senders: Array.from(senderMap.entries())
.map(([sender, count]) => ({ sender, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 20),
};
// 历史日柱图
const dailyHistory = db()
.prepare(
'SELECT date, total FROM daily_stats WHERE chatroom_id = ? ORDER BY date ASC',
)
.all(chatroomId) as DailyHistoryRow[];
// 同步状态
const syncState = getSyncState(chatroomId);
const syncedDates = listAllSyncedDates(chatroomId);
return NextResponse.json({
ok: true,
chatroom_id: chatroomId,
date,
stats,
recent: messages,
daily_history: dailyHistory,
sync_state: syncState ?? null,
synced_dates: syncedDates,
});
}