diff --git a/webui/src/components/Log.vue b/webui/src/components/Log.vue
index e8260c0..cbe3878 100644
--- a/webui/src/components/Log.vue
+++ b/webui/src/components/Log.vue
@@ -67,11 +67,17 @@ const clearLog = () => {
logs.value = []
}
+// 获取日志文本
+const getLogsText = (): string => {
+ return logs.value.map(log => `[${log.time}] [${log.level.toUpperCase()}] ${log.message}`).join('\n')
+}
+
// 暴露方法给父组件
defineExpose({
addLog,
clearLog,
- lastTripRates
+ lastTripRates,
+ getLogsText
})
diff --git a/webui/src/components/ParameterForm.vue b/webui/src/components/ParameterForm.vue
index c8d28b6..561c271 100644
--- a/webui/src/components/ParameterForm.vue
+++ b/webui/src/components/ParameterForm.vue
@@ -287,6 +287,14 @@
@click="exportConfig"
class="px-8"
/>
+
@@ -585,6 +593,40 @@ const parseToml = (tomlStr: string): any => {
return result
}
+// 导出日志
+const exportLog = async () => {
+ try {
+ const logText = logRef.value?.getLogsText() || ''
+ if (!logText) {
+ logRef.value?.addLog('warning', '暂无日志可导出')
+ return
+ }
+
+ if (window.pywebview) {
+ const response = await window.pywebview.api.export_log(logText)
+ if (response.success) {
+ logRef.value?.addLog('info', response.message)
+ } else {
+ logRef.value?.addLog('warning', response.message)
+ }
+ } else {
+ // 开发模式下的模拟
+ logRef.value?.addLog('info', '导出日志(开发模式,直接下载)')
+ const blob = new Blob([logText], { type: 'text/plain' })
+ const url = URL.createObjectURL(blob)
+ const a = document.createElement('a')
+ a.href = url
+ const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, '')
+ a.download = `egm_log_${timestamp}.txt`
+ a.click()
+ URL.revokeObjectURL(url)
+ }
+ } catch (e: any) {
+ error.value = e.message || '导出日志失败'
+ logRef.value?.addLog('error', e.message || '导出日志失败')
+ }
+}
+
// 导出配置
const exportConfig = async () => {
try {
@@ -659,6 +701,7 @@ declare global {
api: {
calculate: (params: AllParameters) => Promise
export_config: (params: AllParameters) => Promise
+ export_log: (logText: string) => Promise
}
}
addLogFromBackend?: (log: { level: string; time: string; message: string }) => void
diff --git a/webview_app.py b/webview_app.py
index 3267d03..c76ae51 100644
--- a/webview_app.py
+++ b/webview_app.py
@@ -348,6 +348,53 @@ class EGMWebApp:
"message": f"保存失败: {str(e)}"
}
+ def export_log(self, log_text: str) -> Dict[str, Any]:
+ """
+ 导出日志为 TXT 文件,弹出保存对话框
+
+ Args:
+ log_text: 日志文本内容
+
+ Returns:
+ 包含保存状态和路径的字典
+ """
+ try:
+ # 生成默认文件名
+ timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
+ default_filename = f'egm_log_{timestamp}.txt'
+
+ # 打开保存文件对话框
+ result = self.window.create_file_dialog(
+ webview.SAVE_DIALOG,
+ directory='',
+ save_filename=default_filename,
+ file_types=('Text Files (*.txt)', 'All files (*.*)')
+ )
+
+ if result and len(result) > 0:
+ file_path = result[0]
+
+ # 写入文件
+ with open(file_path, 'w', encoding='utf-8') as f:
+ f.write(log_text)
+
+ return {
+ "success": True,
+ "message": f"日志已保存到: {file_path}",
+ "file_path": file_path
+ }
+ else:
+ return {
+ "success": False,
+ "message": "用户取消了保存操作"
+ }
+ except Exception as e:
+ logger.error(f"导出日志失败: {str(e)}")
+ return {
+ "success": False,
+ "message": f"保存失败: {str(e)}"
+ }
+
def get_default_config(self) -> Dict[str, Any]:
"""
获取默认配置