| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import streamlit as st
- import pandas as pd
- from datetime import datetime, timedelta
- import random
- import plotly.express as px
- import plotly.graph_objects as go
- st.title("📚 History")
- st.markdown("操作历史和活动记录")
- # 模拟历史数据
- @st.cache_data
- def load_history_data():
- actions = ["登录", "登出", "创建", "编辑", "删除", "查看", "下载", "上传"]
- objects = ["用户账户", "订单记录", "产品信息", "系统设置", "报告文件", "配置文件"]
- users = ["张三", "李四", "王五", "赵六", "钱七", "孙八"]
-
- data = []
- for i in range(500):
- timestamp = datetime.now() - timedelta(
- days=random.randint(0, 90),
- hours=random.randint(0, 23),
- minutes=random.randint(0, 59)
- )
-
- data.append({
- 'id': f"HIST-{4000 + i}",
- 'timestamp': timestamp,
- 'user': random.choice(users),
- 'action': random.choice(actions),
- 'object': random.choice(objects),
- 'ip_address': f"192.168.1.{random.randint(1, 254)}",
- 'status': random.choice(['成功', '失败', '警告']),
- 'details': f"操作详情 {i+1}: 用户执行了相关操作",
- 'session_id': f"SES-{random.randint(10000, 99999)}"
- })
-
- return pd.DataFrame(data)
- # 加载数据
- history_df = load_history_data()
- # 时间范围选择
- st.subheader("📅 时间范围")
- col1, col2, col3 = st.columns(3)
- with col1:
- time_filter = st.selectbox(
- "快速选择",
- ["最近1小时", "最近24小时", "最近7天", "最近30天", "最近90天", "自定义范围"]
- )
- with col2:
- if time_filter == "自定义范围":
- start_date = st.date_input("开始日期", value=datetime.now() - timedelta(days=7))
- else:
- start_date = None
- with col3:
- if time_filter == "自定义范围":
- end_date = st.date_input("结束日期", value=datetime.now())
- else:
- end_date = None
- # 应用时间筛选
- if time_filter == "最近1小时":
- cutoff = datetime.now() - timedelta(hours=1)
- filtered_df = history_df[history_df['timestamp'] >= cutoff]
- elif time_filter == "最近24小时":
- cutoff = datetime.now() - timedelta(days=1)
- filtered_df = history_df[history_df['timestamp'] >= cutoff]
- elif time_filter == "最近7天":
- cutoff = datetime.now() - timedelta(days=7)
- filtered_df = history_df[history_df['timestamp'] >= cutoff]
- elif time_filter == "最近30天":
- cutoff = datetime.now() - timedelta(days=30)
- filtered_df = history_df[history_df['timestamp'] >= cutoff]
- elif time_filter == "最近90天":
- cutoff = datetime.now() - timedelta(days=90)
- filtered_df = history_df[history_df['timestamp'] >= cutoff]
- else: # 自定义范围
- if start_date and end_date:
- filtered_df = history_df[
- (history_df['timestamp'].dt.date >= start_date) &
- (history_df['timestamp'].dt.date <= end_date)
- ]
- else:
- filtered_df = history_df
- # 统计概览
- st.subheader("📊 活动概览")
- col1, col2, col3, col4 = st.columns(4)
- with col1:
- st.metric("总操作数", len(filtered_df))
- with col2:
- unique_users = filtered_df['user'].nunique()
- st.metric("活跃用户", unique_users)
- with col3:
- success_rate = len(filtered_df[filtered_df['status'] == '成功']) / len(filtered_df) * 100 if len(filtered_df) > 0 else 0
- st.metric("成功率", f"{success_rate:.1f}%")
- with col4:
- failed_ops = len(filtered_df[filtered_df['status'] == '失败'])
- st.metric("失败操作", failed_ops)
- # 可视化图表
- st.subheader("📈 活动趋势")
- tab1, tab2, tab3 = st.tabs(["时间趋势", "用户活动", "操作分布"])
- with tab1:
- # 按小时统计活动
- if len(filtered_df) > 0:
- hourly_activity = filtered_df.groupby(filtered_df['timestamp'].dt.hour).size().reset_index()
- hourly_activity.columns = ['hour', 'count']
-
- fig_hourly = px.bar(hourly_activity, x='hour', y='count',
- title='按小时统计的活动分布')
- st.plotly_chart(fig_hourly, use_container_width=True)
- with tab2:
- # 用户活动统计
- if len(filtered_df) > 0:
- user_activity = filtered_df['user'].value_counts().reset_index()
- user_activity.columns = ['user', 'count']
-
- fig_users = px.pie(user_activity, values='count', names='user',
- title='用户活动分布')
- st.plotly_chart(fig_users, use_container_width=True)
- with tab3:
- # 操作类型分布
- if len(filtered_df) > 0:
- action_counts = filtered_df['action'].value_counts().reset_index()
- action_counts.columns = ['action', 'count']
-
- fig_actions = px.bar(action_counts, x='action', y='count',
- title='操作类型分布')
- st.plotly_chart(fig_actions, use_container_width=True)
- # 筛选器
- st.subheader("🔍 详细筛选")
- col1, col2, col3, col4 = st.columns(4)
- with col1:
- selected_users = st.multiselect(
- "用户",
- options=filtered_df['user'].unique(),
- default=filtered_df['user'].unique()
- )
- with col2:
- selected_actions = st.multiselect(
- "操作类型",
- options=filtered_df['action'].unique(),
- default=filtered_df['action'].unique()
- )
- with col3:
- selected_status = st.multiselect(
- "状态",
- options=filtered_df['status'].unique(),
- default=filtered_df['status'].unique()
- )
- with col4:
- search_term = st.text_input("搜索", placeholder="搜索详情...")
- # 应用筛选
- final_df = filtered_df[
- (filtered_df['user'].isin(selected_users)) &
- (filtered_df['action'].isin(selected_actions)) &
- (filtered_df['status'].isin(selected_status))
- ]
- if search_term:
- final_df = final_df[
- final_df['details'].str.contains(search_term, case=False, na=False) |
- final_df['object'].str.contains(search_term, case=False, na=False)
- ]
- # 历史记录表格
- st.subheader("📋 历史记录")
- # 排序选项
- sort_order = st.radio("排序", ["最新在前", "最旧在前"], horizontal=True)
- final_df = final_df.sort_values('timestamp', ascending=(sort_order == "最旧在前"))
- # 分页
- items_per_page = st.selectbox("每页显示", [25, 50, 100], index=1)
- total_pages = (len(final_df) - 1) // items_per_page + 1 if len(final_df) > 0 else 1
- if total_pages > 1:
- page = st.selectbox("页面", range(1, total_pages + 1))
- start_idx = (page - 1) * items_per_page
- end_idx = start_idx + items_per_page
- display_df = final_df.iloc[start_idx:end_idx]
- else:
- display_df = final_df
- # 显示数据
- if len(display_df) > 0:
- st.dataframe(
- display_df[['timestamp', 'user', 'action', 'object', 'status', 'ip_address', 'details']],
- use_container_width=True,
- column_config={
- 'timestamp': st.column_config.DatetimeColumn(
- "时间",
- format="MM-DD HH:mm:ss"
- ),
- 'status': st.column_config.SelectboxColumn(
- "状态",
- options=['成功', '失败', '警告']
- )
- }
- )
-
- # 导出功能
- if st.button("📥 导出当前数据"):
- csv = display_df.to_csv(index=False)
- st.download_button(
- label="下载CSV文件",
- data=csv,
- file_name=f"history_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
- mime="text/csv"
- )
- else:
- st.warning("没有找到匹配的历史记录")
- # 实时更新选项
- st.subheader("🔄 实时更新")
- auto_refresh = st.checkbox("启用自动刷新 (30秒)")
- if auto_refresh:
- st.info("⏱️ 页面将每30秒自动刷新")
- time.sleep(30)
- st.rerun()
|