import { Component, OnInit, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatTableModule } from '@angular/material/table'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatDialogModule, MatDialog } from '@angular/material/dialog'; import { MatSortModule } from '@angular/material/sort'; import { MatTabsModule } from '@angular/material/tabs'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatNativeDateModule } from '@angular/material/core'; import { ApiDialogComponent } from './api-dialog/api-dialog'; interface ApiIntegration { id: string; name: string; type: string; status: 'active' | 'inactive' | 'error'; endpoint: string; authentication: string; lastTested?: string; description: string; configuration: Record; createdBy: string; createdAt: string; updatedAt: string; } interface ApiLog { id: string; timestamp: string; integrationId: string; integrationName: string; requestMethod: string; requestUrl: string; statusCode: number; duration: number; status: 'success' | 'error'; errorMessage?: string; } @Component({ selector: 'app-api-integrations', standalone: true, imports: [ CommonModule, RouterModule, FormsModule, MatButtonModule, MatIconModule, MatTableModule, MatInputModule, MatSelectModule, MatPaginatorModule, MatDialogModule, MatSortModule, MatTabsModule, MatExpansionModule, MatSlideToggleModule, MatDatepickerModule, MatNativeDateModule ], templateUrl: './api-integrations.html', styleUrl: './api-integrations.scss' }) export class ApiIntegrations implements OnInit { // 激活的标签页 activeTab = 'integrations'; // API集成数据 apiIntegrations = signal([]); filteredIntegrations = signal([]); integrationSearchTerm = ''; integrationTypeFilter = ''; integrationStatusFilter = ''; integrationSortColumn = 'createdAt'; integrationSortDirection = 'desc'; integrationPageSize = 10; integrationCurrentPage = 0; // API日志数据 apiLogs = signal([]); filteredLogs = signal([]); logSearchTerm = ''; logIntegrationFilter = ''; logStatusFilter = ''; logStartDate: Date | null = null; logEndDate: Date | null = null; logSortColumn = 'timestamp'; logSortDirection = 'desc'; logPageSize = 20; logCurrentPage = 0; // 可用的筛选选项 integrationTypes = ['渲染农场', '设计素材库', '客户管理', '财务系统', '项目管理', '人力资源', '其他系统']; integrationStatuses = [ { value: 'active', label: '已激活' }, { value: 'inactive', label: '已禁用' }, { value: 'error', label: '错误' } ]; logStatuses = [ { value: 'success', label: '成功' }, { value: 'error', label: '失败' } ]; // 状态颜色映射 statusColors: Record = { 'active': '#00B42A', 'inactive': '#F53F3F', 'error': '#FFAA00' }; // 状态图标映射 statusIcons: Record = { 'active': 'check_circle', 'inactive': 'cancel', 'error': 'error' }; constructor(private dialog: MatDialog) {} ngOnInit(): void { this.loadApiIntegrations(); this.loadApiLogs(); } // 加载API集成数据 loadApiIntegrations(): void { // 模拟API集成数据 this.apiIntegrations.set([ { id: '1', name: '渲染农场API', type: '渲染农场', status: 'active', endpoint: 'https://render-farm.example.com/api/v1', authentication: 'API Key', lastTested: '2025-09-15 10:30:00', description: '与外部渲染农场服务的集成,用于提交和管理渲染任务', configuration: { apiKey: '********', timeout: 300, retryCount: 3, priority: 'medium' }, createdBy: '超级管理员', createdAt: '2025-09-01 14:20:00', updatedAt: '2025-09-10 09:15:00' }, { id: '2', name: '设计素材库API', type: '设计素材库', status: 'active', endpoint: 'https://design-assets.example.com/api/v2', authentication: 'OAuth 2.0', lastTested: '2025-09-14 16:45:00', description: '与设计素材库服务的集成,用于搜索和获取设计素材', configuration: { clientId: 'design_assets_client', clientSecret: '********', scope: 'read write', tokenUrl: 'https://design-assets.example.com/oauth/token' }, createdBy: '超级管理员', createdAt: '2025-08-25 11:30:00', updatedAt: '2025-09-05 15:20:00' }, { id: '3', name: '客户管理系统API', type: '客户管理', status: 'error', endpoint: 'https://crm.example.com/api', authentication: 'API Key', lastTested: '2025-09-15 08:10:00', description: '与客户管理系统的集成,用于同步客户信息和订单数据', configuration: { apiKey: '********', syncInterval: 'daily', syncFields: ['name', 'email', 'phone', 'address'] }, createdBy: '超级管理员', createdAt: '2025-08-20 09:45:00', updatedAt: '2025-09-12 14:30:00' }, { id: '4', name: '财务系统API', type: '财务系统', status: 'inactive', endpoint: 'https://finance.example.com/api/v3', authentication: 'OAuth 2.0', lastTested: '2025-09-10 11:20:00', description: '与财务系统的集成,用于同步项目财务数据和生成报表', configuration: { clientId: 'finance_api_client', clientSecret: '********', scope: 'read', tokenUrl: 'https://finance.example.com/oauth/token' }, createdBy: '超级管理员', createdAt: '2025-08-15 16:00:00', updatedAt: '2025-09-01 10:15:00' }, { id: '5', name: '项目管理工具API', type: '项目管理', status: 'active', endpoint: 'https://project-tool.example.com/api', authentication: 'Webhook', lastTested: '2025-09-15 13:40:00', description: '与项目管理工具的集成,用于创建和更新项目任务', configuration: { webhookUrl: 'https://example.com/webhooks/project-updates', secretToken: '********', eventTypes: ['task_created', 'task_updated', 'task_completed'] }, createdBy: '超级管理员', createdAt: '2025-08-10 14:50:00', updatedAt: '2025-09-08 16:25:00' } ]); this.filteredIntegrations = this.apiIntegrations; this.applyIntegrationFilters(); } // 加载API日志数据 loadApiLogs(): void { // 模拟API日志数据 const mockLogs: ApiLog[] = [ { id: '1', timestamp: '2025-09-15 14:30:25', integrationId: '1', integrationName: '渲染农场API', requestMethod: 'POST', requestUrl: '/render-jobs', statusCode: 200, duration: 1250, status: 'success' }, { id: '2', timestamp: '2025-09-15 14:25:10', integrationId: '2', integrationName: '设计素材库API', requestMethod: 'GET', requestUrl: '/assets?category=3d-models', statusCode: 200, duration: 850, status: 'success' }, { id: '3', timestamp: '2025-09-15 14:20:45', integrationId: '3', integrationName: '客户管理系统API', requestMethod: 'POST', requestUrl: '/customers/sync', statusCode: 401, duration: 450, status: 'error', errorMessage: '认证失败:无效的API密钥' }, { id: '4', timestamp: '2025-09-15 14:15:30', integrationId: '1', integrationName: '渲染农场API', requestMethod: 'GET', requestUrl: '/render-jobs/12345/status', statusCode: 200, duration: 620, status: 'success' }, { id: '5', timestamp: '2025-09-15 14:10:20', integrationId: '5', integrationName: '项目管理工具API', requestMethod: 'POST', requestUrl: '/webhooks/task-created', statusCode: 200, duration: 380, status: 'success' }, { id: '6', timestamp: '2025-09-15 14:05:15', integrationId: '2', integrationName: '设计素材库API', requestMethod: 'POST', requestUrl: '/assets/upload', statusCode: 201, duration: 2350, status: 'success' }, { id: '7', timestamp: '2025-09-15 14:00:55', integrationId: '3', integrationName: '客户管理系统API', requestMethod: 'GET', requestUrl: '/customers?updatedSince=2025-09-01', statusCode: 401, duration: 320, status: 'error', errorMessage: '认证失败:无效的API密钥' }, { id: '8', timestamp: '2025-09-15 13:55:30', integrationId: '1', integrationName: '渲染农场API', requestMethod: 'PUT', requestUrl: '/render-jobs/12345/cancel', statusCode: 200, duration: 580, status: 'success' } ]; // 生成更多日志数据以模拟大量记录 const generatedLogs: ApiLog[] = []; let idCounter = 9; // 复制模拟数据多次以创建大量日志 for (let i = 0; i < 3; i++) { mockLogs.forEach(log => { // 为每条日志创建一个变体,更改时间戳 const logDate = new Date(log.timestamp); logDate.setHours(logDate.getHours() - i * 2); logDate.setMinutes(Math.floor(Math.random() * 60)); logDate.setSeconds(Math.floor(Math.random() * 60)); generatedLogs.push({ ...log, id: idCounter.toString(), timestamp: logDate.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(/\//g, '-') }); idCounter++; }); } // 合并原始数据和生成的数据 this.apiLogs.set([...mockLogs, ...generatedLogs].sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() )); this.filteredLogs = this.apiLogs; this.applyLogFilters(); } // 标签页切换 switchTab(tab: string): void { this.activeTab = tab; } // API集成筛选方法 applyIntegrationFilters(): void { let result = [...this.apiIntegrations()]; // 搜索词筛选 if (this.integrationSearchTerm) { const term = this.integrationSearchTerm.toLowerCase(); result = result.filter(integration => integration.name.toLowerCase().includes(term) || integration.description.toLowerCase().includes(term) || integration.endpoint.toLowerCase().includes(term) ); } // 类型筛选 if (this.integrationTypeFilter) { result = result.filter(integration => integration.type === this.integrationTypeFilter); } // 状态筛选 if (this.integrationStatusFilter) { result = result.filter(integration => integration.status === this.integrationStatusFilter); } // 排序 result.sort((a, b) => { if (this.integrationSortColumn === 'createdAt' || this.integrationSortColumn === 'updatedAt' || this.integrationSortColumn === 'lastTested') { return this.integrationSortDirection === 'asc' ? new Date(a[this.integrationSortColumn] || 0).getTime() - new Date(b[this.integrationSortColumn] || 0).getTime() : new Date(b[this.integrationSortColumn] || 0).getTime() - new Date(a[this.integrationSortColumn] || 0).getTime(); } else { const valueA = a[this.integrationSortColumn as keyof ApiIntegration]?.toString().toLowerCase() || ''; const valueB = b[this.integrationSortColumn as keyof ApiIntegration]?.toString().toLowerCase() || ''; return this.integrationSortDirection === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA); } }); this.filteredIntegrations.set(result); this.integrationCurrentPage = 0; // 重置到第一页 } // API日志筛选方法 applyLogFilters(): void { let result = [...this.apiLogs()]; // 搜索词筛选 if (this.logSearchTerm) { const term = this.logSearchTerm.toLowerCase(); result = result.filter(log => log.integrationName.toLowerCase().includes(term) || log.requestUrl.toLowerCase().includes(term) || (log.errorMessage && log.errorMessage.toLowerCase().includes(term)) ); } // 集成筛选 if (this.logIntegrationFilter) { result = result.filter(log => log.integrationId === this.logIntegrationFilter); } // 状态筛选 if (this.logStatusFilter) { result = result.filter(log => log.status === this.logStatusFilter); } // 日期范围筛选 if (this.logStartDate) { const startDateTime = new Date(this.logStartDate).setHours(0, 0, 0, 0); result = result.filter(log => new Date(log.timestamp).getTime() >= startDateTime); } if (this.logEndDate) { const endDateTime = new Date(this.logEndDate).setHours(23, 59, 59, 999); result = result.filter(log => new Date(log.timestamp).getTime() <= endDateTime); } // 排序 result.sort((a, b) => { if (this.logSortColumn === 'timestamp') { return this.logSortDirection === 'asc' ? new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime() : new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(); } else if (this.logSortColumn === 'duration' || this.logSortColumn === 'statusCode') { // 安全地获取数字值 const valueA = Number(a[this.logSortColumn as keyof ApiLog]) || 0; const valueB = Number(b[this.logSortColumn as keyof ApiLog]) || 0; return this.logSortDirection === 'asc' ? valueA - valueB : valueB - valueA; } else { const valueA = a[this.logSortColumn as keyof ApiLog]?.toString().toLowerCase() || ''; const valueB = b[this.logSortColumn as keyof ApiLog]?.toString().toLowerCase() || ''; return this.logSortDirection === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA); } }); this.filteredLogs.set(result); this.logCurrentPage = 0; // 重置到第一页 } // 集成相关方法 onIntegrationSearch(): void { this.applyIntegrationFilters(); } onIntegrationFilterChange(): void { this.applyIntegrationFilters(); } onIntegrationSort(column: string): void { if (this.integrationSortColumn === column) { this.integrationSortDirection = this.integrationSortDirection === 'asc' ? 'desc' : 'asc'; } else { this.integrationSortColumn = column; this.integrationSortDirection = 'asc'; } this.applyIntegrationFilters(); } // 日志相关方法 onLogSearch(): void { this.applyLogFilters(); } onLogFilterChange(): void { this.applyLogFilters(); } onLogSort(column: string): void { if (this.logSortColumn === column) { this.logSortDirection = this.logSortDirection === 'asc' ? 'desc' : 'asc'; } else { this.logSortColumn = column; this.logSortDirection = 'asc'; } this.applyLogFilters(); } // 打开API对话框 openApiDialog(integration?: ApiIntegration): void { const dialogRef = this.dialog.open(ApiDialogComponent, { width: '600px', data: integration ? { ...integration } : { id: '', name: '', type: '', endpoint: '', authentication: 'none', description: '', configuration: {}, status: 'inactive', lastTested: '', createdBy: '超级管理员', createdAt: new Date().toLocaleString('zh-CN'), updatedAt: new Date().toLocaleString('zh-CN') } }); dialogRef.afterClosed().subscribe(result => { if (result) { if (result.id) { // 更新集成 this.updateIntegration(result); } else { // 创建新集成 this.createIntegration(result); } } }); } // 集成操作方法 createIntegration(integrationData: Omit): void { const newIntegration: ApiIntegration = { ...integrationData, id: (this.apiIntegrations().length + 1).toString(), createdAt: new Date().toLocaleString('zh-CN'), updatedAt: new Date().toLocaleString('zh-CN') }; this.apiIntegrations.set([newIntegration, ...this.apiIntegrations()]); this.applyIntegrationFilters(); } updateIntegration(updatedIntegration: ApiIntegration): void { this.apiIntegrations.set(this.apiIntegrations().map(integration => integration.id === updatedIntegration.id ? updatedIntegration : integration )); this.applyIntegrationFilters(); } deleteIntegration(id: string): void { if (confirm('确定要删除这个API集成吗?')) { this.apiIntegrations.set(this.apiIntegrations().filter(integration => integration.id !== id)); this.applyIntegrationFilters(); } } toggleIntegrationStatus(id: string, status: 'active' | 'inactive'): void { this.apiIntegrations.set(this.apiIntegrations().map(integration => integration.id === id ? { ...integration, status, updatedAt: new Date().toLocaleString('zh-CN') } : integration )); this.applyIntegrationFilters(); } testIntegration(id: string): void { // 模拟测试操作 alert(`正在测试API集成...\n测试完成!`); this.apiIntegrations.set(this.apiIntegrations().map(integration => integration.id === id ? { ...integration, lastTested: new Date().toLocaleString('zh-CN') } : integration )); this.applyIntegrationFilters(); } // 分页相关方法 get paginatedIntegrations(): ApiIntegration[] { const startIndex = this.integrationCurrentPage * this.integrationPageSize; return this.filteredIntegrations().slice(startIndex, startIndex + this.integrationPageSize); } get totalIntegrationPages(): number { return Math.ceil(this.filteredIntegrations().length / this.integrationPageSize); } onIntegrationPageChange(page: number): void { this.integrationCurrentPage = page; } get paginatedLogs(): ApiLog[] { const startIndex = this.logCurrentPage * this.logPageSize; return this.filteredLogs().slice(startIndex, startIndex + this.logPageSize); } get totalLogPages(): number { return Math.ceil(this.filteredLogs().length / this.logPageSize); } onLogPageChange(page: number): void { this.logCurrentPage = page; } // 格式化日期显示 formatDate(dateString: string): string { const date = new Date(dateString); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); } // 获取状态文本 getStatusText(status: string): string { const statusMap = { 'active': '已激活', 'inactive': '已禁用', 'error': '错误' }; return statusMap[status as keyof typeof statusMap] || status; } // 导出日志 exportLogs(): void { // 模拟导出功能 alert(`已导出 ${this.filteredLogs().length} 条API日志记录`); } // 清除筛选条件 clearIntegrationFilters(): void { this.integrationSearchTerm = ''; this.integrationTypeFilter = ''; this.integrationStatusFilter = ''; this.applyIntegrationFilters(); } clearLogFilters(): void { this.logSearchTerm = ''; this.logIntegrationFilter = ''; this.logStatusFilter = ''; this.logStartDate = null; this.logEndDate = null; this.applyLogFilters(); } // 获取集成ID选项 get integrationIdOptions(): { id: string; name: string }[] { return this.apiIntegrations().map(integration => ({ id: integration.id, name: integration.name })); } // 获取页码数组 getPageNumbers(): number[] { const pages = []; const totalPages = this.totalIntegrationPages; const currentPage = this.integrationCurrentPage; const maxVisiblePages = 5; let startPage = Math.max(0, currentPage - Math.floor(maxVisiblePages / 2)); let endPage = startPage + maxVisiblePages - 1; if (endPage >= totalPages) { endPage = totalPages - 1; startPage = Math.max(0, endPage - maxVisiblePages + 1); } for (let i = startPage; i <= endPage; i++) { pages.push(i); } return pages; } // 计算平均响应时间 calculateAverageDuration(): number { if (this.apiLogs().length === 0) return 0; const totalDuration = this.apiLogs().reduce((sum, log) => sum + log.duration, 0); return Math.round(totalDuration / this.apiLogs().length); } // 封装Math对象的方法 mathMin(a: number, b: number): number { return Math.min(a, b); } // 封装Object对象的方法 objectEntries(obj: Record): [string, any][] { return Object.entries(obj); } // 计算活跃集成数量 get activeIntegrationsCount(): number { return this.apiIntegrations().filter(i => i.status === 'active').length; } // 计算禁用集成数量 get inactiveIntegrationsCount(): number { return this.apiIntegrations().filter(i => i.status === 'inactive').length; } // 计算错误集成数量 get errorIntegrationsCount(): number { return this.apiIntegrations().filter(i => i.status === 'error').length; } // 计算成功日志数量 get successLogsCount(): number { return this.apiLogs().filter(l => l.status === 'success').length; } // 计算失败日志数量 get errorLogsCount(): number { return this.apiLogs().filter(l => l.status === 'error').length; } // 计算总API日志数量 get totalApiLogsCount(): number { return this.apiLogs().length; } // 计算平均响应时间(计算属性版本) get averageResponseTime(): number { return this.calculateAverageDuration(); } }