From 6628f663b636675bcaea316f2deaddf337de480e Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期五, 13 三月 2026 10:23:31 +0800
Subject: [PATCH] feat(米重分析): 新增稳态识别和预测功能页面并优化现有模型

---
 app/pages/metered_weight_dashboard.py |  430 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 430 insertions(+), 0 deletions(-)

diff --git a/app/pages/metered_weight_dashboard.py b/app/pages/metered_weight_dashboard.py
new file mode 100644
index 0000000..9824e29
--- /dev/null
+++ b/app/pages/metered_weight_dashboard.py
@@ -0,0 +1,430 @@
+import streamlit as st
+import plotly.express as px
+import plotly.graph_objects as go
+import pandas as pd
+from datetime import datetime, timedelta
+from app.services.extruder_service import ExtruderService
+from app.services.main_process_service import MainProcessService
+
+def show_metered_weight_dashboard():
+    # 鍒濆鍖栨湇鍔�
+    extruder_service = ExtruderService()
+    main_process_service = MainProcessService()
+
+    # 椤甸潰鏍囬
+    st.title("绫抽噸缁煎悎鍒嗘瀽")
+
+    # 鍒濆鍖栦細璇濈姸鎬佺敤浜庢棩鏈熷悓姝�
+    if 'mw_start_date' not in st.session_state:
+        st.session_state['mw_start_date'] = datetime.now().date() - timedelta(days=7)
+    if 'mw_end_date' not in st.session_state:
+        st.session_state['mw_end_date'] = datetime.now().date()
+    if 'mw_quick_select' not in st.session_state:
+        st.session_state['mw_quick_select'] = "鏈�杩�7澶�"
+
+    # 瀹氫箟鍥炶皟鍑芥暟
+    def update_dates(qs):
+        st.session_state['mw_quick_select'] = qs
+        today = datetime.now().date()
+        if qs == "浠婂ぉ":
+            st.session_state['mw_start_date'] = today
+            st.session_state['mw_end_date'] = today
+        elif qs == "鏈�杩�3澶�":
+            st.session_state['mw_start_date'] = today - timedelta(days=3)
+            st.session_state['mw_end_date'] = today
+        elif qs == "鏈�杩�7澶�":
+            st.session_state['mw_start_date'] = today - timedelta(days=7)
+            st.session_state['mw_end_date'] = today
+        elif qs == "鏈�杩�30澶�":
+            st.session_state['mw_start_date'] = today - timedelta(days=30)
+            st.session_state['mw_end_date'] = today
+
+    def on_date_change():
+        st.session_state['mw_quick_select'] = "鑷畾涔�"
+
+    # 鏌ヨ鏉′欢鍖哄煙
+    with st.expander("馃攳 鏌ヨ閰嶇疆", expanded=True):
+        # 娣诲姞鑷畾涔� CSS 瀹炵幇鍝嶅簲寮忔崲琛�
+        st.markdown("""
+            <style>
+            /* 寮哄埗鍒楀鍣ㄦ崲琛� */
+            [data-testid="stExpander"] [data-testid="column"] {
+                flex: 1 1 120px !important;
+                min-width: 120px !important;
+            }
+            /* 閽堝鏃ユ湡杈撳叆妗嗗垪绋嶅井鍔犲涓�鐐� */
+            @media (min-width: 768px) {
+                [data-testid="stExpander"] [data-testid="column"]:nth-child(6),
+                [data-testid="stExpander"] [data-testid="column"]:nth-child(7) {
+                    flex: 2 1 180px !important;
+                    min-width: 180px !important;
+                }
+            }
+            </style>
+            """, unsafe_allow_html=True)
+            
+        # 鍒涘缓甯冨眬
+        cols = st.columns([1, 1, 1, 1, 1, 1.5, 1.5, 1])
+        
+        options = ["浠婂ぉ", "鏈�杩�3澶�", "鏈�杩�7澶�", "鏈�杩�30澶�", "鑷畾涔�"]
+        for i, option in enumerate(options):
+            with cols[i]:
+                # 鏍规嵁褰撳墠閫夋嫨鐘舵�佸喅瀹氭寜閽被鍨�
+                button_type = "primary" if st.session_state['mw_quick_select'] == option else "secondary"
+                if st.button(option, key=f"btn_mw_{option}", width='stretch', type=button_type):
+                    update_dates(option)
+                    st.rerun()
+
+        with cols[5]:
+            start_date = st.date_input(
+                "寮�濮嬫棩鏈�", 
+                label_visibility="collapsed",
+                key="mw_start_date",
+                on_change=on_date_change
+            )
+        
+        with cols[6]:
+            end_date = st.date_input(
+                "缁撴潫鏃ユ湡", 
+                label_visibility="collapsed",
+                key="mw_end_date",
+                on_change=on_date_change
+            )
+
+        with cols[7]:
+            query_button = st.button("馃殌 寮�濮嬪垎鏋�", key="mw_query", width='stretch')
+
+    # 杞崲涓篸atetime瀵硅薄
+    start_dt = datetime.combine(start_date, datetime.min.time())
+    end_dt = datetime.combine(end_date, datetime.max.time())
+
+    # 鏌ヨ澶勭悊
+    if query_button:
+        with st.spinner("姝e湪鑱氬悎鏁版嵁..."):
+            # 1. 鑾峰彇鎸ゅ嚭鏈烘暟鎹�
+            df_extruder = extruder_service.get_extruder_data(start_dt, end_dt)
+            # 澶勭悊鏈哄ご鍘嬪姏锛屽幓闄よ秴杩�2鐨勫��
+            if df_extruder is not None and not df_extruder.empty:
+                df_extruder = df_extruder[df_extruder['head_pressure'] <= 2]
+            
+            # 2. 鑾峰彇涓绘祦绋嬫帶鍒舵暟鎹�
+            df_main_speed = main_process_service.get_cutting_setting_data(start_dt, end_dt)
+            df_temp = main_process_service.get_temperature_control_data(start_dt, end_dt)
+            # 鑾峰彇鐢垫満杩愯鐩戣鏁版嵁
+            df_motor = main_process_service.get_motor_monitoring_data(start_dt, end_dt)
+            # 澶勭悊鐢垫満绾块�熸暟鎹紝闄や互10
+            if df_motor is not None and not df_motor.empty:
+                df_motor['m1_line_speed'] = df_motor['m1_line_speed'] / 10
+                df_motor['m2_line_speed'] = df_motor['m2_line_speed'] / 10
+
+            # 妫�鏌ユ槸鍚︽湁鏁版嵁
+            has_data = any([
+                df_extruder is not None and not df_extruder.empty,
+                df_main_speed is not None and not df_main_speed.empty,
+                df_temp is not None and not df_temp.empty,
+                df_motor is not None and not df_motor.empty        
+            ])
+
+            if not has_data:
+                st.warning("鎵�閫夋椂闂存鍐呮湭鎵惧埌浠讳綍鏁版嵁锛岃灏濊瘯璋冩暣鏌ヨ鏉′欢銆�")
+                return
+
+            # --- 鍥捐〃1: 绫抽噸涓庡疄闄呭弬鏁板垎鏋� ---
+            st.subheader("馃搱 绫抽噸涓庡疄闄呭弬鏁板垎鏋�")
+            fig1 = go.Figure()
+
+            # 娣诲姞绫抽噸
+            if df_extruder is not None and not df_extruder.empty:
+                fig1.add_trace(go.Scatter(
+                    x=df_extruder['time'], 
+                    y=df_extruder['metered_weight'],
+                    name='绫抽噸 (Kg/m)',
+                    mode='lines',
+                    line=dict(color='blue', width=2),
+                    yaxis='y1'
+                ))
+                
+                # 娣诲姞鎸ゅ嚭鏈哄疄闄呰浆閫�
+                fig1.add_trace(go.Scatter(
+                    x=df_extruder['time'], 
+                    y=df_extruder['screw_speed_actual'],
+                    name='鎸ゅ嚭鏈哄疄闄呰浆閫� (RPM)',
+                    mode='lines',
+                    line=dict(color='green', width=1.5),
+                    yaxis='y2'
+                ))
+                
+                # 娣诲姞鎸ゅ嚭鏈烘満澶村帇鍔�
+                fig1.add_trace(go.Scatter(
+                    x=df_extruder['time'], 
+                    y=df_extruder['head_pressure'],
+                    name='鎸ゅ嚭鏈烘満澶村帇鍔�',
+                    mode='lines',
+                    line=dict(color='orange', width=1.5),
+                    yaxis='y3'
+                ))
+
+            # 娣诲姞娴佺▼涓婚��
+            if df_main_speed is not None and not df_main_speed.empty:
+                fig1.add_trace(go.Scatter(
+                    x=df_main_speed['time'], 
+                    y=df_main_speed['process_main_speed'],
+                    name='娴佺▼涓婚�� (M/Min)',
+                    mode='lines',
+                    line=dict(color='red', width=1.5),
+                    yaxis='y4' # 鍗曠嫭鐨勯�熷害杞�
+                ))
+
+            # 娣诲姞娓╁害鏄剧ず鍊�
+            if df_temp is not None and not df_temp.empty:
+                temp_display_fields = {
+                    'nakata_extruder_screw_display_temp': '铻烘潌鏄剧ず (掳C)',
+                    'nakata_extruder_rear_barrel_display_temp': '鍚庢満绛掓樉绀� (掳C)',
+                    'nakata_extruder_front_barrel_display_temp': '鍓嶆満绛掓樉绀� (掳C)',
+                    'nakata_extruder_head_display_temp': '鏈哄ご鏄剧ず (掳C)',
+                }
+                for field, label in temp_display_fields.items():
+                    fig1.add_trace(go.Scatter(
+                        x=df_temp['time'], 
+                        y=df_temp[field],
+                        name=label,
+                        mode='lines',
+                        line=dict(width=1),
+                        yaxis='y5'
+                    ))
+            
+            # 娣诲姞鐢垫満绾块�熸暟鎹�
+            if df_motor is not None and not df_motor.empty:
+                fig1.add_trace(go.Scatter(
+                    x=df_motor['time'], 
+                    y=df_motor['m1_line_speed'],
+                    name='鎷夊嚭涓�娈电嚎閫� (M/Min)',
+                    mode='lines',
+                    line=dict(color='cyan', width=1.5),
+                    yaxis='y4'
+                ))
+                fig1.add_trace(go.Scatter(
+                    x=df_motor['time'], 
+                    y=df_motor['m2_line_speed'],
+                    name='鎷夊嚭浜屾绾块�� (M/Min)',
+                    mode='lines',
+                    line=dict(color='teal', width=1.5),
+                    yaxis='y4'
+                ))
+
+            # 璁剧疆鍥捐〃1甯冨眬
+            fig1.update_layout(
+                title='绫抽噸涓庡疄闄呭弬鏁拌秼鍔垮垎鏋�',
+                xaxis=dict(
+                    title='鏃堕棿',
+                    rangeslider=dict(visible=True),
+                    type='date'
+                ),
+                yaxis=dict(
+                    title='绫抽噸 (Kg/m)',
+                    title_font=dict(color='blue'),
+                    tickfont=dict(color='blue')
+                ),
+                yaxis2=dict(
+                    title='鎸ゅ嚭鏈鸿浆閫� (RPM)',
+                    title_font=dict(color='green'),
+                    tickfont=dict(color='green'),
+                    overlaying='y',
+                    side='right'
+                ),
+                yaxis3=dict(
+                    title='鏈哄ご鍘嬪姏',
+                    title_font=dict(color='orange'),
+                    tickfont=dict(color='orange'),
+                    overlaying='y',
+                    side='right',
+                    anchor='free',
+                    position=0.85
+                ),
+                yaxis4=dict(
+                    title='娴佺▼涓婚�� (M/Min)',
+                    title_font=dict(color='red'),
+                    tickfont=dict(color='red'),
+                    overlaying='y',
+                    side='right',
+                    anchor='free',
+                    position=0.75
+                ),
+                yaxis5=dict(
+                    title='娓╁害鏄剧ず (掳C)',
+                    title_font=dict(color='purple'),
+                    tickfont=dict(color='purple'),
+                    overlaying='y',
+                    side='left',
+                    anchor='free',
+                    position=0.15
+                ),
+                yaxis6=dict(
+                    title='鎷夊嚭绾块�� (M/Min)',
+                    title_font=dict(color='cyan'),
+                    tickfont=dict(color='cyan'),
+                    overlaying='y',
+                    side='right',
+                    anchor='free',
+                    position=0.65
+                ),
+                legend=dict(
+                    orientation="h",
+                    yanchor="bottom",
+                    y=1.02,
+                    xanchor="right",
+                    x=1
+                ),
+                height=600,
+                margin=dict(l=100, r=200, t=100, b=100),
+                hovermode='x unified'
+            )
+
+            # 鏄剧ず鍥捐〃1
+            st.plotly_chart(fig1, width='stretch', config={'scrollZoom': True})
+
+            # --- 鍥捐〃2: 绫抽噸涓庤瀹氬弬鏁板垎鏋� ---
+            st.subheader("馃搱 绫抽噸涓庤瀹氬弬鏁板垎鏋�")
+            fig2 = go.Figure()
+
+            # 娣诲姞绫抽噸
+            if df_extruder is not None and not df_extruder.empty:
+                fig2.add_trace(go.Scatter(
+                    x=df_extruder['time'], 
+                    y=df_extruder['metered_weight'],
+                    name='绫抽噸 (Kg/m)',
+                    mode='lines',
+                    line=dict(color='blue', width=2),
+                    yaxis='y1'
+                ))
+                
+                # 娣诲姞鎸ゅ嚭鏈鸿瀹氳浆閫�
+                fig2.add_trace(go.Scatter(
+                    x=df_extruder['time'], 
+                    y=df_extruder['screw_speed_set'],
+                    name='鎸ゅ嚭鏈鸿瀹氳浆閫� (RPM)',
+                    mode='lines',
+                    line=dict(color='green', width=1.5, dash='dash'),
+                    yaxis='y2'
+                ))
+                
+                # 娣诲姞鎸ゅ嚭鏈烘満澶村帇鍔�
+                fig2.add_trace(go.Scatter(
+                    x=df_extruder['time'], 
+                    y=df_extruder['head_pressure'],
+                    name='鎸ゅ嚭鏈烘満澶村帇鍔�',
+                    mode='lines',
+                    line=dict(color='orange', width=1.5),
+                    yaxis='y3'
+                ))
+
+            # 娣诲姞娴佺▼涓婚��
+            if df_main_speed is not None and not df_main_speed.empty:
+                fig2.add_trace(go.Scatter(
+                    x=df_main_speed['time'], 
+                    y=df_main_speed['process_main_speed'],
+                    name='娴佺▼涓婚�� (M/Min)',
+                    mode='lines',
+                    line=dict(color='red', width=1.5),
+                    yaxis='y4' # 鍗曠嫭鐨勯�熷害杞�
+                ))
+
+            # 娣诲姞娓╁害璁惧畾鍊�
+            if df_temp is not None and not df_temp.empty:
+                temp_set_fields = {
+                    'nakata_extruder_screw_set_temp': '铻烘潌璁惧畾 (掳C)',
+                    'nakata_extruder_rear_barrel_set_temp': '鍚庢満绛掕瀹� (掳C)',
+                    'nakata_extruder_front_barrel_set_temp': '鍓嶆満绛掕瀹� (掳C)',
+                    'nakata_extruder_head_set_temp': '鏈哄ご璁惧畾 (掳C)',
+                }
+                for field, label in temp_set_fields.items():
+                    fig2.add_trace(go.Scatter(
+                        x=df_temp['time'], 
+                        y=df_temp[field],
+                        name=label,
+                        mode='lines',
+                        line=dict(width=1, dash='dash'),
+                        yaxis='y5'
+                    ))
+
+            # 璁剧疆鍥捐〃2甯冨眬
+            fig2.update_layout(
+                title='绫抽噸涓庤瀹氬弬鏁拌秼鍔垮垎鏋�',
+                xaxis=dict(
+                    title='鏃堕棿',
+                    rangeslider=dict(visible=True),
+                    type='date'
+                ),
+                yaxis=dict(
+                    title='绫抽噸 (Kg/m)',
+                    title_font=dict(color='blue'),
+                    tickfont=dict(color='blue')
+                ),
+                yaxis2=dict(
+                    title='鎸ゅ嚭鏈鸿浆閫� (RPM)',
+                    title_font=dict(color='green'),
+                    tickfont=dict(color='green'),
+                    overlaying='y',
+                    side='right'
+                ),
+                yaxis3=dict(
+                    title='鏈哄ご鍘嬪姏',
+                    title_font=dict(color='orange'),
+                    tickfont=dict(color='orange'),
+                    overlaying='y',
+                    side='right',
+                    anchor='free',
+                    position=0.85
+                ),
+                yaxis4=dict(
+                    title='娴佺▼涓婚�� (M/Min)',
+                    title_font=dict(color='red'),
+                    tickfont=dict(color='red'),
+                    overlaying='y',
+                    side='right',
+                    anchor='free',
+                    position=0.75
+                ),
+                yaxis5=dict(
+                    title='娓╁害璁惧畾 (掳C)',
+                    title_font=dict(color='purple'),
+                    tickfont=dict(color='purple'),
+                    overlaying='y',
+                    side='left',
+                    anchor='free',
+                    position=0.15
+                ),
+                legend=dict(
+                    orientation="h",
+                    yanchor="bottom",
+                    y=1.02,
+                    xanchor="right",
+                    x=1
+                ),
+                height=600,
+                margin=dict(l=100, r=150, t=100, b=100),
+                hovermode='x unified'
+            )
+
+            # 鏄剧ず鍥捐〃2
+            st.plotly_chart(fig2, width='stretch', config={'scrollZoom': True})
+            
+            # 鏁版嵁鎽樿
+            # st.subheader("馃搳 鏁版嵁鎽樿")
+            # summary_cols = st.columns(4)
+            
+            # with summary_cols[0]:
+            #     if df_extruder is not None and not df_extruder.empty:
+            #         st.metric("骞冲潎绫抽噸", f"{df_extruder['metered_weight'].mean():.2f} Kg/m")
+            
+            # with summary_cols[1]:
+            #     if df_extruder is not None and not df_extruder.empty:
+            #         st.metric("骞冲潎璁惧畾杞��", f"{df_extruder['screw_speed_set'].mean():.2f} RPM")
+            
+            # with summary_cols[2]:
+            #     if df_extruder is not None and not df_extruder.empty:
+            #         st.metric("骞冲潎瀹為檯杞��", f"{df_extruder['screw_speed_actual'].mean():.2f} RPM")
+            
+            # with summary_cols[3]:
+            #     if df_extruder is not None and not df_extruder.empty:
+            #         st.metric("骞冲潎鏈哄ご鍘嬪姏", f"{df_extruder['head_pressure'].mean():.2f}")

--
Gitblit v1.9.3