Compare commits
10 Commits
18fc8fcb0e
...
36139d4ab5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36139d4ab5 | ||
|
|
6471c066df | ||
|
|
3465cda361 | ||
|
|
aed5c5e3cb | ||
|
|
d5a9bb8798 | ||
|
|
e4da22868d | ||
|
|
568d7d3ef6 | ||
|
|
9d69b1bad2 | ||
|
|
d1baa87ae4 | ||
|
|
195beb3520 |
15
main.py
15
main.py
@@ -151,19 +151,20 @@ def run_egm(para: Parameter, animation=None) -> dict:
|
||||
* 180
|
||||
/ math.pi
|
||||
)
|
||||
logger.info(f"地线保护角{shield_angle_at_avg_height:.2f}°")
|
||||
logger.info(f"地线保护角(平均高处){shield_angle_at_avg_height:.2f}°")
|
||||
logger.debug(f"最低相防护标识{rg_type}。(g表示地面,c表示下导线)")
|
||||
rated_voltage = para.rated_voltage
|
||||
logger.info(f"交、直流标识{para.ac_or_dc}")
|
||||
for u_bar in range(voltage_n): # 计算不同工作电压下的跳闸率
|
||||
if para.ac_or_dc=="AC":
|
||||
# TODO 需要区分交、直流
|
||||
u_ph = (
|
||||
math.sqrt(2)
|
||||
* rated_voltage
|
||||
* math.cos(2 * math.pi / voltage_n * u_bar)
|
||||
/ 1.732
|
||||
) # 运行相电压
|
||||
# u_ph = (
|
||||
# math.sqrt(2)
|
||||
# * rated_voltage
|
||||
# * math.cos(2 * math.pi / voltage_n * u_bar)
|
||||
# / 1.732
|
||||
# ) # 运行相电压
|
||||
u_ph = rated_voltage/1.732
|
||||
else:
|
||||
u_ph = rated_voltage
|
||||
logger.info(f"计算第{phase_conductor_foo + 1}相,电压为{u_ph:.2f}kV")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 1.0.16
|
||||
version: 1.0.17
|
||||
company_name: EGM
|
||||
file_description: EGM Lightning Protection Calculator
|
||||
product_name: Lightening
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>EGM 输电线路绕击跳闸率计算 v1.0.16</title>
|
||||
<title>EGM 输电线路绕击跳闸率计算 v1.0.17</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
<template>
|
||||
<ParameterForm />
|
||||
<div class="app-container">
|
||||
<ParameterForm />
|
||||
<div class="version-footer">v{{ appVersion }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ParameterForm from '@/components/ParameterForm.vue'
|
||||
|
||||
const appVersion = __APP_VERSION__
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.version-footer {
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<q-card class="shadow-2">
|
||||
<q-card class="full-height">
|
||||
<q-card-section class="bg-indigo-50">
|
||||
<div class="text-h6 text-indigo-900 flex items-center gap-2">
|
||||
<q-icon name="architecture" />
|
||||
@@ -368,7 +368,7 @@ const drawShieldingAngle = (range: ReturnType<typeof calculateRange>) => {
|
||||
ctx.stroke()
|
||||
|
||||
// 绘制标注文字
|
||||
const labelText = `保护角: ${Math.abs(shieldingAngle).toFixed(2)}°`
|
||||
const labelText = `保护角(平均高处): ${Math.abs(shieldingAngle).toFixed(2)}°`
|
||||
ctx.font = 'bold 12px Arial'
|
||||
|
||||
// 绘制标注文字
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
<q-page class="q-pa-md">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<!-- 基本参数 + 杆塔几何结构 并排布局 -->
|
||||
<div class="row q-col-gutter-md q-mb-md">
|
||||
<div class="row q-col-gutter-md q-mb-md items-stretch" style="min-height: 500px;">
|
||||
<!-- 左侧:基本参数 -->
|
||||
<div class="col-12 col-lg-6">
|
||||
<q-card class="shadow-2 full-height">
|
||||
<div class="col-12 col-lg-6" style="display: flex;">
|
||||
<q-card class="shadow-2" style="flex: 1;">
|
||||
<q-card-section class="bg-indigo-50">
|
||||
<div class="text-h6 text-indigo-900 flex items-center gap-2">
|
||||
<q-icon name="settings" />
|
||||
@@ -204,7 +204,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 右侧:杆塔几何结构可视化 -->
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="col-12 col-lg-6" style="display: flex;">
|
||||
<Geometry
|
||||
:h-arm="params.parameter.h_arm"
|
||||
:gc-x="params.parameter.gc_x"
|
||||
@@ -213,6 +213,8 @@
|
||||
:string-c-len="params.parameter.string_c_len"
|
||||
:string-g-len="params.parameter.string_g_len"
|
||||
:ground-angels="params.parameter.ground_angels"
|
||||
class="shadow-2"
|
||||
style="flex: 1;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -305,15 +307,6 @@
|
||||
|
||||
<q-card-section>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
v-model="params.optional.voltage_n"
|
||||
type="number"
|
||||
label="计算时电压分成多少份"
|
||||
>
|
||||
<q-tooltip>将电压波形离散化的份数,即将交流电压在一个周期内的不同值进行计算。</q-tooltip>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
v-model="params.optional.max_i"
|
||||
@@ -421,7 +414,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { ref, reactive, computed, onMounted, onUnmounted, watch, toRaw } from 'vue'
|
||||
import type { AllParameters } from '@/types'
|
||||
import LogComponent from './Log.vue'
|
||||
import Animation from './Animation.vue'
|
||||
@@ -452,7 +445,7 @@ const defaultParams: AllParameters = {
|
||||
u_50: -1
|
||||
},
|
||||
optional: {
|
||||
voltage_n: 3,
|
||||
voltage_n: 1,
|
||||
max_i: 300
|
||||
}
|
||||
}
|
||||
@@ -481,14 +474,12 @@ const currentType = computed(() => {
|
||||
return params.parameter.rated_voltage.includes('±') ? 'DC' : 'AC'
|
||||
})
|
||||
|
||||
// 监听电压等级变化,同步更新 ac_or_dc 和 voltage_n 字段
|
||||
// 监听电压等级变化,同步更新 ac_or_dc 字段
|
||||
watch(
|
||||
() => params.parameter.rated_voltage,
|
||||
(newVoltage) => {
|
||||
const isDC = newVoltage.includes('±')
|
||||
params.parameter.ac_or_dc = isDC ? 'DC' : 'AC'
|
||||
// DC 时电压份数为 1,AC 时为 3
|
||||
params.optional.voltage_n = isDC ? 1 : 3
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
@@ -638,8 +629,15 @@ const calculate = async () => {
|
||||
// 后台线程启动计算,实时日志通过 addLogFromBackend 推送
|
||||
// 结果通过 receiveResult 回调接收
|
||||
// 传递动画启用状态
|
||||
// 使用 toRaw 解包响应式对象,确保 pywebview 能正确序列化参数
|
||||
const rawParams = toRaw(params)
|
||||
const paramsWithAnimation = {
|
||||
...params,
|
||||
parameter: toRaw(rawParams.parameter),
|
||||
advance: toRaw(rawParams.advance),
|
||||
optional: {
|
||||
...toRaw(rawParams.optional),
|
||||
voltage_n: 1 // 强制将电压份数设置为1
|
||||
},
|
||||
animation_enabled: animationRef.value?.isEnabled() ?? false
|
||||
}
|
||||
await window.pywebview.api.calculate(paramsWithAnimation)
|
||||
@@ -794,6 +792,8 @@ const exportConfig = async () => {
|
||||
if (window.pywebview) {
|
||||
const response = await window.pywebview.api.export_config(params)
|
||||
if (response.success) {
|
||||
// 显示导出的文件路径
|
||||
currentFilePath.value = response.file_path || ''
|
||||
logRef.value?.addLog('info', response.message)
|
||||
} else {
|
||||
logRef.value?.addLog('warning', response.message)
|
||||
@@ -905,6 +905,15 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
// 禁用数字输入框的滚轮调整功能
|
||||
const preventWheelOnNumberInput = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement
|
||||
if (target && target.type === 'number') {
|
||||
e.preventDefault()
|
||||
;(target as HTMLElement).blur()
|
||||
}
|
||||
}
|
||||
|
||||
// 注册全局日志接收函数,供后端实时调用
|
||||
onMounted(() => {
|
||||
// 程序启动时,根据雷暴日初始化地闪密度
|
||||
@@ -912,6 +921,9 @@ onMounted(() => {
|
||||
params.advance.ng = Math.round(0.023 * Math.pow(params.parameter.td, 1.3) * 100) / 100
|
||||
}
|
||||
|
||||
// 禁用数字输入框的滚轮调整
|
||||
document.addEventListener('wheel', preventWheelOnNumberInput, { passive: false })
|
||||
|
||||
// 实时日志推送
|
||||
window.addLogFromBackend = (log: { level: string; time: string; message: string }) => {
|
||||
logRef.value?.addLog(log.level as any, log.message)
|
||||
@@ -934,6 +946,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('wheel', preventWheelOnNumberInput)
|
||||
window.addLogFromBackend = undefined
|
||||
window.receiveResult = undefined
|
||||
})
|
||||
@@ -944,4 +957,15 @@ onUnmounted(() => {
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* 隐藏数字输入框的上下箭头 */
|
||||
:deep(input[type="number"]) {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
:deep(input[type="number"]::-webkit-inner-spin-button),
|
||||
:deep(input[type="number"]::-webkit-outer-spin-button) {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
3
webui/src/vite-env.d.ts
vendored
Normal file
3
webui/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare const __APP_VERSION__: string
|
||||
@@ -2,8 +2,14 @@ import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { quasar, transformAssetUrls } from '@quasar/vite-plugin'
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
const version = readFileSync(fileURLToPath(new URL('../VERSION', import.meta.url)), 'utf-8').trim()
|
||||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
__APP_VERSION__: JSON.stringify(version)
|
||||
},
|
||||
base: './',
|
||||
plugins: [
|
||||
vue({
|
||||
|
||||
Reference in New Issue
Block a user