feat: 实现Creo模型导出功能并优化API响应处理

- 实现完整的Creo模型导出功能,支持STEP格式
- 新增CreoApi.exportModel方法,支持格式和路径配置
- 完善CreoExportTools页面,包含表单绑定和用户交互
- 优化apiClient响应处理逻辑,优先使用数据中success字段判断
- 修复API错误处理中headers安全访问问题
- 简化导出格式选择,专注核心STP导出需求

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sladro 2025-09-18 15:03:45 +08:00
parent 808f371f84
commit 1c3762d83f
3 changed files with 97 additions and 25 deletions

View File

@ -47,31 +47,21 @@
<div class="export-options">
<div class="option-group">
<label for="export-format">导出格式</label>
<select id="export-format">
<select id="export-format" v-model="exportForm.format" @change="onFormatChange">
<option value="">请选择导出格式</option>
<option value="step">STEP (.stp)</option>
<option value="iges">IGES (.igs)</option>
<option value="stl">STL (.stl)</option>
<option value="pdf">PDF (.pdf)</option>
<option value="dwg">DWG (.dwg)</option>
</select>
</div>
<div class="option-group">
<label for="export-path">导出路径</label>
<div class="input-group">
<input type="text" id="export-path" placeholder=".\model.stp (当前目录)" class="form-input">
<button class="btn btn-outline" id="browse-path-btn">
<i class="fas fa-folder-open"></i>
浏览
</button>
</div>
<small class="form-hint">默认保存到当前目录 (.\filename.ext)点击浏览可选择其他路径</small>
<input type="text" id="export-path" v-model="exportForm.path" placeholder="D:\model.stp" class="form-input">
<small class="form-hint">请输入完整的文件路径包含文件名和.stp扩展名</small>
</div>
</div>
<div class="card-actions">
<button class="btn btn-export btn-lg btn-full" id="start-export-btn" disabled="true">
<button class="btn btn-export btn-lg btn-full" :disabled="!canExport" @click="startExport">
<i class="fas fa-download"></i>
开始导出
</button>
@ -91,7 +81,7 @@
<div class="export-options">
<div class="option-group">
<label>几何类型 (geom_flags)</label>
<select id="creo-geom-flags">
<select id="creo-geom-flags" v-model="exportForm.geomFlags">
<option value="solids">实体 (Solids)</option>
<option value="surfaces">曲面 (Surfaces)</option>
<option value="wireframe">线框 (Wireframe)</option>
@ -102,7 +92,7 @@
<div class="option-group">
<label>
<input type="checkbox" id="creo-advanced-mode">
<input type="checkbox" v-model="exportForm.advancedMode">
启用高级导出模式
</label>
<small class="form-hint">提供更多导出控制选项和优化</small>
@ -110,7 +100,7 @@
<div class="option-group">
<label>
<input type="checkbox" id="creo-export-current" checked="true">
<input type="checkbox" v-model="exportForm.exportCurrent">
导出当前活动文件推荐
</label>
<small class="form-hint">不指定文件名自动导出当前在Creo中打开的文件</small>
@ -157,7 +147,43 @@
</template>
<script setup>
// Creo
import { reactive, computed } from 'vue'
import creoApi from '@/services/creoApi'
//
const exportForm = reactive({
format: '',
path: '',
geomFlags: 'solids',
advancedMode: false,
exportCurrent: true
})
//
const canExport = computed(() => {
return exportForm.format && exportForm.path
})
//
const startExport = async () => {
if (!canExport.value) return
await creoApi.exportModel(
exportForm.format,
exportForm.path,
{
geom_flags: exportForm.geomFlags,
advanced: exportForm.advancedMode
}
)
}
//
const onFormatChange = () => {
if (exportForm.format === 'step' && !exportForm.path) {
exportForm.path = 'D:\\model.stp'
}
}
</script>
<style scoped>

View File

@ -16,7 +16,7 @@ class ApiLogger {
status: response.ok ? 'success' : 'error',
statusCode: response.status,
duration: `${duration}ms`,
responseSize: response.headers.get('content-length') || 'unknown'
responseSize: response.headers?.get('content-length') || 'unknown'
}
// 为将来扩展预留:可以发送到日志服务
@ -151,13 +151,18 @@ class ApiClient {
// 响应拦截器
await this.interceptResponse(response, requestContext, duration)
// 检查响应状态
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
// 先解析响应数据
const data = await this.parseResponse(response)
// 优先检查数据中的success字段
if (data && data.success === false) {
throw new Error(data.error || '操作失败')
}
// 解析响应数据
const data = await this.parseResponse(response)
// 如果数据中没有success字段才检查HTTP状态码
if (data && typeof data.success === 'undefined' && !response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
// 成功后处理
await this.handleSuccess(response, requestContext, data, duration)
@ -219,6 +224,7 @@ class ApiClient {
return await response.text()
}
// 成功处理
async handleSuccess(response, context, data, duration) {
// 记录日志
@ -230,7 +236,12 @@ class ApiClient {
// 错误处理
async handleError(error, context, duration) {
const errorResponse = { ok: false, status: 0, statusText: error.message }
const errorResponse = {
ok: false,
status: 0,
statusText: error.message,
headers: new Map()
}
// 确保隐藏loading动画
this.hideLoading()

View File

@ -190,6 +190,41 @@ class CreoApiService {
}
})
}
/**
* 导出模型到指定格式
* @param {string} formatType - 导出格式类型 (step, iges, stl, pdf, dwg)
* @param {string} exportPath - 导出文件路径
* @param {Object} options - 导出选项
* @param {string} options.geom_flags - 几何类型 (solids, surfaces, wireframe, quilts)
* @param {boolean} options.advanced - 是否启用高级模式
* @returns {Promise<{success: boolean, data?: any, error?: string}>}
*/
async exportModel(formatType, exportPath, options = {}) {
if (!formatType) {
throw new Error('导出格式不能为空')
}
if (!exportPath) {
throw new Error('导出路径不能为空')
}
const url = buildApiUrl(this.softwareName, 'export')
return await apiClient.post(url, {
"software_type": SOFTWARE_TYPE,
"format_type": formatType,
"export_path": exportPath,
"options": {
"geom_flags": options.geom_flags || "solids",
"advanced": options.advanced || false
}
}, {
operationContext: {
software: 'Creo',
operation: `模型导出 - ${formatType.toUpperCase()}`
}
})
}
}
// 导出单例实例