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