CadHubManage/websocket-file-api-docs.md

1284 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WebSocket 文件管理API文档
## 概述
通过WebSocket连接实现CAD文件的列表查询和下载功能。支持Creo、PDMS、Revit三种CAD软件的文件格式。
## WebSocket连接
**连接地址**: `ws://localhost:8000/api/v1/ws/connect`
**连接参数**:
- `client_id`: 客户端ID可选不提供会自动生成
- `user_id`: 用户ID可选
**连接示例**:
```javascript
const ws = new WebSocket('ws://localhost:8000/api/v1/ws/connect?user_id=user123');
```
---
## 支持的文件格式
### 📐 Creo 文件
- `.prt` - 零件文件Part
- `.asm` - 装配文件Assembly
- `.drw` - 工程图文件Drawing
- **特别支持版本号后缀**`.prt.1`, `.prt.2`, `.asm.1`
### 🏭 PDMS 文件
- `.rvm` - 3D模型文件
- `.dri` - 图纸文件
### 🏗️ Revit 文件
- `.rvt` - Revit项目文件
- `.rfa` - Revit族文件Family
- `.rte` - Revit模板文件
---
## WebSocket消息格式
### 1. 获取CAD文件列表
**发送消息**:
```json
{
"type": "get_file_list"
}
```
**响应消息**:
```json
{
"type": "info",
"message": "获取文件列表成功",
"data": {
"base_path": "C:\\Users\\Public\\Documents",
"total_count": 15,
"files": [
{
"filename": "part1.prt.1",
"relative_path": "creo/part1.prt.1",
"absolute_path": "C:\\Users\\Public\\Documents\\creo\\part1.prt.1",
"size": 1024000,
"modified_time": 1706950800.0,
"extension": ".prt.1"
},
{
"filename": "building.rvt",
"relative_path": "revit/building.rvt",
"absolute_path": "C:\\Users\\Public\\Documents\\revit\\building.rvt",
"size": 5120000,
"modified_time": 1706951000.0,
"extension": ".rvt"
}
]
},
"timestamp": "2026-02-04T10:30:00"
}
```
---
### 2. 获取单个文件下载链接
**发送消息**:
```json
{
"type": "download_file",
"file_path": "creo/part1.prt.1"
}
```
**响应消息**:
```json
{
"type": "info",
"message": "文件下载链接已生成",
"data": {
"file_path": "creo/part1.prt.1",
"filename": "part1.prt.1",
"download_url": "/api/v1/files/download/creo/part1.prt.1",
"file_size": 1024000
},
"timestamp": "2026-02-04T10:30:00"
}
```
**使用下载链接**:
```javascript
// 获取到download_url后使用HTTP GET请求下载
const downloadUrl = `http://localhost:8000${data.download_url}`;
window.open(downloadUrl, '_blank');
```
---
### 3. 获取批量下载链接
**发送消息**:
```json
{
"type": "download_batch",
"file_paths": [
"creo/part1.prt.1",
"creo/assembly.asm",
"revit/building.rvt"
]
}
```
**响应消息**:
```json
{
"type": "info",
"message": "批量下载链接已生成",
"data": {
"file_count": 3,
"file_paths": [
"creo/part1.prt.1",
"creo/assembly.asm",
"revit/building.rvt"
],
"download_url": "/api/v1/files/download/batch",
"method": "POST",
"note": "请使用POST方法将file_paths作为JSON数组发送到此URL"
},
"timestamp": "2026-02-04T10:30:00"
}
```
**使用批量下载**:
```javascript
// 使用fetch API进行POST请求
const response = await fetch('http://localhost:8000/api/v1/files/download/batch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data.file_paths)
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'cad_files.zip';
a.click();
```
---
## 完整前端示例
### JavaScript/WebSocket
```javascript
class CADFileManager {
constructor(serverUrl = 'ws://localhost:8000/api/v1/ws/connect') {
this.ws = null;
this.serverUrl = serverUrl;
this.httpBaseUrl = 'http://localhost:8000';
}
// 连接WebSocket
connect(userId = 'user123') {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(`${this.serverUrl}?user_id=${userId}`);
this.ws.onopen = () => {
console.log('WebSocket连接成功');
resolve();
};
this.ws.onerror = (error) => {
console.error('WebSocket错误:', error);
reject(error);
};
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
this.handleMessage(message);
};
});
}
// 处理服务器消息
handleMessage(message) {
console.log('收到消息:', message);
if (message.type === 'info' && message.data) {
// 处理不同类型的响应
if (message.data.files) {
this.onFileListReceived(message.data);
} else if (message.data.download_url) {
this.onDownloadUrlReceived(message.data);
}
} else if (message.type === 'error') {
console.error('错误:', message.message);
}
}
// 获取文件列表
getFileList() {
this.ws.send(JSON.stringify({
type: 'get_file_list'
}));
}
// 文件列表回调(可以被覆盖)
onFileListReceived(data) {
console.log('文件列表:', data.files);
console.log('总数:', data.total_count);
}
// 请求单个文件下载
requestDownload(filePath) {
this.ws.send(JSON.stringify({
type: 'download_file',
file_path: filePath
}));
}
// 下载URL回调
onDownloadUrlReceived(data) {
const fullUrl = `${this.httpBaseUrl}${data.download_url}`;
console.log('下载链接:', fullUrl);
// 自动触发下载
window.open(fullUrl, '_blank');
}
// 请求批量下载
async requestBatchDownload(filePaths) {
// 批量下载直接使用HTTP POST
const response = await fetch(`${this.httpBaseUrl}/api/v1/files/download/batch`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(filePaths)
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'cad_files.zip';
a.click();
window.URL.revokeObjectURL(url);
}
// 断开连接
disconnect() {
if (this.ws) {
this.ws.close();
}
}
}
// 使用示例
async function main() {
const manager = new CADFileManager();
// 连接
await manager.connect('user123');
// 自定义文件列表回调
manager.onFileListReceived = (data) => {
console.log(`找到 ${data.total_count} 个文件`);
data.files.forEach(file => {
console.log(`- ${file.filename} (${(file.size / 1024).toFixed(2)} KB)`);
});
};
// 获取文件列表
manager.getFileList();
// 下载单个文件
setTimeout(() => {
manager.requestDownload('creo/part1.prt.1');
}, 2000);
// 批量下载
setTimeout(async () => {
await manager.requestBatchDownload([
'creo/part1.prt.1',
'revit/building.rvt'
]);
}, 4000);
}
main();
```
---
### React示例
```jsx
import React, { useState, useEffect, useRef } from 'react';
function CADFileManager() {
const [files, setFiles] = useState([]);
const [selectedFiles, setSelectedFiles] = useState([]);
const [connected, setConnected] = useState(false);
const wsRef = useRef(null);
useEffect(() => {
// 连接WebSocket
const ws = new WebSocket('ws://localhost:8000/api/v1/ws/connect?user_id=user123');
ws.onopen = () => {
console.log('WebSocket连接成功');
setConnected(true);
// 连接成功后立即获取文件列表
ws.send(JSON.stringify({ type: 'get_file_list' }));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'info' && message.data?.files) {
setFiles(message.data.files);
} else if (message.type === 'info' && message.data?.download_url) {
// 自动打开下载链接
window.open(`http://localhost:8000${message.data.download_url}`, '_blank');
}
};
wsRef.current = ws;
return () => {
ws.close();
};
}, []);
// 刷新文件列表
const refreshFileList = () => {
if (wsRef.current && connected) {
wsRef.current.send(JSON.stringify({ type: 'get_file_list' }));
}
};
// 下载单个文件
const downloadFile = (filePath) => {
if (wsRef.current && connected) {
wsRef.current.send(JSON.stringify({
type: 'download_file',
file_path: filePath
}));
}
};
// 批量下载
const downloadBatch = async () => {
const response = await fetch('http://localhost:8000/api/v1/files/download/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(selectedFiles)
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'cad_files.zip';
a.click();
window.URL.revokeObjectURL(url);
};
// 切换文件选择
const toggleFileSelection = (filePath) => {
setSelectedFiles(prev =>
prev.includes(filePath)
? prev.filter(f => f !== filePath)
: [...prev, filePath]
);
};
return (
<div style={{ padding: '20px' }}>
<h1>CAD文件管理器</h1>
<div style={{ marginBottom: '20px' }}>
<span>连接状态: {connected ? '✅ 已连接' : '❌ 未连接'}</span>
<button onClick={refreshFileList} style={{ marginLeft: '10px' }}>
刷新列表
</button>
<button
onClick={downloadBatch}
disabled={selectedFiles.length === 0}
style={{ marginLeft: '10px' }}
>
批量下载 ({selectedFiles.length})
</button>
</div>
<div>
<h2>文件列表 ( {files.length} )</h2>
<table border="1" cellPadding="8" style={{ width: '100%' }}>
<thead>
<tr>
<th>选择</th>
<th>文件名</th>
<th>路径</th>
<th>大小</th>
<th>扩展名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{files.map(file => (
<tr key={file.absolute_path}>
<td>
<input
type="checkbox"
checked={selectedFiles.includes(file.relative_path)}
onChange={() => toggleFileSelection(file.relative_path)}
/>
</td>
<td>{file.filename}</td>
<td>{file.relative_path}</td>
<td>{(file.size / 1024).toFixed(2)} KB</td>
<td>{file.extension}</td>
<td>
<button onClick={() => downloadFile(file.relative_path)}>
下载
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
export default CADFileManager;
```
---
## 错误处理
**错误响应格式**:
```json
{
"type": "error",
"message": "错误描述",
"timestamp": "2026-02-04T10:30:00"
}
```
**常见错误**:
- `"缺少参数: file_path"` - 未提供文件路径
- `"缺少参数: file_paths (必须是数组)"` - 批量下载参数格式错误
- `"访问被拒绝"` - 文件路径不安全
- `"文件不存在"` - 请求的文件不存在
- `"只能下载CAD文件"` - 尝试下载非CAD格式文件
- `"获取文件列表失败"` - 扫描文件系统失败
---
## 注意事项
1. **WebSocket用于控制HTTP用于下载**
- 文件列表通过WebSocket返回
- 文件下载使用HTTP接口因为WebSocket不适合传输大文件
2. **路径安全**
- 所有文件路径都会进行安全检查
- 只能访问配置目录内的文件
3. **文件格式限制**
- 只能下载Creo、PDMS、Revit格式的文件
- 自动识别带版本号的Creo文件
4. **批量下载**
- 文件打包为ZIP格式
- 保持原有目录结构
- 自动跳过不存在或不安全的文件
5. **配置路径**
- 默认路径:`C:\Users\Public\Documents`
- 可在 `configs/software_config.yaml` 中修改
---
## 文件批量重命名功能
### 4. 获取重命名策略列表
**发送消息**:
```json
{
"type": "get_rename_strategies"
}
```
**响应消息**:
```json
{
"type": "info",
"message": "获取重命名策略成功",
"data": {
"strategies": [
{
"name": "add_prefix",
"description": "在文件名前添加前缀"
},
{
"name": "add_suffix",
"description": "在扩展名前添加后缀"
},
{
"name": "sequence",
"description": "使用序号重命名文件"
},
{
"name": "replace_text",
"description": "替换文件名中的文本"
},
{
"name": "add_datetime",
"description": "添加日期时间戳"
},
{
"name": "change_case",
"description": "转换文件名大小写"
}
],
"total_count": 6
},
"timestamp": "2026-02-04T11:10:00"
}
```
---
### 5. 预览重命名结果
**发送消息**:
```json
{
"type": "preview_rename",
"file_paths": [
"creo/part1.prt.1",
"creo/assembly.asm",
"revit/building.rvt"
],
"strategy": "add_prefix",
"params": {
"prefix": "NEW_"
}
}
```
**响应消息**:
```json
{
"type": "info",
"message": "重命名预览生成成功",
"data": {
"strategy": "add_prefix",
"params": {
"prefix": "NEW_"
},
"preview": [
{
"original": "part1.prt.1",
"new": "NEW_part1.prt.1",
"success": true
},
{
"original": "assembly.asm",
"new": "NEW_assembly.asm",
"success": true
},
{
"original": "building.rvt",
"new": "NEW_building.rvt",
"success": true
}
],
"total_count": 3
},
"timestamp": "2026-02-04T11:10:00"
}
```
---
### 6. 执行批量重命名
**发送消息**:
```json
{
"type": "rename_files",
"file_paths": [
"creo/part1.prt.1",
"creo/assembly.asm"
],
"strategy": "sequence",
"params": {
"base_name": "component",
"start_number": 1,
"digits": 3,
"separator": "_"
}
}
```
**响应消息**:
```json
{
"type": "info",
"message": "批量重命名完成: 成功 2 个, 失败 0 个",
"data": {
"strategy": "sequence",
"params": {
"base_name": "component",
"start_number": 1,
"digits": 3,
"separator": "_"
},
"success_count": 2,
"failed_count": 0,
"results": [
{
"original_path": "creo/part1.prt.1",
"original_name": "part1.prt.1",
"new_name": "component_001.prt.1",
"new_path": "creo/component_001.prt.1",
"success": true
},
{
"original_path": "creo/assembly.asm",
"original_name": "assembly.asm",
"new_name": "component_002.asm",
"new_path": "creo/component_002.asm",
"success": true
}
]
},
"timestamp": "2026-02-04T11:10:00"
}
```
---
## 重命名策略参数说明
### 1. add_prefix添加前缀
```json
{
"strategy": "add_prefix",
"params": {
"prefix": "NEW_"
}
}
```
### 2. add_suffix添加后缀
```json
{
"strategy": "add_suffix",
"params": {
"suffix": "_backup"
}
}
```
### 3. sequence序号重命名
```json
{
"strategy": "sequence",
"params": {
"base_name": "file",
"start_number": 1,
"digits": 3,
"separator": "_"
}
}
```
- `base_name`: 基础文件名
- `start_number`: 起始序号默认1
- `digits`: 序号位数默认3如001
- `separator`: 分隔符(默认下划线)
### 4. replace_text文本替换
```json
{
"strategy": "replace_text",
"params": {
"search": "old",
"replace": "new",
"case_sensitive": true
}
}
```
- `search`: 要搜索的文本
- `replace`: 替换为的文本
- `case_sensitive`: 是否区分大小写默认true
### 5. add_datetime添加日期时间
```json
{
"strategy": "add_datetime",
"params": {
"format": "%Y%m%d_%H%M%S",
"position": "suffix",
"separator": "_"
}
}
```
- `format`: 日期时间格式(默认:`%Y%m%d_%H%M%S`
- `position`: 位置,`prefix`或`suffix`默认suffix
- `separator`: 分隔符(默认下划线)
### 6. change_case大小写转换
```json
{
"strategy": "change_case",
"params": {
"case_type": "lower"
}
}
```
- `case_type`: 转换类型,可选值:`lower`(小写)、`upper`(大写)、`title`(标题格式)
---
## 重命名功能使用示例
### JavaScript示例
```javascript
// 扩展之前的 CADFileManager 类
class CADFileManager {
// ... 之前的代码 ...
// 获取重命名策略列表
getRenameStrategies() {
this.ws.send(JSON.stringify({
type: 'get_rename_strategies'
}));
}
// 预览重命名
previewRename(filePaths, strategy, params) {
this.ws.send(JSON.stringify({
type: 'preview_rename',
file_paths: filePaths,
strategy: strategy,
params: params
}));
}
// 执行批量重命名
renameFiles(filePaths, strategy, params) {
this.ws.send(JSON.stringify({
type: 'rename_files',
file_paths: filePaths,
strategy: strategy,
params: params
}));
}
}
// 使用示例
async function renameExample() {
const manager = new CADFileManager();
await manager.connect('user123');
// 1. 获取策略列表
manager.getRenameStrategies();
// 2. 预览重命名(添加前缀)
setTimeout(() => {
manager.previewRename(
['creo/part1.prt.1', 'creo/assembly.asm'],
'add_prefix',
{ prefix: 'V2_' }
);
}, 1000);
// 3. 执行重命名(序号重命名)
setTimeout(() => {
manager.renameFiles(
['creo/part1.prt.1', 'creo/part2.prt.1'],
'sequence',
{
base_name: 'component',
start_number: 1,
digits: 3,
separator: '_'
}
);
}, 3000);
}
```
### React示例
```jsx
function CADFileRenamer() {
const [files, setFiles] = useState([]);
const [selectedFiles, setSelectedFiles] = useState([]);
const [strategies, setStrategies] = useState([]);
const [selectedStrategy, setSelectedStrategy] = useState('');
const [renameParams, setRenameParams] = useState({});
const [previewResults, setPreviewResults] = useState([]);
const wsRef = useRef(null);
useEffect(() => {
const ws = new WebSocket('ws://localhost:8000/api/v1/ws/connect?user_id=user123');
ws.onopen = () => {
// 获取文件列表和策略列表
ws.send(JSON.stringify({ type: 'get_file_list' }));
ws.send(JSON.stringify({ type: 'get_rename_strategies' }));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'info') {
if (message.data?.files) {
setFiles(message.data.files);
} else if (message.data?.strategies) {
setStrategies(message.data.strategies);
} else if (message.data?.preview) {
setPreviewResults(message.data.preview);
} else if (message.data?.results) {
// 重命名完成,刷新文件列表
ws.send(JSON.stringify({ type: 'get_file_list' }));
setPreviewResults([]);
setSelectedFiles([]);
}
}
};
wsRef.current = ws;
return () => ws.close();
}, []);
// 预览重命名
const handlePreview = () => {
if (wsRef.current && selectedFiles.length > 0 && selectedStrategy) {
wsRef.current.send(JSON.stringify({
type: 'preview_rename',
file_paths: selectedFiles,
strategy: selectedStrategy,
params: renameParams
}));
}
};
// 执行重命名
const handleRename = () => {
if (wsRef.current && selectedFiles.length > 0 && selectedStrategy) {
if (confirm(`确定要重命名 ${selectedFiles.length} 个文件吗?`)) {
wsRef.current.send(JSON.stringify({
type: 'rename_files',
file_paths: selectedFiles,
strategy: selectedStrategy,
params: renameParams
}));
}
}
};
return (
<div style={{ padding: '20px' }}>
<h1>CAD文件批量重命名</h1>
{/* 策略选择 */}
<div style={{ marginBottom: '20px' }}>
<label>重命名策略: </label>
<select
value={selectedStrategy}
onChange={(e) => setSelectedStrategy(e.target.value)}
>
<option value="">请选择策略</option>
{strategies.map(s => (
<option key={s.name} value={s.name}>{s.description}</option>
))}
</select>
</div>
{/* 参数输入(根据策略动态显示) */}
{selectedStrategy === 'add_prefix' && (
<div>
<label>前缀: </label>
<input
type="text"
value={renameParams.prefix || ''}
onChange={(e) => setRenameParams({...renameParams, prefix: e.target.value})}
/>
</div>
)}
{/* 操作按钮 */}
<div style={{ marginBottom: '20px' }}>
<button onClick={handlePreview} disabled={selectedFiles.length === 0}>
预览重命名
</button>
<button onClick={handleRename} disabled={selectedFiles.length === 0} style={{ marginLeft: '10px' }}>
执行重命名
</button>
</div>
{/* 预览结果 */}
{previewResults.length > 0 && (
<div style={{ marginBottom: '20px', padding: '10px', background: '#f0f0f0' }}>
<h3>预览结果</h3>
{previewResults.map((result, idx) => (
<div key={idx}>
{result.original} {result.new}
</div>
))}
</div>
)}
{/* 文件列表 */}
<h2>文件列表</h2>
<table border="1" cellPadding="8">
<thead>
<tr>
<th>选择</th>
<th>文件名</th>
<th>路径</th>
</tr>
</thead>
<tbody>
{files.map(file => (
<tr key={file.absolute_path}>
<td>
<input
type="checkbox"
checked={selectedFiles.includes(file.relative_path)}
onChange={(e) => {
if (e.target.checked) {
setSelectedFiles([...selectedFiles, file.relative_path]);
} else {
setSelectedFiles(selectedFiles.filter(f => f !== file.relative_path));
}
}}
/>
</td>
<td>{file.filename}</td>
<td>{file.relative_path}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
```
---
## 重命名功能注意事项
1. **文件名冲突处理**
- 如果重命名后的文件名已存在,系统会自动添加数字后缀(如 `file_1`, `file_2`
- 最多尝试1000次避免无限循环
2. **扩展名保留**
- 所有重命名策略都会保留原有的文件扩展名
- 支持带版本号的扩展名(如 `.prt.1`, `.prt.2`
3. **预览功能**
- 建议在执行重命名前先使用预览功能
- 预览不会修改实际文件,只返回重命名结果
4. **错误处理**
- 批量重命名时,单个文件失败不会影响其他文件
- 返回结果中会详细说明每个文件的成功/失败状态
5. **安全性**
- 只能重命名配置目录内的CAD文件
- 路径安全检查防止目录遍历攻击
---
## 配置管理功能
### 7. 获取文件配置
**发送消息**:
```json
{
"type": "get_file_config"
}
```
**响应消息**:
```json
{
"type": "info",
"message": "获取文件配置成功",
"data": {
"base_path": "C:\\Users\\Public\\Documents",
"file_extensions": {
"creo": [".prt", ".asm", ".drw"],
"pdms": [".rvm", ".dri"],
"revit": [".rvt", ".rfa", ".rte"]
}
},
"timestamp": "2026-02-04T14:30:00"
}
```
---
### 8. 设置文件基础路径
**发送消息**:
```json
{
"type": "set_base_path",
"base_path": "D:\\CAD_Files"
}
```
**响应消息(成功)**:
```json
{
"type": "info",
"message": "基础路径设置成功",
"data": {
"base_path": "D:\\CAD_Files"
},
"timestamp": "2026-02-04T14:30:00"
}
```
**响应消息(失败)**:
```json
{
"type": "error",
"message": "设置基础路径失败: 路径不存在: D:\\Invalid_Path",
"timestamp": "2026-02-04T14:30:00"
}
```
---
### 9. 设置文件扩展名
**发送消息**:
```json
{
"type": "set_file_extensions",
"file_extensions": {
"creo": [".prt", ".asm", ".drw", ".sec"],
"pdms": [".rvm", ".dri"],
"revit": [".rvt", ".rfa", ".rte"],
"autocad": [".dwg", ".dxf"]
}
}
```
**响应消息(成功)**:
```json
{
"type": "info",
"message": "文件扩展名配置已更新",
"data": {
"file_extensions": {
"creo": [".prt", ".asm", ".drw", ".sec"],
"pdms": [".rvm", ".dri"],
"revit": [".rvt", ".rfa", ".rte"],
"autocad": [".dwg", ".dxf"]
}
},
"timestamp": "2026-02-04T14:30:00"
}
```
**响应消息(失败)**:
```json
{
"type": "error",
"message": "设置文件扩展名失败: 扩展名格式错误: dwg必须以'.'开头",
"timestamp": "2026-02-04T14:30:00"
}
```
---
## 配置管理功能使用示例
### JavaScript示例
```javascript
// 扩展之前的 CADFileManager 类
class CADFileManager {
// ... 之前的代码 ...
// 获取文件配置
getFileConfig() {
this.ws.send(JSON.stringify({
type: 'get_file_config'
}));
}
// 设置基础路径
setBasePath(basePath) {
this.ws.send(JSON.stringify({
type: 'set_base_path',
base_path: basePath
}));
}
// 设置文件扩展名
setFileExtensions(extensions) {
this.ws.send(JSON.stringify({
type: 'set_file_extensions',
file_extensions: extensions
}));
}
}
// 使用示例
async function configExample() {
const manager = new CADFileManager();
await manager.connect('user123');
// 1. 获取当前配置
manager.getFileConfig();
// 2. 修改基础路径
setTimeout(() => {
manager.setBasePath('D:\\CAD_Files');
}, 1000);
// 3. 修改文件扩展名添加AutoCAD支持
setTimeout(() => {
manager.setFileExtensions({
creo: ['.prt', '.asm', '.drw'],
pdms: ['.rvm', '.dri'],
revit: ['.rvt', '.rfa', '.rte'],
autocad: ['.dwg', '.dxf']
});
}, 2000);
}
```
### React示例
```jsx
function CADConfigManager() {
const [basePath, setBasePath] = useState('');
const [fileExtensions, setFileExtensions] = useState({});
const [newBasePath, setNewBasePath] = useState('');
const wsRef = useRef(null);
useEffect(() => {
const ws = new WebSocket('ws://localhost:8000/api/v1/ws/connect?user_id=user123');
ws.onopen = () => {
// 连接成功后获取当前配置
ws.send(JSON.stringify({ type: 'get_file_config' }));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'info' && message.data) {
if (message.data.base_path) {
setBasePath(message.data.base_path);
}
if (message.data.file_extensions) {
setFileExtensions(message.data.file_extensions);
}
}
};
wsRef.current = ws;
return () => ws.close();
}, []);
// 修改基础路径
const handleSetBasePath = () => {
if (wsRef.current && newBasePath) {
wsRef.current.send(JSON.stringify({
type: 'set_base_path',
base_path: newBasePath
}));
}
};
// 修改文件扩展名
const handleSetExtensions = (software, extensions) => {
const newExtensions = {
...fileExtensions,
[software]: extensions
};
if (wsRef.current) {
wsRef.current.send(JSON.stringify({
type: 'set_file_extensions',
file_extensions: newExtensions
}));
}
};
return (
<div style={{ padding: '20px' }}>
<h1>CAD配置管理器</h1>
<div style={{ marginBottom: '20px' }}>
<h2>当前基础路径</h2>
<p>{basePath}</p>
<input
type="text"
placeholder="输入新路径"
value={newBasePath}
onChange={(e) => setNewBasePath(e.target.value)}
/>
<button onClick={handleSetBasePath}>修改路径</button>
</div>
<div>
<h2>当前文件扩展名配置</h2>
<pre>{JSON.stringify(fileExtensions, null, 2)}</pre>
</div>
</div>
);
}
```
---
## 配置管理功能注意事项
1. **路径验证**
- 设置基础路径前会验证路径是否存在
- 路径必须是有效的目录,不能是文件
2. **扩展名格式**
- 所有扩展名必须以`.`开头
- 扩展名配置必须是字典格式,值必须是数组
3. **配置持久化**
- 所有配置修改会立即写入`configs/software_config.yaml`文件
- 配置修改后会立即生效,影响文件列表和下载功能
4. **权限要求**
- 修改配置需要对配置文件有写入权限
- 建议在管理员权限下运行
5. **配置同步**
- 修改配置后,建议重新获取文件列表以查看变更效果
- 多个客户端同时修改配置时,以最后一次修改为准