Skip to content

Commit 5f1cf53

Browse files
authored
Merge pull request #55 from sunmh207/feature/20250321-ui
add chart to dashboard
2 parents 52d4f16 + 4a6e55d commit 5f1cf53

File tree

8 files changed

+128
-7
lines changed

8 files changed

+128
-7
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
![MR图片](./doc/img/mr.png)
1919

20-
![Note图片](./doc/img/note.jpeg)
20+
![Note图片](./doc/img/note.jpg)
2121

22-
![Dashboard图片](./doc/img/dashboard.png)
22+
![Dashboard图片](./doc/img/dashboard.jpg)
2323

2424
## 原理
2525

biz/service/review_service.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def insert_push_review_log(entity: PushReviewEntity):
117117
print(f"Error inserting review log: {e}")
118118

119119
@staticmethod
120-
def get_push_review_logs(authors: list = None, updated_at_gte: int = None,
120+
def get_push_review_logs(authors: list = None, project_names: list = None, updated_at_gte: int = None,
121121
updated_at_lte: int = None) -> pd.DataFrame:
122122
"""获取符合条件的推送审核日志"""
123123
try:
@@ -136,6 +136,11 @@ def get_push_review_logs(authors: list = None, updated_at_gte: int = None,
136136
query += f" AND author IN ({placeholders})"
137137
params.extend(authors)
138138

139+
if project_names:
140+
placeholders = ','.join(['?'] * len(project_names))
141+
query += f" AND project_name IN ({placeholders})"
142+
params.extend(project_names)
143+
139144
# 动态添加 updated_at_gte 条件
140145
if updated_at_gte is not None:
141146
query += " AND updated_at >= ?"

doc/img/dashboard.jpg

386 KB
Loading

doc/img/dashboard.png

-86.8 KB
Binary file not shown.

doc/img/note.jpeg

-28.5 KB
Binary file not shown.

doc/img/note.jpg

164 KB
Loading

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ openai==1.59.3
77
httpx[socks]
88
ollama==0.4.7
99
pandas==2.2.3
10-
streamlit==1.42.2
10+
streamlit==1.42.2
11+
matplotlib==3.10.1

ui.py

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pandas as pd
55
import streamlit as st
66
from dotenv import load_dotenv
7-
7+
import matplotlib.pyplot as plt
88
from biz.service.review_service import ReviewService
99

1010
load_dotenv("conf/.env")
@@ -24,7 +24,8 @@ def authenticate(username, password):
2424

2525
# 获取数据函数
2626
def get_data(service_func, authors=None, project_names=None, updated_at_gte=None, updated_at_lte=None, columns=None):
27-
df = service_func(authors=authors, project_names=project_names, updated_at_gte=updated_at_gte, updated_at_lte=updated_at_lte)
27+
df = service_func(authors=authors, project_names=project_names, updated_at_gte=updated_at_gte,
28+
updated_at_lte=updated_at_lte)
2829

2930
if df.empty:
3031
return pd.DataFrame(columns=columns)
@@ -72,6 +73,104 @@ def login_page():
7273
st.error("用户名或密码错误")
7374

7475

76+
# 生成项目提交数量图表
77+
def generate_project_count_chart(df):
78+
if df.empty:
79+
st.info("没有数据可供展示")
80+
return
81+
82+
# 计算每个项目的提交数量
83+
project_counts = df['project_name'].value_counts().reset_index()
84+
project_counts.columns = ['project_name', 'count']
85+
86+
# 生成颜色列表,每个项目一个颜色
87+
colors = plt.colormaps['tab20'].resampled(len(project_counts))
88+
89+
# 显示提交数量柱状图
90+
fig1, ax1 = plt.subplots(figsize=(10, 6))
91+
ax1.bar(
92+
project_counts['project_name'],
93+
project_counts['count'],
94+
color=[colors(i) for i in range(len(project_counts))]
95+
)
96+
plt.xticks(rotation=45, ha='right', fontsize=26)
97+
plt.tight_layout()
98+
st.pyplot(fig1)
99+
100+
101+
# 生成项目平均分数图表
102+
def generate_project_score_chart(df):
103+
if df.empty:
104+
st.info("没有数据可供展示")
105+
return
106+
107+
# 计算每个项目的平均分数
108+
project_scores = df.groupby('project_name')['score'].mean().reset_index()
109+
project_scores.columns = ['project_name', 'average_score']
110+
111+
# 生成颜色列表,每个项目一个颜色
112+
# colors = plt.cm.get_cmap('Accent', len(project_scores)) # 使用'tab20'颜色映射,适合分类数据
113+
colors = plt.colormaps['Accent'].resampled(len(project_scores))
114+
# 显示平均分数柱状图
115+
fig2, ax2 = plt.subplots(figsize=(10, 6))
116+
ax2.bar(
117+
project_scores['project_name'],
118+
project_scores['average_score'],
119+
color=[colors(i) for i in range(len(project_scores))]
120+
)
121+
plt.xticks(rotation=45, ha='right', fontsize=26)
122+
plt.tight_layout()
123+
st.pyplot(fig2)
124+
125+
126+
# 生成人员提交数量图表
127+
def generate_author_count_chart(df):
128+
if df.empty:
129+
st.info("没有数据可供展示")
130+
return
131+
132+
# 计算每个人员的提交数量
133+
author_counts = df['author'].value_counts().reset_index()
134+
author_counts.columns = ['author', 'count']
135+
136+
# 生成颜色列表,每个项目一个颜色
137+
colors = plt.colormaps['Paired'].resampled(len(author_counts))
138+
# 显示提交数量柱状图
139+
fig1, ax1 = plt.subplots(figsize=(10, 6))
140+
ax1.bar(
141+
author_counts['author'],
142+
author_counts['count'],
143+
color=[colors(i) for i in range(len(author_counts))]
144+
)
145+
plt.xticks(rotation=45, ha='right', fontsize=26)
146+
plt.tight_layout()
147+
st.pyplot(fig1)
148+
149+
150+
# 生成人员平均分数图表
151+
def generate_author_score_chart(df):
152+
if df.empty:
153+
st.info("没有数据可供展示")
154+
return
155+
156+
# 计算每个人员的平均分数
157+
author_scores = df.groupby('author')['score'].mean().reset_index()
158+
author_scores.columns = ['author', 'average_score']
159+
160+
# 显示平均分数柱状图
161+
fig2, ax2 = plt.subplots(figsize=(10, 6))
162+
# 生成颜色列表,每个项目一个颜色
163+
colors = plt.colormaps['Pastel1'].resampled(len(author_scores))
164+
ax2.bar(
165+
author_scores['author'],
166+
author_scores['average_score'],
167+
color=[colors(i) for i in range(len(author_scores))]
168+
)
169+
plt.xticks(rotation=45, ha='right', fontsize=26)
170+
plt.tight_layout()
171+
st.pyplot(fig2)
172+
173+
75174
# 主要内容
76175
def main_page():
77176
st.markdown("#### 审查日志")
@@ -109,7 +208,8 @@ def display_data(tab, service_func, columns, column_config):
109208
with col4:
110209
project_names = st.multiselect("项目名", unique_projects, default=[], key=f"{tab}_projects")
111210

112-
data = get_data(service_func, authors=authors,project_names=project_names, updated_at_gte=int(start_datetime.timestamp()),
211+
data = get_data(service_func, authors=authors, project_names=project_names,
212+
updated_at_gte=int(start_datetime.timestamp()),
113213
updated_at_lte=int(end_datetime.timestamp()), columns=columns)
114214
df = pd.DataFrame(data)
115215

@@ -123,6 +223,21 @@ def display_data(tab, service_func, columns, column_config):
123223
average_score = df["score"].mean() if not df.empty else 0
124224
st.markdown(f"**总记录数:** {total_records},**平均分:** {average_score:.2f}")
125225

226+
# 创建2x2网格布局展示四个图表
227+
row1, row2, row3, row4 = st.columns(4)
228+
with row1:
229+
st.markdown("<div style='text-align: center;'><b>项目提交次数</b></div>", unsafe_allow_html=True)
230+
generate_project_count_chart(df)
231+
with row2:
232+
st.markdown("<div style='text-align: center;'><b>项目平均分数</b></div>", unsafe_allow_html=True)
233+
generate_project_score_chart(df)
234+
with row3:
235+
st.markdown("<div style='text-align: center;'><b>人员提交次数</b></div>", unsafe_allow_html=True)
236+
generate_author_count_chart(df)
237+
with row4:
238+
st.markdown("<div style='text-align: center;'><b>人员平均分数</b></div>", unsafe_allow_html=True)
239+
generate_author_score_chart(df)
240+
126241
# Merge Request 数据展示
127242
mr_columns = ["project_name", "author", "source_branch", "target_branch", "updated_at", "commit_messages", "score",
128243
"url"]

0 commit comments

Comments
 (0)