import { Component, OnInit, inject, signal } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { DatePipe } from '@angular/common'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MockDataService } from '../../../core/services/mock-data.service'; import { QiweApiService } from '../../../core/services/api/qiwe-api.service'; import { environment } from '../../../../environments/environment'; import type { Group, Document, RiskEvent } from '../../../core/models'; import type { MessageDto } from '../../../core/services/api/qiwe-api.service'; import { StatCardComponent } from '../../../shared/components/stat-card/stat-card.component'; import { StatusBadgeComponent } from '../../../shared/components/status-badge/status-badge.component'; import { MessageStripComponent } from '../../../shared/components/message-strip/message-strip.component'; import { EmptyStateComponent } from '../../../shared/components/empty-state/empty-state.component'; import { DataTableComponent } from '../../../shared/components/data-table/data-table.component'; interface TabDef { key: string; label: string; } @Component({ selector: 'app-group-detail', standalone: true, imports: [ DatePipe, FaIconComponent, StatCardComponent, StatusBadgeComponent, MessageStripComponent, EmptyStateComponent, DataTableComponent, ], templateUrl: './group-detail.component.html', }) export class GroupDetailComponent implements OnInit { private route = inject(ActivatedRoute); private router = inject(Router); private mockData = inject(MockDataService); private qiweApi = inject(QiweApiService); loading = true; dataSource = signal<'api' | 'mock'>('mock'); group: Group | null = null; activeTab = 'info'; documents: Document[] = []; riskEvents: RiskEvent[] = []; messages: MessageDto[] = []; messagesTotal = 0; chatMessagesTotal = 0; messagesLoading = false; messagesError = ''; showSystemMessages = false; private static readonly MSG_TYPE_LABELS: Record = { 0: '文本', 2: '文本', 13: '链接', 14: '图片', 31: '应用消息', 2063: '撤回', }; readonly tabs: TabDef[] = [ { key: 'info', label: '基本信息' }, { key: 'messages', label: '群消息' }, { key: 'members', label: '群成员' }, { key: 'documents', label: '沟通记录' }, { key: 'risk', label: '风控事件' }, ]; readonly docColumns = [ { key: 'title', label: '文档标题' }, { key: 'createdBy', label: '创建人' }, { key: 'createdAt', label: '创建时间' }, { key: 'complianceStatus', label: '状态', template: 'status' as const }, ]; get messageRows(): Array { return this.messages.map((m) => ({ ...m, senderLabel: this.formatSenderLabel(m), contentLabel: this.formatMessageContent(m), msgTypeLabel: GroupDetailComponent.MSG_TYPE_LABELS[m.msgType] ?? `类型${m.msgType}`, timeLabel: new Date(m.timestamp).toLocaleString('zh-CN'), })); } private formatSenderLabel(m: MessageDto): string { if (m.senderName && m.senderName !== m.senderId) return m.senderName; if (!m.senderId) return '未知'; return m.senderId; } private formatMessageContent(m: MessageDto): string { if (m.msgType === 2063) return '撤回了一条消息'; let text = (m.content || '').trim(); if (text.startsWith('{') || text.startsWith('[')) { try { const parsed = JSON.parse(text) as Record; if (parsed['revokeMsgUniqueIdentifier']) return '撤回了一条消息'; text = typeof parsed['content'] === 'string' ? parsed['content'].trim() : typeof parsed['title'] === 'string' ? parsed['title'].trim() : typeof parsed['linkUrl'] === 'string' ? parsed['linkUrl'].trim() : ''; } catch { /* keep raw */ } } if (text) return text; const labels: Record = { 14: '[图片]', 16: '[语音]', 15: '[文件]', 22: '[视频]', 13: '[链接]', }; return labels[m.msgType] ?? `(${GroupDetailComponent.MSG_TYPE_LABELS[m.msgType] ?? '无文本内容'})`; } readonly riskColumns = [ { key: 'title', label: '事件名称' }, { key: 'type', label: '类型' }, { key: 'severity', label: '严重程度', template: 'status' as const }, { key: 'status', label: '处理状态', template: 'status' as const }, { key: 'createdAt', label: '发现时间' }, ]; ngOnInit(): void { this.route.paramMap.subscribe(params => { const id = params.get('id'); if (id) void this.loadGroup(id); }); } private async loadGroup(id: string): Promise { this.loading = true; if (environment.useBackendApi) { const result = await this.qiweApi.getGroup(id); if (result.ok && result.data?.group) { this.group = this.qiweApi.mapToGroup(result.data.group); this.dataSource.set('api'); this.documents = []; this.riskEvents = []; if (this.group.messageCountTotal > 0) { this.activeTab = 'messages'; } await this.loadMessages(id); this.loading = false; return; } } this.group = this.mockData.getGroups().find(g => g.id === id) ?? null; if (this.group) { this.dataSource.set('mock'); this.documents = this.mockData.getDocuments().filter(d => d.groupId === id); this.riskEvents = this.mockData.getRiskEvents().filter(e => e.groupId === id); } this.loading = false; } goBack(): void { this.router.navigate(['/groups']); } setActiveTab(key: string): void { this.activeTab = key; if (key === 'messages' && this.group && environment.useBackendApi && this.messages.length === 0) { void this.loadMessages(this.group.id); } } private async loadMessages(roomId: string): Promise { if (!environment.useBackendApi) return; this.messagesLoading = true; this.messagesError = ''; const result = await this.qiweApi.listMessages(roomId, 100, 0, !this.showSystemMessages); if (result.ok && result.data) { this.messages = result.data.messages; this.messagesTotal = result.data.total; this.chatMessagesTotal = result.data.chatTotal ?? result.data.messages.length; } else { this.messages = []; this.messagesTotal = 0; this.chatMessagesTotal = 0; this.messagesError = result.error ?? '加载消息失败'; } this.messagesLoading = false; } toggleSystemMessages(): void { this.showSystemMessages = !this.showSystemMessages; if (this.group) void this.loadMessages(this.group.id); } }