|
@@ -0,0 +1,748 @@
|
|
|
+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<string, any>;
|
|
|
+ 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,
|
|
|
+ ApiDialogComponent
|
|
|
+ ],
|
|
|
+ templateUrl: './api-integrations.html',
|
|
|
+ styleUrl: './api-integrations.scss'
|
|
|
+})
|
|
|
+export class ApiIntegrations implements OnInit {
|
|
|
+ // 激活的标签页
|
|
|
+ activeTab = 'integrations';
|
|
|
+
|
|
|
+ // API集成数据
|
|
|
+ apiIntegrations = signal<ApiIntegration[]>([]);
|
|
|
+ filteredIntegrations = signal<ApiIntegration[]>([]);
|
|
|
+ integrationSearchTerm = '';
|
|
|
+ integrationTypeFilter = '';
|
|
|
+ integrationStatusFilter = '';
|
|
|
+ integrationSortColumn = 'createdAt';
|
|
|
+ integrationSortDirection = 'desc';
|
|
|
+ integrationPageSize = 10;
|
|
|
+ integrationCurrentPage = 0;
|
|
|
+
|
|
|
+ // API日志数据
|
|
|
+ apiLogs = signal<ApiLog[]>([]);
|
|
|
+ filteredLogs = signal<ApiLog[]>([]);
|
|
|
+ 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<string, string> = {
|
|
|
+ 'active': '#00B42A',
|
|
|
+ 'inactive': '#F53F3F',
|
|
|
+ 'error': '#FFAA00'
|
|
|
+ };
|
|
|
+
|
|
|
+ // 状态图标映射
|
|
|
+ statusIcons: Record<string, string> = {
|
|
|
+ '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<ApiIntegration, 'id'>): 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>): [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();
|
|
|
+ }
|
|
|
+}
|