feat: 添加配置文件的导入功能及文件路径显示
新增通过系统对话框导入配置文件的功能 在界面上显示当前打开的配置文件路径 添加对50%击穿电压的验证 优化开发模式下的文件导入备用方案
This commit is contained in:
@@ -2,16 +2,20 @@
|
|||||||
<q-layout view="lHh lpr lFf">
|
<q-layout view="lHh lpr lFf">
|
||||||
<q-header elevated class="bg-indigo-600 text-white">
|
<q-header elevated class="bg-indigo-600 text-white">
|
||||||
<q-toolbar>
|
<q-toolbar>
|
||||||
<q-toolbar-title>
|
<q-toolbar-title class="q-py-sm">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<q-icon name="flash_on" size="md" />
|
<q-icon name="flash_on" size="md" />
|
||||||
<span class="text-xl font-bold">EGM 输电线路绕击跳闸率计算</span>
|
<span class="text-xl font-bold">EGM 输电线路绕击跳闸率计算</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="currentFilePath" class="text-sm truncate max-w-2xl bg-white text-green-700 px-2 py-0.5 rounded mt-1" :title="currentFilePath">
|
||||||
|
{{ currentFilePath }}
|
||||||
|
</div>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
|
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
|
|
||||||
<q-page class="q-pa-md">
|
<q-page class="q-pa-md">
|
||||||
<div class="max-w-4xl mx-auto">
|
<div class="max-w-4xl mx-auto">
|
||||||
<!-- 基本参数 -->
|
<!-- 基本参数 -->
|
||||||
@@ -342,7 +346,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 隐藏的文件输入 -->
|
<!-- 隐藏的文件输入(开发模式备用) -->
|
||||||
<input
|
<input
|
||||||
ref="fileInput"
|
ref="fileInput"
|
||||||
type="file"
|
type="file"
|
||||||
@@ -441,6 +445,8 @@ const error = ref<string | null>(null)
|
|||||||
const logRef = ref<InstanceType<typeof LogComponent> | null>(null)
|
const logRef = ref<InstanceType<typeof LogComponent> | null>(null)
|
||||||
const animationRef = ref<InstanceType<typeof Animation> | null>(null)
|
const animationRef = ref<InstanceType<typeof Animation> | null>(null)
|
||||||
const fileInput = ref<HTMLInputElement | null>(null)
|
const fileInput = ref<HTMLInputElement | null>(null)
|
||||||
|
// 当前打开的文件路径
|
||||||
|
const currentFilePath = ref<string>('')
|
||||||
// 雷电流概率密度系数设置开关
|
// 雷电流概率密度系数设置开关
|
||||||
const showIpCoefficients = ref(false)
|
const showIpCoefficients = ref(false)
|
||||||
// 50%击穿电压设置开关
|
// 50%击穿电压设置开关
|
||||||
@@ -582,6 +588,16 @@ const calculate = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证50%击穿电压
|
||||||
|
if (showU50.value) {
|
||||||
|
const u50 = Number(params.advance.u_50)
|
||||||
|
if (u50 < 1000) {
|
||||||
|
error.value = '请检查参数:"50%击穿电压 U_50"的值应该大于等于 1000 kV'
|
||||||
|
logRef.value?.addLog('error', '请检查参数:"50%击穿电压 U_50"的值应该大于等于 1000 kV')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
calculating.value = true
|
calculating.value = true
|
||||||
result.value = null
|
result.value = null
|
||||||
error.value = null
|
error.value = null
|
||||||
@@ -771,12 +787,44 @@ const exportConfig = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导入配置 - 触发文件选择
|
// 导入配置 - 调用后端文件对话框
|
||||||
const importConfig = () => {
|
const importConfig = async () => {
|
||||||
fileInput.value?.click()
|
try {
|
||||||
|
if (window.pywebview) {
|
||||||
|
const response = await window.pywebview.api.import_config()
|
||||||
|
if (response.success && response.params) {
|
||||||
|
// 合并导入的参数到当前参数
|
||||||
|
if (response.params.parameter) {
|
||||||
|
Object.assign(params.parameter, response.params.parameter)
|
||||||
|
}
|
||||||
|
if (response.params.advance) {
|
||||||
|
Object.assign(params.advance, response.params.advance)
|
||||||
|
}
|
||||||
|
if (response.params.optional) {
|
||||||
|
Object.assign(params.optional, response.params.optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理文件选择
|
// 显示完整文件路径
|
||||||
|
currentFilePath.value = response.file_path || ''
|
||||||
|
|
||||||
|
logRef.value?.addLog('info', `成功导入配置: ${response.file_path}`)
|
||||||
|
result.value = null
|
||||||
|
error.value = null
|
||||||
|
} else if (!response.success && response.message !== '用户取消了选择') {
|
||||||
|
error.value = response.message || '导入失败'
|
||||||
|
logRef.value?.addLog('error', response.message || '导入失败')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 开发模式下使用 HTML 文件输入
|
||||||
|
fileInput.value?.click()
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
error.value = e.message || '导入失败'
|
||||||
|
logRef.value?.addLog('error', e.message || '导入失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理文件选择(开发模式备用)
|
||||||
const handleFileSelect = async (event: Event) => {
|
const handleFileSelect = async (event: Event) => {
|
||||||
const input = event.target as HTMLInputElement
|
const input = event.target as HTMLInputElement
|
||||||
const file = input.files?.[0]
|
const file = input.files?.[0]
|
||||||
@@ -797,6 +845,8 @@ const handleFileSelect = async (event: Event) => {
|
|||||||
Object.assign(params.optional, importedParams.optional)
|
Object.assign(params.optional, importedParams.optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentFilePath.value = file.name
|
||||||
|
|
||||||
logRef.value?.addLog('info', `成功导入配置: ${file.name}`)
|
logRef.value?.addLog('info', `成功导入配置: ${file.name}`)
|
||||||
result.value = null
|
result.value = null
|
||||||
error.value = null
|
error.value = null
|
||||||
@@ -815,6 +865,7 @@ declare global {
|
|||||||
pywebview?: {
|
pywebview?: {
|
||||||
api: {
|
api: {
|
||||||
calculate: (params: AllParameters) => Promise<any>
|
calculate: (params: AllParameters) => Promise<any>
|
||||||
|
import_config: () => Promise<any>
|
||||||
export_config: (params: AllParameters) => Promise<any>
|
export_config: (params: AllParameters) => Promise<any>
|
||||||
export_log: (logText: string) => Promise<any>
|
export_log: (logText: string) => Promise<any>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import json
|
|||||||
import math
|
import math
|
||||||
import threading
|
import threading
|
||||||
import queue
|
import queue
|
||||||
|
import tomllib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, List
|
from typing import Dict, Any, List
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -524,6 +525,46 @@ class EGMWebApp:
|
|||||||
"message": f"保存失败: {str(e)}"
|
"message": f"保存失败: {str(e)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def import_config(self) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
导入配置从 TOML 文件,弹出打开对话框
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含解析后的参数和文件路径的字典
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 打开文件选择对话框
|
||||||
|
result = self.window.create_file_dialog(
|
||||||
|
webview.OPEN_DIALOG,
|
||||||
|
directory='',
|
||||||
|
file_types=('TOML Files (*.toml)', 'All files (*.*)')
|
||||||
|
)
|
||||||
|
|
||||||
|
if result and len(result) > 0:
|
||||||
|
file_path = result[0]
|
||||||
|
|
||||||
|
# 读取并解析 TOML 文件
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
toml_data = tomllib.load(f)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": f"成功导入配置",
|
||||||
|
"file_path": file_path,
|
||||||
|
"params": toml_data
|
||||||
|
}
|
||||||
|
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]:
|
def get_default_config(self) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
获取默认配置
|
获取默认配置
|
||||||
|
|||||||
Reference in New Issue
Block a user