mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-04-23 01:39:37 +08:00
feat: 新增群成员管理 & 改造成员表模型
This commit is contained in:
@@ -70,7 +70,7 @@ export function getNightOwlAnalysis(sessionId: string, filter?: TimeFilter): any
|
||||
msg.sender_id as senderId,
|
||||
msg.ts,
|
||||
m.platform_id as platformId,
|
||||
m.name
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
${clauseWithSystem}
|
||||
@@ -347,7 +347,7 @@ export function getDragonKingAnalysis(sessionId: string, filter?: TimeFilter): a
|
||||
strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime') as date,
|
||||
msg.sender_id,
|
||||
m.platform_id,
|
||||
m.name,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name,
|
||||
COUNT(*) as msg_count
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
@@ -417,7 +417,7 @@ export function getDivingAnalysis(sessionId: string, filter?: TimeFilter): any {
|
||||
SELECT
|
||||
m.id as member_id,
|
||||
m.platform_id,
|
||||
m.name,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name,
|
||||
MAX(msg.ts) as last_ts
|
||||
FROM member m
|
||||
JOIN message msg ON m.id = msg.sender_id
|
||||
@@ -475,7 +475,7 @@ export function getCheckInAnalysis(sessionId: string, filter?: TimeFilter): any
|
||||
`
|
||||
SELECT
|
||||
msg.sender_id as senderId,
|
||||
m.name,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name,
|
||||
DATE(${tsExpr}, 'unixepoch', 'localtime') as day
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
|
||||
@@ -20,9 +20,9 @@ export function getMonologueAnalysis(sessionId: string, filter?: TimeFilter): an
|
||||
|
||||
let whereClause = clause
|
||||
if (whereClause.includes('WHERE')) {
|
||||
whereClause += " AND m.name != '系统消息' AND msg.type = 0"
|
||||
whereClause += " AND COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0"
|
||||
} else {
|
||||
whereClause = " WHERE m.name != '系统消息' AND msg.type = 0"
|
||||
whereClause = " WHERE COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0"
|
||||
}
|
||||
|
||||
const messages = db
|
||||
@@ -33,7 +33,7 @@ export function getMonologueAnalysis(sessionId: string, filter?: TimeFilter): an
|
||||
msg.sender_id as senderId,
|
||||
msg.ts,
|
||||
m.platform_id as platformId,
|
||||
m.name
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
${whereClause}
|
||||
@@ -200,7 +200,7 @@ export function getMemeBattleAnalysis(sessionId: string, filter?: TimeFilter): a
|
||||
msg.type,
|
||||
msg.ts,
|
||||
m.platform_id as platformId,
|
||||
m.name
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
${whereClause}
|
||||
|
||||
@@ -30,9 +30,9 @@ export function getRepeatAnalysis(sessionId: string, filter?: TimeFilter): any {
|
||||
|
||||
let whereClause = clause
|
||||
if (whereClause.includes('WHERE')) {
|
||||
whereClause += " AND m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND TRIM(msg.content) != ''"
|
||||
whereClause += " AND COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND TRIM(msg.content) != ''"
|
||||
} else {
|
||||
whereClause = " WHERE m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND TRIM(msg.content) != ''"
|
||||
whereClause = " WHERE COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND TRIM(msg.content) != ''"
|
||||
}
|
||||
|
||||
const messages = db
|
||||
@@ -44,7 +44,7 @@ export function getRepeatAnalysis(sessionId: string, filter?: TimeFilter): any {
|
||||
msg.content,
|
||||
msg.ts,
|
||||
m.platform_id as platformId,
|
||||
m.name
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
${whereClause}
|
||||
@@ -259,10 +259,10 @@ export function getCatchphraseAnalysis(sessionId: string, filter?: TimeFilter):
|
||||
let whereClause = clause
|
||||
if (whereClause.includes('WHERE')) {
|
||||
whereClause +=
|
||||
" AND m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(TRIM(msg.content)) >= 2"
|
||||
" AND COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(TRIM(msg.content)) >= 2"
|
||||
} else {
|
||||
whereClause =
|
||||
" WHERE m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(TRIM(msg.content)) >= 2"
|
||||
" WHERE COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(TRIM(msg.content)) >= 2"
|
||||
}
|
||||
|
||||
const rows = db
|
||||
@@ -271,7 +271,7 @@ export function getCatchphraseAnalysis(sessionId: string, filter?: TimeFilter):
|
||||
SELECT
|
||||
m.id as memberId,
|
||||
m.platform_id as platformId,
|
||||
m.name,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name,
|
||||
TRIM(msg.content) as content,
|
||||
COUNT(*) as count
|
||||
FROM message msg
|
||||
|
||||
@@ -27,9 +27,9 @@ export function getMentionAnalysis(sessionId: string, filter?: TimeFilter): any
|
||||
const members = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT id, platform_id as platformId, name
|
||||
SELECT id, platform_id as platformId, COALESCE(group_nickname, account_name, platform_id) as name
|
||||
FROM member
|
||||
WHERE name != '系统消息'
|
||||
WHERE COALESCE(account_name, '') != '系统消息'
|
||||
`
|
||||
)
|
||||
.all() as Array<{ id: number; platformId: string; name: string }>
|
||||
@@ -67,9 +67,9 @@ export function getMentionAnalysis(sessionId: string, filter?: TimeFilter): any
|
||||
|
||||
let whereClause = clause
|
||||
if (whereClause.includes('WHERE')) {
|
||||
whereClause += " AND m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND msg.content LIKE '%@%'"
|
||||
whereClause += " AND COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND msg.content LIKE '%@%'"
|
||||
} else {
|
||||
whereClause = " WHERE m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND msg.content LIKE '%@%'"
|
||||
whereClause = " WHERE COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND msg.content LIKE '%@%'"
|
||||
}
|
||||
|
||||
const messages = db
|
||||
@@ -352,9 +352,9 @@ export function getLaughAnalysis(sessionId: string, filter?: TimeFilter, keyword
|
||||
|
||||
let whereClause = clause
|
||||
if (whereClause.includes('WHERE')) {
|
||||
whereClause += " AND m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL"
|
||||
whereClause += " AND COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL"
|
||||
} else {
|
||||
whereClause = " WHERE m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL"
|
||||
whereClause = " WHERE COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL"
|
||||
}
|
||||
|
||||
const messages = db
|
||||
@@ -364,7 +364,7 @@ export function getLaughAnalysis(sessionId: string, filter?: TimeFilter, keyword
|
||||
msg.sender_id as senderId,
|
||||
msg.content,
|
||||
m.platform_id as platformId,
|
||||
m.name
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
${whereClause}
|
||||
|
||||
@@ -38,7 +38,7 @@ export function getRecentMessages(
|
||||
const timeCondition = timeClause ? timeClause.replace('WHERE', 'AND') : ''
|
||||
|
||||
// 排除系统消息,只获取文本消息(type=0)
|
||||
const systemFilter = "AND m.name != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND msg.content != ''"
|
||||
const systemFilter = "AND COALESCE(m.account_name, '') != '系统消息' AND msg.type = 0 AND msg.content IS NOT NULL AND msg.content != ''"
|
||||
|
||||
// 查询总数
|
||||
const countSql = `
|
||||
@@ -56,7 +56,7 @@ export function getRecentMessages(
|
||||
const sql = `
|
||||
SELECT
|
||||
msg.id,
|
||||
m.name as senderName,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as senderName,
|
||||
m.platform_id as senderPlatformId,
|
||||
msg.content,
|
||||
msg.ts as timestamp,
|
||||
@@ -79,63 +79,79 @@ export function getRecentMessages(
|
||||
/**
|
||||
* 关键词搜索消息
|
||||
* @param sessionId 会话 ID
|
||||
* @param keywords 关键词数组(OR 逻辑)
|
||||
* @param keywords 关键词数组(OR 逻辑),可以为空数组
|
||||
* @param filter 时间过滤器
|
||||
* @param limit 返回数量限制
|
||||
* @param offset 偏移量(分页)
|
||||
* @param senderId 可选的发送者成员 ID,用于筛选特定成员的消息
|
||||
*/
|
||||
export function searchMessages(
|
||||
sessionId: string,
|
||||
keywords: string[],
|
||||
filter?: TimeFilter,
|
||||
limit: number = 20,
|
||||
offset: number = 0
|
||||
offset: number = 0,
|
||||
senderId?: number
|
||||
): { messages: SearchMessageResult[]; total: number } {
|
||||
const db = openDatabase(sessionId)
|
||||
if (!db) return { messages: [], total: 0 }
|
||||
|
||||
// 构建关键词条件(OR 逻辑)
|
||||
const keywordConditions = keywords.map(() => `msg.content LIKE ?`).join(' OR ')
|
||||
const keywordParams = keywords.map((k) => `%${k}%`)
|
||||
let keywordCondition = '1=1' // 默认条件(始终为真)
|
||||
const keywordParams: string[] = []
|
||||
if (keywords.length > 0) {
|
||||
keywordCondition = `(${keywords.map(() => `msg.content LIKE ?`).join(' OR ')})`
|
||||
keywordParams.push(...keywords.map((k) => `%${k}%`))
|
||||
}
|
||||
|
||||
// 构建时间过滤条件
|
||||
const { clause: timeClause, params: timeParams } = buildTimeFilter(filter)
|
||||
const timeCondition = timeClause ? timeClause.replace('WHERE', 'AND') : ''
|
||||
|
||||
// 排除系统消息
|
||||
const systemFilter = "AND m.name != '系统消息'"
|
||||
const systemFilter = "AND COALESCE(m.account_name, '') != '系统消息'"
|
||||
|
||||
// 构建发送者筛选条件
|
||||
let senderCondition = ''
|
||||
const senderParams: number[] = []
|
||||
if (senderId !== undefined) {
|
||||
senderCondition = 'AND msg.sender_id = ?'
|
||||
senderParams.push(senderId)
|
||||
}
|
||||
|
||||
// 查询总数
|
||||
const countSql = `
|
||||
SELECT COUNT(*) as total
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE (${keywordConditions})
|
||||
WHERE ${keywordCondition}
|
||||
${timeCondition}
|
||||
${systemFilter}
|
||||
${senderCondition}
|
||||
`
|
||||
const totalRow = db.prepare(countSql).get(...keywordParams, ...timeParams) as { total: number }
|
||||
const totalRow = db.prepare(countSql).get(...keywordParams, ...timeParams, ...senderParams) as { total: number }
|
||||
const total = totalRow?.total || 0
|
||||
|
||||
// 查询消息
|
||||
const sql = `
|
||||
SELECT
|
||||
msg.id,
|
||||
m.name as senderName,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as senderName,
|
||||
m.platform_id as senderPlatformId,
|
||||
msg.content,
|
||||
msg.ts as timestamp,
|
||||
msg.type
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE (${keywordConditions})
|
||||
WHERE ${keywordCondition}
|
||||
${timeCondition}
|
||||
${systemFilter}
|
||||
${senderCondition}
|
||||
ORDER BY msg.ts DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
|
||||
const rows = db.prepare(sql).all(...keywordParams, ...timeParams, limit, offset) as SearchMessageResult[]
|
||||
const rows = db.prepare(sql).all(...keywordParams, ...timeParams, ...senderParams, limit, offset) as SearchMessageResult[]
|
||||
|
||||
return { messages: rows, total }
|
||||
}
|
||||
@@ -159,14 +175,14 @@ export function getMessageContext(
|
||||
const sql = `
|
||||
SELECT
|
||||
msg.id,
|
||||
m.name as senderName,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as senderName,
|
||||
m.platform_id as senderPlatformId,
|
||||
msg.content,
|
||||
msg.ts as timestamp,
|
||||
msg.type
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE m.name != '系统消息'
|
||||
WHERE COALESCE(m.account_name, '') != '系统消息'
|
||||
AND msg.ts BETWEEN ? AND ?
|
||||
ORDER BY msg.ts ASC
|
||||
LIMIT ?
|
||||
@@ -183,3 +199,82 @@ export function getMessageContext(
|
||||
return rows
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个成员之间的对话
|
||||
* 提取两人相邻发言形成的对话片段
|
||||
* @param sessionId 会话 ID
|
||||
* @param memberId1 成员1的 ID
|
||||
* @param memberId2 成员2的 ID
|
||||
* @param filter 时间过滤器
|
||||
* @param limit 返回消息数量限制
|
||||
*/
|
||||
export function getConversationBetween(
|
||||
sessionId: string,
|
||||
memberId1: number,
|
||||
memberId2: number,
|
||||
filter?: TimeFilter,
|
||||
limit: number = 100
|
||||
): { messages: SearchMessageResult[]; total: number; member1Name: string; member2Name: string } {
|
||||
const db = openDatabase(sessionId)
|
||||
if (!db) return { messages: [], total: 0, member1Name: '', member2Name: '' }
|
||||
|
||||
// 获取成员名称
|
||||
const member1 = db.prepare(`
|
||||
SELECT COALESCE(group_nickname, account_name, platform_id) as name
|
||||
FROM member WHERE id = ?
|
||||
`).get(memberId1) as { name: string } | undefined
|
||||
|
||||
const member2 = db.prepare(`
|
||||
SELECT COALESCE(group_nickname, account_name, platform_id) as name
|
||||
FROM member WHERE id = ?
|
||||
`).get(memberId2) as { name: string } | undefined
|
||||
|
||||
if (!member1 || !member2) {
|
||||
return { messages: [], total: 0, member1Name: '', member2Name: '' }
|
||||
}
|
||||
|
||||
// 构建时间过滤条件
|
||||
const { clause: timeClause, params: timeParams } = buildTimeFilter(filter)
|
||||
const timeCondition = timeClause ? timeClause.replace('WHERE', 'AND') : ''
|
||||
|
||||
// 查询两人之间的所有消息
|
||||
const countSql = `
|
||||
SELECT COUNT(*) as total
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE msg.sender_id IN (?, ?)
|
||||
${timeCondition}
|
||||
AND msg.content IS NOT NULL AND msg.content != ''
|
||||
`
|
||||
const totalRow = db.prepare(countSql).get(memberId1, memberId2, ...timeParams) as { total: number }
|
||||
const total = totalRow?.total || 0
|
||||
|
||||
// 查询消息
|
||||
const sql = `
|
||||
SELECT
|
||||
msg.id,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as senderName,
|
||||
m.platform_id as senderPlatformId,
|
||||
msg.content,
|
||||
msg.ts as timestamp,
|
||||
msg.type
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE msg.sender_id IN (?, ?)
|
||||
${timeCondition}
|
||||
AND msg.content IS NOT NULL AND msg.content != ''
|
||||
ORDER BY msg.ts DESC
|
||||
LIMIT ?
|
||||
`
|
||||
|
||||
const rows = db.prepare(sql).all(memberId1, memberId2, ...timeParams, limit) as SearchMessageResult[]
|
||||
|
||||
// 返回时按时间正序排列(便于阅读对话)
|
||||
return {
|
||||
messages: rows.reverse(),
|
||||
total,
|
||||
member1Name: member1.name,
|
||||
member2Name: member2.name,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,15 @@
|
||||
import Database from 'better-sqlite3'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { openDatabase, getDbDir, getDbPath, buildTimeFilter, buildSystemMessageFilter, type TimeFilter } from '../core'
|
||||
import {
|
||||
openDatabase,
|
||||
closeDatabase,
|
||||
getDbDir,
|
||||
getDbPath,
|
||||
buildTimeFilter,
|
||||
buildSystemMessageFilter,
|
||||
type TimeFilter,
|
||||
} from '../core'
|
||||
|
||||
// ==================== 基础查询 ====================
|
||||
|
||||
@@ -40,7 +48,7 @@ export function getMemberActivity(sessionId: string, filter?: TimeFilter): any[]
|
||||
const { clause, params } = buildTimeFilter(filter)
|
||||
|
||||
const msgFilterBase = clause ? clause.replace('WHERE', 'AND') : ''
|
||||
const msgFilterWithSystem = msgFilterBase + " AND m.name != '系统消息'"
|
||||
const msgFilterWithSystem = msgFilterBase + " AND COALESCE(m.account_name, '') != '系统消息'"
|
||||
|
||||
const totalClauseWithSystem = buildSystemMessageFilter(clause)
|
||||
const totalMessages = (
|
||||
@@ -60,11 +68,11 @@ export function getMemberActivity(sessionId: string, filter?: TimeFilter): any[]
|
||||
SELECT
|
||||
m.id as memberId,
|
||||
m.platform_id as platformId,
|
||||
m.name,
|
||||
COALESCE(m.group_nickname, m.account_name, m.platform_id) as name,
|
||||
COUNT(msg.id) as messageCount
|
||||
FROM member m
|
||||
LEFT JOIN message msg ON m.id = msg.sender_id ${msgFilterWithSystem}
|
||||
WHERE m.name != '系统消息'
|
||||
WHERE COALESCE(m.account_name, '') != '系统消息'
|
||||
GROUP BY m.id
|
||||
HAVING messageCount > 0
|
||||
ORDER BY messageCount DESC
|
||||
@@ -287,13 +295,13 @@ export function getMemberNameHistory(sessionId: string, memberId: number): any[]
|
||||
const rows = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT name, start_ts as startTs, end_ts as endTs
|
||||
SELECT name_type as nameType, name, start_ts as startTs, end_ts as endTs
|
||||
FROM member_name_history
|
||||
WHERE member_id = ?
|
||||
ORDER BY start_ts DESC
|
||||
`
|
||||
)
|
||||
.all(memberId) as Array<{ name: string; startTs: number; endTs: number | null }>
|
||||
.all(memberId) as Array<{ nameType: string; name: string; startTs: number; endTs: number | null }>
|
||||
|
||||
return rows
|
||||
}
|
||||
@@ -336,7 +344,7 @@ export function getAllSessions(): any[] {
|
||||
`SELECT COUNT(*) as count
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE m.name != '系统消息'`
|
||||
WHERE COALESCE(m.account_name, '') != '系统消息'`
|
||||
)
|
||||
.get() as { count: number }
|
||||
).count
|
||||
@@ -345,7 +353,7 @@ export function getAllSessions(): any[] {
|
||||
.prepare(
|
||||
`SELECT COUNT(*) as count
|
||||
FROM member
|
||||
WHERE name != '系统消息'`
|
||||
WHERE COALESCE(account_name, '') != '系统消息'`
|
||||
)
|
||||
.get() as { count: number }
|
||||
).count
|
||||
@@ -387,7 +395,7 @@ export function getSession(sessionId: string): any | null {
|
||||
`SELECT COUNT(*) as count
|
||||
FROM message msg
|
||||
JOIN member m ON msg.sender_id = m.id
|
||||
WHERE m.name != '系统消息'`
|
||||
WHERE COALESCE(m.account_name, '') != '系统消息'`
|
||||
)
|
||||
.get() as { count: number }
|
||||
).count
|
||||
@@ -397,7 +405,7 @@ export function getSession(sessionId: string): any | null {
|
||||
.prepare(
|
||||
`SELECT COUNT(*) as count
|
||||
FROM member
|
||||
WHERE name != '系统消息'`
|
||||
WHERE COALESCE(account_name, '') != '系统消息'`
|
||||
)
|
||||
.get() as { count: number }
|
||||
).count
|
||||
@@ -414,3 +422,159 @@ export function getSession(sessionId: string): any | null {
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 成员管理 ====================
|
||||
|
||||
/**
|
||||
* 成员信息(含统计数据)
|
||||
*/
|
||||
interface MemberWithStats {
|
||||
id: number
|
||||
platformId: string
|
||||
accountName: string | null
|
||||
groupNickname: string | null
|
||||
aliases: string[]
|
||||
messageCount: number
|
||||
}
|
||||
|
||||
// 用于标记已检查过 aliases 字段的会话
|
||||
const aliasesCheckedSessions = new Set<string>()
|
||||
|
||||
/**
|
||||
* 确保 member 表有 aliases 字段(数据库迁移)
|
||||
* 用于兼容旧数据库
|
||||
*/
|
||||
function ensureAliasesColumn(sessionId: string): void {
|
||||
// 每个会话只检查一次
|
||||
if (aliasesCheckedSessions.has(sessionId)) return
|
||||
|
||||
const dbPath = getDbPath(sessionId)
|
||||
if (!fs.existsSync(dbPath)) return
|
||||
|
||||
// 先关闭可能缓存的只读连接
|
||||
closeDatabase(sessionId)
|
||||
|
||||
// 使用写入模式打开数据库检查并添加字段
|
||||
const db = new Database(dbPath)
|
||||
db.pragma('journal_mode = WAL')
|
||||
|
||||
try {
|
||||
// 检查 aliases 字段是否存在
|
||||
const columns = db.prepare('PRAGMA table_info(member)').all() as Array<{ name: string }>
|
||||
const hasAliases = columns.some((col) => col.name === 'aliases')
|
||||
|
||||
if (!hasAliases) {
|
||||
// 添加 aliases 字段
|
||||
db.exec("ALTER TABLE member ADD COLUMN aliases TEXT DEFAULT '[]'")
|
||||
console.log(`[Worker] Added aliases column to member table in session ${sessionId}`)
|
||||
}
|
||||
|
||||
// 标记为已检查
|
||||
aliasesCheckedSessions.add(sessionId)
|
||||
} finally {
|
||||
db.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有成员列表(含消息数和别名)
|
||||
*/
|
||||
export function getMembers(sessionId: string): MemberWithStats[] {
|
||||
// 先确保数据库有 aliases 字段(兼容旧数据库)
|
||||
ensureAliasesColumn(sessionId)
|
||||
|
||||
const db = openDatabase(sessionId)
|
||||
if (!db) return []
|
||||
|
||||
const rows = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
m.id,
|
||||
m.platform_id as platformId,
|
||||
m.account_name as accountName,
|
||||
m.group_nickname as groupNickname,
|
||||
m.aliases,
|
||||
COUNT(msg.id) as messageCount
|
||||
FROM member m
|
||||
LEFT JOIN message msg ON m.id = msg.sender_id
|
||||
WHERE COALESCE(m.group_nickname, m.account_name, m.platform_id) != '系统消息'
|
||||
GROUP BY m.id
|
||||
ORDER BY messageCount DESC
|
||||
`
|
||||
)
|
||||
.all() as Array<{
|
||||
id: number
|
||||
platformId: string
|
||||
accountName: string | null
|
||||
groupNickname: string | null
|
||||
aliases: string | null
|
||||
messageCount: number
|
||||
}>
|
||||
|
||||
return rows.map((row) => ({
|
||||
id: row.id,
|
||||
platformId: row.platformId,
|
||||
accountName: row.accountName,
|
||||
groupNickname: row.groupNickname,
|
||||
aliases: row.aliases ? JSON.parse(row.aliases) : [],
|
||||
messageCount: row.messageCount,
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新成员别名
|
||||
*/
|
||||
export function updateMemberAliases(sessionId: string, memberId: number, aliases: string[]): boolean {
|
||||
const dbPath = getDbPath(sessionId)
|
||||
if (!fs.existsSync(dbPath)) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const db = new Database(dbPath)
|
||||
db.pragma('journal_mode = WAL')
|
||||
|
||||
const stmt = db.prepare('UPDATE member SET aliases = ? WHERE id = ?')
|
||||
stmt.run(JSON.stringify(aliases), memberId)
|
||||
|
||||
db.close()
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('[Worker] Failed to update member aliases:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除成员及其所有消息
|
||||
*/
|
||||
export function deleteMember(sessionId: string, memberId: number): boolean {
|
||||
const dbPath = getDbPath(sessionId)
|
||||
if (!fs.existsSync(dbPath)) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const db = new Database(dbPath)
|
||||
db.pragma('journal_mode = WAL')
|
||||
|
||||
// 使用事务删除成员及其相关数据
|
||||
const deleteTransaction = db.transaction(() => {
|
||||
// 1. 删除该成员的消息
|
||||
db.prepare('DELETE FROM message WHERE sender_id = ?').run(memberId)
|
||||
|
||||
// 2. 删除该成员的昵称历史
|
||||
db.prepare('DELETE FROM member_name_history WHERE member_id = ?').run(memberId)
|
||||
|
||||
// 3. 删除成员记录
|
||||
db.prepare('DELETE FROM member WHERE id = ?').run(memberId)
|
||||
})
|
||||
|
||||
deleteTransaction()
|
||||
db.close()
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('[Worker] Failed to delete member:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ export {
|
||||
getMemberNameHistory,
|
||||
getAllSessions,
|
||||
getSession,
|
||||
// 成员管理
|
||||
getMembers,
|
||||
updateMemberAliases,
|
||||
deleteMember,
|
||||
} from './basic'
|
||||
|
||||
// 高级分析
|
||||
@@ -33,5 +37,4 @@ export {
|
||||
} from './advanced'
|
||||
|
||||
// AI 查询
|
||||
export { searchMessages, getMessageContext, getRecentMessages } from './ai'
|
||||
|
||||
export { searchMessages, getMessageContext, getRecentMessages, getConversationBetween } from './ai'
|
||||
|
||||
Reference in New Issue
Block a user