From 2ec763b86a69e37a6e8ce87d61802d7c74e3b393 Mon Sep 17 00:00:00 2001 From: dmy Date: Sun, 4 Jan 2026 19:11:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E7=94=B5=E7=BC=86?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=A0=A1=E9=AA=8C=E5=92=8CUI=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gui.py | 12 +++++++----- main.py | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/gui.py b/gui.py index b886fe0..df25e39 100644 --- a/gui.py +++ b/gui.py @@ -379,10 +379,11 @@ def index(): refs["status_label"].text = "准备开始计算..." except queue.Empty: break - if new_msg: - # 强制日志框滚动到最底部,确保最后一行可见 + if new_msg and refs["log_box"]: + # 使用 JS 直接滚动 log 元素到最底部 + # 增加一个小延时确保内容渲染完成 ui.run_javascript( - 'const el = document.querySelector(".analysis-log-box"); if (el) { el.scrollTop = el.scrollHeight; }' + f'var el = document.getElementById("c{refs["log_box"].id}"); if(el) {{ setTimeout(() => {{ el.scrollTop = el.scrollHeight; }}, 10); }}' ) log_timer = ui.timer(0.1, process_log_queue) @@ -500,13 +501,14 @@ def index(): with ui.expansion("查看实时日志", icon="terminal", value=True).classes( "w-full mt-4 text-sm" ): + # 直接控制 log 组件的样式和滚动,去除 scroll_area 中间层 refs["log_box"] = ui.log(max_lines=100).classes( - "w-full h-32 text-xs font-mono bg-black text-green-400 analysis-log-box" + "w-full h-32 overflow-y-auto p-2 bg-black text-xs font-mono text-green-400 leading-snug" ) processing_dialog.props("persistent") with ui.header().classes("bg-primary text-white p-4 shadow-lg"): - ui.label("海上风电场集电线路设计优化系统").classes("text-2xl font-bold") + ui.label("海上风电场集电线路设计优化系统 v1.0").classes("text-2xl font-bold") ui.label("Wind Farm Collector System Design Optimizer").classes( "text-sm opacity-80" ) diff --git a/main.py b/main.py index 5f02fa7..6e51931 100644 --- a/main.py +++ b/main.py @@ -153,9 +153,48 @@ def load_data_from_excel(file_path): specs.append((section, capacity, resistance, cost, is_optional)) if specs: - specs.sort(key=lambda x: x[1]) # 按载流量排序 + # --- 输入数据校验:单调性 --- + for i in range(len(specs) - 1): + curr_s = specs[i] + next_s = specs[i + 1] + + # 校验截面 (section) + if curr_s[0] >= next_s[0]: + raise ValueError( + f"电缆数据校验失败:Excel中电缆顺序必须按截面从小到大排列。第{i+1}行({curr_s[0]}mm²) >= 第{i+2}行({next_s[0]}mm²)。" + ) + + # 校验载流量 (capacity) + if curr_s[1] >= next_s[1]: + raise ValueError( + f"电缆数据校验失败:Excel中电缆载流量必须严格递增。第{i+1}行({curr_s[1]}A) >= 第{i+2}行({next_s[1]}A)。" + ) + + specs.sort(key=lambda x: x[1]) # 按载流量排序 + + # --- 输入数据校验 --- + # 筛选出所有标记为 Optional='Y' 的电缆 + optional_cables = [s for s in specs if s[4]] + + # 规则1: 最多只能有一条可选电缆 + if len(optional_cables) > 1: + raise ValueError( + f"电缆数据校验失败:检测到 {len(optional_cables)} 条可选电缆(Optional='Y')。系统限制最多只能指定 1 条可选电缆。" + ) + + # 规则2: 如果存在可选电缆,它必须是所有电缆中截面最大的一条 + if len(optional_cables) == 1: + opt_cable = optional_cables[0] + # s[0] 是截面积 + max_section = max(s[0] for s in specs) + if opt_cable[0] < max_section: + raise ValueError( + f"电缆数据校验失败:可选电缆 ({opt_cable[0]}mm²) 必须是所有电缆中截面最大的一条 (当前最大为 {max_section}mm²)。" + ) + # -------------------- + cable_specs = specs - + print(f"成功加载: {len(turbines)} 台风机, {len(substation)} 座升压站") if cable_specs: print(f"成功加载: {len(cable_specs)} 种电缆规格")