import { randomUUID } from 'crypto'; /** * 用户服务:管理用户 UUID 和认证 */ export class UserService { constructor(driver) { this.driver = driver; } /** * 创建或获取用户 */ async getOrCreateUser(token) { const session = this.driver.session(); try { // 尝试通过 token 查找用户 const result = await session.run( `MATCH (u:User {token: $token}) RETURN u`, { token } ); if (result.records.length > 0) { const user = result.records[0].get('u'); return { id: user.properties.id, token: user.properties.token, createdAt: user.properties.created_at }; } // 创建新用户 const userId = randomUUID(); const createdAt = new Date().toISOString(); await session.run( `CREATE (u:User {id: $id, token: $token, created_at: $created_at})`, { id: userId, token, created_at: createdAt } ); return { id: userId, token, createdAt }; } finally { await session.close(); } } /** * 验证用户 token */ async validateUser(token) { if (!token) return null; const session = this.driver.session(); try { const result = await session.run( `MATCH (u:User {token: $token}) RETURN u`, { token } ); if (result.records.length > 0) { const user = result.records[0].get('u'); return { id: user.properties.id, token: user.properties.token }; } return null; } finally { await session.close(); } } /** * 获取用户图谱统计 */ async getUserGraphStats(userId) { const session = this.driver.session(); try { const result = await session.run( ` MATCH (p:Person {user_id: $userId}) RETURN p.id AS id, p.name AS name, 'person' AS type, null AS occurred_at LIMIT 200 `, { userId } ); const persons = result.records.map(r => ({ id: r.get('id'), name: r.get('name'), type: r.get('type'), occurred_at: r.get('occurred_at') })); const events = await session.run( ` MATCH (e:Event {user_id: $userId}) RETURN e.id AS id, e.summary AS name, 'event' AS type, e.occurred_at AS occurred_at LIMIT 200 `, { userId } ); const topics = await session.run( ` MATCH (t:Topic {user_id: $userId}) RETURN t.name AS id, t.name AS name, 'topic' AS type, null AS occurred_at LIMIT 100 `, { userId } ); const nodes = [ ...persons, ...events.records.map(r => ({ id: r.get('id'), name: r.get('name'), type: r.get('type'), occurred_at: r.get('occurred_at') })), ...topics.records.map(r => ({ id: r.get('id'), name: r.get('name'), type: r.get('type'), occurred_at: r.get('occurred_at') })) ]; // 查询关系 const personEventRels = await session.run( ` MATCH (p:Person {user_id: $userId})-[:PARTICIPATES_IN]->(e:Event {user_id: $userId}) RETURN p.id AS source, e.id AS target, 'PARTICIPATES_IN' AS type LIMIT 500 `, { userId } ); const eventTopicRels = await session.run( ` MATCH (e:Event {user_id: $userId})-[:ABOUT]->(t:Topic {user_id: $userId}) RETURN e.id AS source, t.name AS target, 'ABOUT' AS type LIMIT 300 `, { userId } ); const links = [ ...personEventRels.records.map(r => ({ source: r.get('source'), target: r.get('target'), type: r.get('type') })), ...eventTopicRels.records.map(r => ({ source: r.get('source'), target: r.get('target'), type: r.get('type') })) ]; return { ok: true, nodes, links, total: nodes.length }; } finally { await session.close(); } } }