123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747 |
- 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
- ],
- 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();
- }
- }
|