feat: 添加配置导入功能

将重置参数按钮改为导入配置按钮,并实现TOML文件解析和参数导入功能
This commit is contained in:
dmy
2026-03-02 22:57:13 +08:00
parent 73681f629d
commit 8aa2f600ed

View File

@@ -267,11 +267,11 @@
class="px-8" class="px-8"
/> />
<q-btn <q-btn
color="grey-7" color="orange"
size="lg" size="lg"
label="重置参数" label="导入配置"
icon="refresh" icon="upload"
@click="resetParams" @click="importConfig"
class="px-8" class="px-8"
/> />
<q-btn <q-btn
@@ -284,6 +284,15 @@
/> />
</div> </div>
<!-- 隐藏的文件输入 -->
<input
ref="fileInput"
type="file"
accept=".toml"
style="display: none"
@change="handleFileSelect"
/>
<!-- 错误信息 --> <!-- 错误信息 -->
@@ -355,6 +364,7 @@ const calculating = ref(false)
const result = ref<string | null>(null) const result = ref<string | null>(null)
const error = ref<string | null>(null) const error = ref<string | null>(null)
const logRef = ref<InstanceType<typeof LogComponent> | null>(null) const logRef = ref<InstanceType<typeof LogComponent> | null>(null)
const fileInput = ref<HTMLInputElement | null>(null)
const voltageOptions = [ const voltageOptions = [
'110kV', '220kV', '330kV', '500kV', '750kV','1000kV', '110kV', '220kV', '330kV', '500kV', '750kV','1000kV',
@@ -440,13 +450,6 @@ const calculate = async () => {
} }
} }
// 重置参数
const resetParams = () => {
Object.assign(params, JSON.parse(JSON.stringify(defaultParams)))
result.value = null
error.value = null
}
// 将参数转换为 TOML 格式 // 将参数转换为 TOML 格式
const tomlStringify = (obj: any, indent: string = ''): string => { const tomlStringify = (obj: any, indent: string = ''): string => {
let result = '' let result = ''
@@ -471,6 +474,72 @@ const tomlStringify = (obj: any, indent: string = ''): string => {
return result return result
} }
// 解析 TOML 格式字符串
const parseToml = (tomlStr: string): any => {
const result: any = {}
let currentSection: any = result
let currentSectionName = ''
const lines = tomlStr.split('\n')
for (let line of lines) {
line = line.trim()
// 跳过空行和注释
if (!line || line.startsWith('#')) continue
// 匹配 section [xxx]
const sectionMatch = line.match(/^\[([^\]]+)\]$/)
if (sectionMatch) {
currentSectionName = sectionMatch[1]
currentSection = {}
result[currentSectionName] = currentSection
continue
}
// 匹配 key = value
const kvMatch = line.match(/^([^=]+)=(.*)$/)
if (kvMatch) {
const key = kvMatch[1].trim()
let value: any = kvMatch[2].trim()
// 解析数组 [1, 2, 3]
if (value.startsWith('[') && value.endsWith(']')) {
const arrStr = value.slice(1, -1).trim()
if (arrStr) {
value = arrStr.split(',').map((s: string) => {
s = s.trim()
if (s.startsWith('"') && s.endsWith('"')) {
return s.slice(1, -1)
}
return isNaN(Number(s)) ? s : Number(s)
})
} else {
value = []
}
}
// 解析字符串 "xxx"
else if (value.startsWith('"') && value.endsWith('"')) {
value = value.slice(1, -1)
}
// 解析布尔值
else if (value === 'true') {
value = true
} else if (value === 'false') {
value = false
}
// 解析数字
else if (!isNaN(Number(value))) {
value = Number(value)
}
currentSection[key] = value
}
}
return result
}
// 导出配置 // 导出配置
const exportConfig = async () => { const exportConfig = async () => {
try { try {
@@ -500,6 +569,44 @@ const exportConfig = async () => {
} }
} }
// 导入配置 - 触发文件选择
const importConfig = () => {
fileInput.value?.click()
}
// 处理文件选择
const handleFileSelect = async (event: Event) => {
const input = event.target as HTMLInputElement
const file = input.files?.[0]
if (!file) return
try {
const content = await file.text()
const importedParams = parseToml(content)
// 合并导入的参数到当前参数
if (importedParams.parameter) {
Object.assign(params.parameter, importedParams.parameter)
}
if (importedParams.advance) {
Object.assign(params.advance, importedParams.advance)
}
if (importedParams.optional) {
Object.assign(params.optional, importedParams.optional)
}
logRef.value?.addLog('info', `成功导入配置: ${file.name}`)
result.value = null
error.value = null
} catch (e: any) {
error.value = e.message || '导入失败'
logRef.value?.addLog('error', e.message || '导入失败')
}
// 清空 input 以便可以重复选择同一个文件
input.value = ''
}
// 声明 pywebview API 类型 // 声明 pywebview API 类型
declare global { declare global {
interface Window { interface Window {