CadHubManage/frontend-api-docs.md
root 664181ec6b feat: 集成AVEVA PDMS 12.1 SP4支持
- 添加PDMS软件配置,支持批处理文件启动方式
- 配置executable_path为pdms.bat,startup_args为["Design", "noconsole"]
- 通过进程检测工具确定正确的进程名称:des.exe和PDMSConsole.exe
- 新增check_pdms_processes.py进程检测工具,可自动识别PDMS进程
- 更新Readme.md和frontend-api-docs.md文档
- 支持与Creo、Revit一致的启动、停止、重启功能

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-01 21:14:32 +08:00

23 KiB
Raw Blame History

CadHubManage 前端API文档

项目概述

CadHubManage是一个通过WebSocket实时控制Windows服务器上软件的管理系统提供软件启动、停止、状态监控和操作日志记录功能。

基础信息

  • API版本: v1.0.0
  • WebSocket URL: ws://localhost:8000/api/v1/ws/connect
  • 协议: WebSocket
  • 数据格式: JSON

快速开始

1. 健康检查HTTP接口

GET /health

响应:

{
    "status": "healthy"
}

2. 服务信息HTTP接口

GET /

响应:

{
    "message": "CadHubManage API服务正在运行",
    "version": "1.0.0", 
    "docs": "/docs"
}

3. 连接WebSocket

const ws = new WebSocket('ws://localhost:8000/api/v1/ws/connect?client_id=web_client&user_id=admin');

WebSocket实时通信API

连接WebSocket

ws://localhost:8000/api/v1/ws/connect?client_id=client123&user_id=user456

连接参数:

  • client_id: 客户端唯一标识符 (可选,自动生成)
  • user_id: 用户ID (可选)

WebSocket消息格式

发送消息类型

1. 心跳检测

{
    "type": "ping"  // 必填:固定值
}

参数说明:

  • type (必填string): 固定值 "ping"

2. 获取服务状态

{
    "type": "get_status"  // 必填:固定值
}

参数说明:

  • type (必填string): 固定值 "get_status"

3. 获取软件列表

{
    "type": "get_software_list"  // 必填:固定值
}

参数说明:

  • type (必填string): 固定值 "get_software_list"

4. 启动软件

{
    "type": "start_software",      // 必填:固定值
    "software_id": "creo"          // 必填:软件标识符
}

参数说明:

  • type (必填string): 固定值 "start_software"
  • software_id (必填string): 软件标识符长度1-50字符只能包含字母、数字、下划线

5. 停止软件

{
    "type": "stop_software",       // 必填:固定值
    "software_id": "creo"          // 必填:软件标识符
}

参数说明:

  • type (必填string): 固定值 "stop_software"
  • software_id (必填string): 软件标识符长度1-50字符只能包含字母、数字、下划线

6. 重启软件

{
    "type": "restart_software",    // 必填:固定值
    "software_id": "creo"          // 必填:软件标识符
}

参数说明:

  • type (必填string): 固定值 "restart_software"
  • software_id (必填string): 软件标识符长度1-50字符只能包含字母、数字、下划线

6. 记录操作日志

{
    "type": "log_operation",           // 必填:固定值
    "operation": "手动启动软件",       // 必填:操作名称
    "details": "用户通过界面启动Creo", // 可选:详细描述
    "action_type": "software_control", // 可选:行为类型
    "target_object": "creo",           // 可选:目标对象
    "status": "success",               // 可选:操作状态
    "duration": 5.2,                   // 可选:操作耗时(秒)
    "operation_category": "软件控制"    // 可选:操作分类
}

参数说明:

  • type (必填string): 固定值 "log_operation"
  • operation (必填string): 操作名称长度1-100字符
  • details (可选string): 详细描述最大1000字符
  • action_type (可选string): 行为类型,可选值: create, read, update, delete, execute, export, import
  • target_object (可选string): 目标对象最大50字符
  • status (可选string): 操作状态,可选值: success, failed, pending默认success
  • duration (可选number): 操作耗时单位秒范围0-3600
  • operation_category (可选string): 操作分类最大50字符

7. 查询操作日志

{
    "type": "query_logs",                    // 必填:固定值
    "log_type": "user_operation",           // 可选:日志类型
    "operation": "启动软件",                // 可选:操作名称
    "user_id_filter": "user123",            // 可选用户ID过滤
    "level": "info",                        // 可选:日志级别
    "start_time": "2024-01-01T00:00:00Z",   // 可选:开始时间
    "end_time": "2024-01-02T00:00:00Z",     // 可选:结束时间
    "limit": 100,                           // 可选:返回数量限制
    "offset": 0                             // 可选:偏移量
}

参数说明:

  • type (必填string): 固定值 "query_logs"
  • log_type (可选string): 日志类型,可选值: system_operation, user_operation
  • operation (可选string): 操作名称,支持模糊匹配
  • user_id_filter (可选string): 用户ID过滤最大50字符
  • level (可选string): 日志级别,可选值: debug, info, warning, error
  • start_time (可选string): 开始时间ISO 8601格式 (YYYY-MM-DDTHH:mm:ssZ)
  • end_time (可选string): 结束时间ISO 8601格式 (YYYY-MM-DDTHH:mm:ssZ)
  • limit (可选number): 返回数量限制范围1-1000默认100
  • offset (可选number): 偏移量最小0默认0

8. 根据ID获取日志

{
    "type": "get_log_by_id",  // 必填:固定值
    "log_id": "log_123"       // 必填日志ID
}

参数说明:

  • type (必填string): 固定值 "get_log_by_id"
  • log_id (必填string): 日志唯一标识符长度1-100字符

9. 获取日志统计信息

{
    "type": "get_log_stats"  // 必填:固定值
}

参数说明:

  • type (必填string): 固定值 "get_log_stats"

10. 清理过期日志

{
    "type": "cleanup_logs"  // 必填:固定值
}

参数说明:

  • type (必填string): 固定值 "cleanup_logs"

11. 获取操作类型列表

{
    "type": "get_operation_types"  // 必填:固定值
}

参数说明:

  • type (必填string): 固定值 "get_operation_types"

接收消息类型

1. 欢迎消息

{
    "type": "info",
    "message": "欢迎连接客户端ID: client123",
    "client_id": "client123",
    "user_id": "user456",
    "timestamp": "2024-01-01T10:00:00Z"
}

2. 心跳响应

{
    "type": "heartbeat",
    "message": "pong",
    "timestamp": "2024-01-01T10:00:00Z"
}

3. 服务状态响应

{
    "type": "info",
    "message": "服务状态正常",
    "data": {
        "active_connections": 3,
        "connected_users": ["user123", "user456"]
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

4. 软件列表更新

{
    "type": "software_list_update",
    "data": {
        "software_list": [
            {
                "id": "creo",
                "name": "PTC Creo",
                "status": "running",
                "executable_path": "C:\\Program Files\\PTC\\Creo 5.0.0.0\\Parametric\\bin\\parametric.exe"
            }
        ]
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

5. 任务创建响应

{
    "type": "info",
    "message": "软件 creo 启动任务已创建",
    "data": {
        "task_id": "task_123",
        "software_id": "creo",
        "status": "pending"
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

6. 日志记录确认

{
    "type": "log_recorded",
    "message": "操作日志已记录",
    "data": {
        "log_id": "log_456",
        "operation": "手动启动软件"
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

7. 日志查询响应

{
    "type": "info",
    "message": "日志查询成功",
    "data": {
        "logs": [
            {
                "id": "log_123",
                "operation": "启动软件",
                "user_id": "user123",
                "timestamp": "2024-01-01T10:00:00Z",
                "level": "info",
                "details": "启动PTC Creo成功"
            }
        ],
        "total": 1,
        "limit": 100,
        "offset": 0
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

8. 日志统计响应

{
    "type": "info",
    "message": "获取统计信息成功",
    "data": {
        "stats": {
            "period": "24小时",
            "system_operations": 45,
            "user_operations": 123,
            "error_logs": 2,
            "total_logs": 168,
            "timestamp": "2024-01-01T10:00:00Z"
        }
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

9. 操作类型列表响应

{
    "type": "info",
    "message": "获取操作类型成功",
    "data": {
        "operations": ["启动软件", "停止软件", "重启软件"],
        "categories": ["软件控制", "系统管理"],
        "total_operations": 3,
        "total_categories": 2
    },
    "timestamp": "2024-01-01T10:00:00Z"
}

10. 错误消息

{
    "type": "error",
    "message": "启动软件失败: 软件路径不存在",
    "timestamp": "2024-01-01T10:00:00Z"
}

数据模型

软件配置

当前支持的软件(位于configs/software_config.yaml

software:
  creo:
    name: "PTC Creo"
    executable_path: "C:\\Program Files\\PTC\\Creo 5.0.0.0\\Parametric\\bin\\parametric.exe"
    startup_args: []
    startup_timeout: 60
    check_process_name: ["xtop.exe", "pro_comm_msg.exe"]  # 支持多进程检测
    stop_timeout: 15  # 停止超时时间(秒)
    
  revit:
    name: "Autodesk Revit 2017"
    executable_path: "C:\\Program Files\\Autodesk\\Revit 2017\\Revit.exe"
    startup_args: ["/language", "CHS"]
    startup_timeout: 90
    check_process_name: "Revit.exe"  # 单进程检测
    
  pdms:
    name: "AVEVA PDMS 12.1 SP4"
    executable_path: "C:\\AVEVA\\Plant\\PDMS12.1.SP4\\pdms.bat"  # 支持批处理文件
    startup_args: ["Design", "noconsole"]
    startup_timeout: 120
    check_process_name: ["des.exe", "PDMSConsole.exe"]  # PDMS多进程检测
    stop_timeout: 20

配置字段说明:

  • name: 软件显示名称
  • executable_path: 软件可执行文件完整路径
  • startup_args: 启动参数数组
  • startup_timeout: 启动超时时间(秒)
  • check_process_name: 进程检测名称,支持字符串(单进程)或数组(多进程)
  • stop_timeout: 停止操作超时时间(秒),可选

日志类型枚举

  • LogType: system_operation, user_operation
  • LogLevel: debug, info, warning, error
  • ActionType: create, read, update, delete, execute, export, import
  • OperationStatus: success, failed, pending

错误处理

HTTP错误码

  • 200: 成功
  • 404: 资源不存在
  • 500: 服务器内部错误

WebSocket错误

错误消息统一格式:

{
    "type": "error",
    "message": "错误描述",
    "timestamp": "2024-01-01T10:00:00Z"
}

使用示例

JavaScript WebSocket客户端示例

// 连接WebSocket
const ws = new WebSocket('ws://localhost:8000/api/v1/ws/connect?client_id=web_client&user_id=admin');

// 连接成功
ws.onopen = function() {
    console.log('WebSocket连接成功');
    
    // 发送心跳
    ws.send(JSON.stringify({type: 'ping'}));
};

// 接收消息
ws.onmessage = function(event) {
    const message = JSON.parse(event.data);
    console.log('收到消息:', message);
    
    switch(message.type) {
        case 'heartbeat':
            console.log('心跳响应');
            break;
        case 'software_list_update':
            console.log('软件列表:', message.data.software_list);
            break;
        case 'info':
            if (message.data && message.data.logs) {
                console.log('日志查询结果:', message.data.logs);
            } else if (message.data && message.data.stats) {
                console.log('统计信息:', message.data.stats);
            }
            break;
        case 'error':
            console.error('错误:', message.message);
            break;
    }
};

// 启动软件
function startSoftware(softwareId) {
    ws.send(JSON.stringify({
        type: 'start_software',
        software_id: softwareId
    }));
}

// 停止软件
function stopSoftware(softwareId) {
    ws.send(JSON.stringify({
        type: 'stop_software',
        software_id: softwareId
    }));
}

// 重启软件
function restartSoftware(softwareId) {
    ws.send(JSON.stringify({
        type: 'restart_software',
        software_id: softwareId
    }));
}

// 记录操作日志
function logOperation(operation, details) {
    ws.send(JSON.stringify({
        type: 'log_operation',
        operation: operation,
        details: details,
        status: 'success'
    }));
}

// 查询日志
function queryLogs(filters = {}) {
    ws.send(JSON.stringify({
        type: 'query_logs',
        ...filters
    }));
}

// 获取日志统计
function getLogStats() {
    ws.send(JSON.stringify({
        type: 'get_log_stats'
    }));
}

// 获取操作类型列表
function getOperationTypes() {
    ws.send(JSON.stringify({
        type: 'get_operation_types'
    }));
}

// 清理过期日志
function cleanupLogs() {
    ws.send(JSON.stringify({
        type: 'cleanup_logs'
    }));
}

// 使用示例
setTimeout(() => {
    // 查询最近的用户操作日志
    queryLogs({
        log_type: 'user_operation',
        limit: 50,
        offset: 0
    });
    
    // 获取统计信息
    getLogStats();
    
    // 获取操作类型
    getOperationTypes();
}, 1000);

WebSocket连接管理指南

连接状态管理

WebSocket连接具有多种状态前端需要正确处理这些状态转换

class WebSocketManager {
    constructor(url, options = {}) {
        this.url = url;
        this.ws = null;
        this.connectionState = 'DISCONNECTED'; // CONNECTING, CONNECTED, DISCONNECTED, ERROR
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
        this.reconnectDelay = options.reconnectDelay || 1000;
        this.heartbeatInterval = options.heartbeatInterval || 30000;
        this.heartbeatTimer = null;
        
        // 事件监听器
        this.listeners = {
            onOpen: [],
            onMessage: [],
            onClose: [],
            onError: [],
            onStateChange: []
        };
    }
    
    // 连接WebSocket
    connect() {
        if (this.connectionState === 'CONNECTING' || this.connectionState === 'CONNECTED') {
            return;
        }
        
        this.setState('CONNECTING');
        this.ws = new WebSocket(this.url);
        
        this.ws.onopen = (event) => {
            this.setState('CONNECTED');
            this.reconnectAttempts = 0;
            this.startHeartbeat();
            this.emit('onOpen', event);
        };
        
        this.ws.onmessage = (event) => {
            const message = JSON.parse(event.data);
            this.emit('onMessage', message);
        };
        
        this.ws.onclose = (event) => {
            this.setState('DISCONNECTED');
            this.stopHeartbeat();
            this.emit('onClose', event);
            
            // 自动重连
            if (!event.wasClean && this.reconnectAttempts < this.maxReconnectAttempts) {
                setTimeout(() => {
                    this.reconnectAttempts++;
                    this.connect();
                }, this.reconnectDelay * Math.pow(2, this.reconnectAttempts)); // 指数退避
            }
        };
        
        this.ws.onerror = (event) => {
            this.setState('ERROR');
            this.emit('onError', event);
        };
    }
    
    // 断开连接
    disconnect() {
        if (this.ws) {
            this.ws.close(1000, 'Client disconnect');
            this.ws = null;
        }
        this.stopHeartbeat();
        this.setState('DISCONNECTED');
    }
    
    // 发送消息
    send(message) {
        if (this.connectionState === 'CONNECTED' && this.ws) {
            this.ws.send(JSON.stringify(message));
            return true;
        }
        return false;
    }
    
    // 心跳检测
    startHeartbeat() {
        this.heartbeatTimer = setInterval(() => {
            if (this.connectionState === 'CONNECTED') {
                this.send({ type: 'ping' });
            }
        }, this.heartbeatInterval);
    }
    
    stopHeartbeat() {
        if (this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer);
            this.heartbeatTimer = null;
        }
    }
    
    // 状态管理
    setState(newState) {
        if (this.connectionState !== newState) {
            const oldState = this.connectionState;
            this.connectionState = newState;
            this.emit('onStateChange', { oldState, newState });
        }
    }
    
    // 事件系统
    on(event, callback) {
        if (this.listeners[event]) {
            this.listeners[event].push(callback);
        }
    }
    
    off(event, callback) {
        if (this.listeners[event]) {
            const index = this.listeners[event].indexOf(callback);
            if (index > -1) {
                this.listeners[event].splice(index, 1);
            }
        }
    }
    
    emit(event, data) {
        if (this.listeners[event]) {
            this.listeners[event].forEach(callback => callback(data));
        }
    }
}

使用示例

// 创建WebSocket管理器
const wsManager = new WebSocketManager(
    'ws://localhost:8000/api/v1/ws/connect?client_id=web_client&user_id=admin',
    {
        maxReconnectAttempts: 5,
        reconnectDelay: 1000,
        heartbeatInterval: 30000
    }
);

// 监听连接状态变化
wsManager.on('onStateChange', ({ oldState, newState }) => {
    console.log(`连接状态变化: ${oldState} -> ${newState}`);
    updateUI(newState);
});

// 监听消息
wsManager.on('onMessage', (message) => {
    handleMessage(message);
});

// 监听错误
wsManager.on('onError', (error) => {
    console.error('WebSocket错误:', error);
    showErrorNotification('连接出现错误,正在尝试重连...');
});

// 连接
wsManager.connect();

// 发送消息(带重试)
function sendMessageWithRetry(message, maxRetries = 3) {
    let retries = 0;
    
    function attemptSend() {
        if (wsManager.send(message)) {
            return true;
        }
        
        if (retries < maxRetries && wsManager.connectionState !== 'CONNECTED') {
            retries++;
            setTimeout(attemptSend, 1000);
        } else {
            console.error('发送消息失败:', message);
            return false;
        }
    }
    
    return attemptSend();
}

错误处理完整指南

错误分类和处理策略

1. 连接错误

网络连接失败

// 错误场景:网络不可达、服务器关闭
wsManager.on('onError', (event) => {
    if (event.code === 1006) { // 异常关闭
        showNotification('网络连接中断,正在尝试重连...', 'warning');
        // 自动重连逻辑已在管理器中处理
    }
});

认证失败

// 错误场景client_id或user_id无效
wsManager.on('onMessage', (message) => {
    if (message.type === 'error' && message.message.includes('认证')) {
        showNotification('认证失败,请重新登录', 'error');
        redirectToLogin();
    }
});

2. 业务错误

软件操作错误

// 错误响应示例
{
    "type": "error",
    "message": "启动软件失败: 软件路径不存在",
    "error_code": "SOFTWARE_NOT_FOUND",
    "timestamp": "2024-01-01T10:00:00Z"
}

// 处理方式
function handleSoftwareError(message) {
    const errorHandlers = {
        'SOFTWARE_NOT_FOUND': () => {
            showNotification('软件未找到,请检查软件配置', 'error');
            // 可以引导用户到配置页面
        },
        'SOFTWARE_ALREADY_RUNNING': () => {
            showNotification('软件已在运行中', 'info');
            // 更新软件状态显示
        },
        'INSUFFICIENT_PERMISSIONS': () => {
            showNotification('权限不足,无法执行操作', 'error');
            // 可能需要提升权限
        }
    };
    
    const handler = errorHandlers[message.error_code];
    if (handler) {
        handler();
    } else {
        showNotification(message.message, 'error');
    }
}

参数验证错误

// 前端参数验证
function validateLogOperation(params) {
    const errors = [];
    
    if (!params.operation || params.operation.length === 0) {
        errors.push('operation字段不能为空');
    }
    if (params.operation && params.operation.length > 100) {
        errors.push('operation字段长度不能超过100字符');
    }
    if (params.details && params.details.length > 1000) {
        errors.push('details字段长度不能超过1000字符');
    }
    if (params.duration && (params.duration < 0 || params.duration > 3600)) {
        errors.push('duration字段值必须在0-3600范围内');
    }
    
    return errors;
}

// 使用示例
function logUserOperation(params) {
    const errors = validateLogOperation(params);
    if (errors.length > 0) {
        showNotification(`参数错误: ${errors.join(', ')}`, 'error');
        return;
    }
    
    wsManager.send({
        type: 'log_operation',
        ...params
    });
}

3. 常见错误代码表

错误代码 描述 处理建议
INVALID_MESSAGE_FORMAT 消息格式错误 检查JSON格式重新发送
UNKNOWN_MESSAGE_TYPE 未知消息类型 检查type字段值
MISSING_REQUIRED_PARAMETER 缺少必填参数 补充必填参数
SOFTWARE_NOT_FOUND 软件未找到 检查software_id更新软件配置
SOFTWARE_ALREADY_RUNNING 软件已运行 更新UI状态无需重复启动
PERMISSION_DENIED 权限不足 联系管理员或重新认证
OPERATION_TIMEOUT 操作超时 检查网络连接,重试操作
SERVER_INTERNAL_ERROR 服务器内部错误 稍后重试,联系技术支持

开发注意事项

  1. 纯WebSocket架构: 所有功能通过WebSocket实现提供实时双向通信
  2. CORS已配置: 允许所有来源,生产环境需要修改
  3. 连接管理: 实现完整的连接状态管理和自动重连机制
  4. 参数验证: 前端应进行客户端验证,提升用户体验
  5. 错误处理: 提供统一的错误响应格式和处理策略
  6. 心跳检测: 定期发送ping消息保持连接活跃
  7. 消息格式: 所有WebSocket消息采用统一JSON格式
  8. 重连策略: 使用指数退避算法避免服务器压力

联系与支持

如有问题请参考项目代码或联系开发团队。


文档版本: 1.0.0
最后更新: 2024-01-01