fix: 修复打包后exe程序在无控制台模式下运行时的uvicorn日志配置错误

通过检测sys.frozen判断运行环境,只在打包后的exe程序中禁用日志配置,
避免AttributeError: 'NoneType' object has no attribute 'isatty'错误。
普通Python运行环境保留完整日志功能,方便调试。
This commit is contained in:
dmy
2026-01-05 09:52:51 +08:00
parent 2ec763b86a
commit a5b46529da
4 changed files with 214 additions and 113 deletions

96
gui.py
View File

@@ -38,6 +38,8 @@ state = {
"results": [],
"substation": None,
"turbines": None,
"cable_specs": None,
"system_params": None,
"temp_dir": os.path.join(tempfile.gettempdir(), "windfarm_gui_uploads"),
}
@@ -70,8 +72,74 @@ def index():
"upload_widget": None,
"run_btn": None,
"current_file_label": None,
"info_container": None, # 新增信息展示容器
}
def update_info_panel():
if refs["info_container"]:
refs["info_container"].clear()
with refs["info_container"]:
# System Params - Always show
with ui.row().classes("w-full items-center gap-4 mb-2"):
ui.icon('settings', color='primary').classes('text-2xl')
ui.label("系统参数").classes("text-lg font-bold")
params_text = []
# 获取电压
v = 66000 # Default
is_default_v = True
if state.get("system_params") and 'voltage' in state['system_params']:
v = state['system_params']['voltage']
is_default_v = False
v_str = f"电压: {v/1000:.1f} kV" if v >= 1000 else f"电压: {v} V"
if is_default_v:
v_str += " (默认)"
params_text.append(v_str)
# 获取功率因数
pf = 0.95 # Default
is_default_pf = True
if state.get("system_params") and 'power_factor' in state['system_params']:
pf = state['system_params']['power_factor']
is_default_pf = False
pf_str = f"功率因数: {pf}"
if is_default_pf:
pf_str += " (默认)"
params_text.append(pf_str)
for p in params_text:
ui.chip(p, icon='bolt').props('outline color=primary')
ui.separator().classes('my-2')
# Cables
if state.get("cable_specs"):
with ui.row().classes("w-full items-center gap-2 mb-2"):
ui.icon('cable', color='secondary').classes('text-2xl')
ui.label("电缆规格参数").classes("text-lg font-bold")
columns = [
{'name': 'section', 'label': '截面 (mm²)', 'field': 'section', 'align': 'center'},
{'name': 'capacity', 'label': '载流量 (A)', 'field': 'capacity', 'align': 'center'},
{'name': 'resistance', 'label': '电阻 (Ω/km)', 'field': 'resistance', 'align': 'center'},
{'name': 'cost', 'label': '参考单价 (元/m)', 'field': 'cost', 'align': 'center'},
]
rows = []
for spec in state["cable_specs"]:
# spec is (section, capacity, resistance, cost, is_optional)
rows.append({
'section': spec[0],
'capacity': spec[1],
'resistance': spec[2],
'cost': spec[3]
})
ui.table(columns=columns, rows=rows).classes('w-full').props('dense flat bordered')
else:
ui.label("未检测到电缆数据,将使用默认参数。").classes("text-gray-500 italic")
async def handle_upload(e: events.UploadEventArguments):
try:
filename = None
@@ -125,7 +193,16 @@ def index():
refs["current_file_label"].text = f"当前文件: {filename}"
# 加载数据
state["turbines"], state["substation"], _ = load_data_from_excel(path)
try:
# 尝试解包 4 个返回值 (新版 main.py)
state["turbines"], state["substation"], state["cable_specs"], state["system_params"] = load_data_from_excel(path)
except ValueError:
# 兼容旧版 (如果是 3 个返回值)
state["turbines"], state["substation"], state["cable_specs"] = load_data_from_excel(path)
state["system_params"] = {}
update_info_panel()
except Exception as ex:
ui.notify(f"上传处理失败: {ex}", type="negative")
@@ -546,6 +623,11 @@ def index():
)
with ui.column().classes("w-3/4 gap-4"):
# 新增:信息展示卡片
with ui.card().classes("w-full p-4 shadow-md").style("max-height: 400px; overflow-y: auto;"):
refs["info_container"] = ui.column().classes("w-full")
ui.label("请上传 Excel 文件以查看系统参数和电缆规格...").classes("text-gray-500 italic")
with ui.card().classes("w-full p-4 shadow-md"):
ui.label("方案对比结果 (点击行查看拓扑详情)").classes(
"text-xl font-semibold mb-2"
@@ -610,4 +692,14 @@ def find_available_port(start_port=8080, max_attempts=10):
# 自动寻找可用端口,避免端口冲突
target_port = find_available_port(8080)
ui.run(title="海上风电场集电线路优化", port=target_port)
# 检测是否为打包后的exe程序
import sys
if getattr(sys, 'frozen', False):
# 打包环境下禁用日志配置,避免在无控制台模式下出现错误
import logging
logging.disable(logging.CRITICAL)
ui.run(title="海上风电场集电线路优化", port=target_port, log_level=None)
else:
# 普通使用环境保留日志功能
ui.run(title="海上风电场集电线路优化", port=target_port)