@app.route('/data/risk', methods=['GET'])
def risk_data():
return merged_df_jsonfrom datetime import datetime
import pandas as pd
from bp import output_data
from pe import original_df
from hrc import hr_res
import json
import pprint
import numpy as np
hr_res = hr_res[(hr_res['年份'] >= 2025) | ((hr_res['年份'] >= 2024) & (hr_res['月份'] >= 7))]
original_df = original_df[['emp_id', 'name', '年月', 'ldept', 'findings', '异常项目详情', '异常数量', '分析意见', '可能疾病']]
hr_res = hr_res[['年月', '员工总数']]
hr_pe = pd.merge(
hr_res,
original_df,
left_on=['年月'],
right_on=['年月'],
how='outer'
)
# hr_pe.to_excel("temp/hr_pe.xlsx", index=False)
all_records = []
for emp_info in output_data['employees'].values():
employee_id = emp_info['employee_id']
department = emp_info['department']
name = emp_info['name']
# 遍历该员工的所有记录
for record in emp_info['records']:
record['employee_id'] = employee_id
record['department'] = department
record['name'] = name
all_records.append(record)
df_emp = pd.DataFrame(all_records)
df_emp['employee_id'] = df_emp['employee_id'].astype(float)
# 将日期列转换为datetime类型以便排序
df_emp['date'] = pd.to_datetime(df_emp['date'], errors='coerce')
# 每个人每年月只保留最新的一条数据
df_emp = df_emp.sort_values(['year_month', 'employee_id', 'date'], ascending=[True, True, False])
df_emp = df_emp.groupby(['year_month', 'employee_id']).first().reset_index()
# df_emp.to_excel("temp/df_emp.xlsx", index=False)
hr_bp = pd.merge(
hr_res,
df_emp,
left_on=['年月'],
right_on=['year_month'],
how='outer'
)
# hr_bp.to_excel("temp/hr_bp.xlsx", index=False)
# 合并数据
merged_df = pd.merge(
hr_pe,
hr_bp,
left_on=['年月', '员工总数', 'emp_id'],
right_on=['年月', '员工总数', 'employee_id'],
how='outer'
)
# 打印合并后的结果
# print(merged_df)
# 定义健康等级函数
def assign_health_level(row):
bp_level = row['bp_level']
bmi_level = row['bmi_level']
if bp_level in ["二级高血压(中度)", "三级高血压(重度)"]:
return '风险'
elif bp_level == "正常血压" and bmi_level == "正常" and (row['异常项目详情'] == "无异常"):
return '健康'
elif bp_level in ["正常高值", "一级高血压(轻度)"] or bmi_level in ["较瘦", "超重"] or (row['异常项目详情'] != "无异常"):
return '亚健康'
return '亚健康'
merged_df = merged_df[~(merged_df['ldept'].isna() & merged_df['department'].isna())]
# 应用健康等级分类
merged_df['健康等级'] = merged_df.apply(assign_health_level, axis=1)
merged_df.to_excel("temp/表格数据.xlsx", index=False)
# 按年月统计各级别人数
monthly_stats = merged_df.groupby(['year_month', '健康等级']).size().unstack(fill_value=0)
# monthly_stats.to_excel("temp/monthly_health_stats.xlsx")
# 按年月统计量测人数(去重后)
grouped_data = merged_df.groupby('year_month').size().reset_index(name='量测人数')
# grouped_data.to_excel("temp/grouped_data.xlsx")
# 按年份和月份分组统计血压分级
bp_grouped = merged_df.groupby(['year_month', 'bp_level']).size().reset_index(name='员工数量')
bp_pivot = bp_grouped.pivot_table(
index='year_month',
columns='bp_level',
values='员工数量',
fill_value=0
).reset_index()
# 按年份和月份分组统计BMI分级
bmi_grouped = merged_df.groupby(['year_month', 'bmi_level']).size().reset_index(name='员工数量')
bmi_pivot = bmi_grouped.pivot_table(
index='year_month',
columns='bmi_level',
values='员工数量',
fill_value=0
).reset_index()
# merged_df_sorted = merged_df.sort_values(by='year_month', ascending=False)
# merged_df_sorted.to_excel("temp/merged_df.xlsx", index=False)
for col in merged_df.select_dtypes(include=['datetime64']).columns:
merged_df[col] = merged_df[col].astype(str)
merged_df = merged_df.where(pd.notnull(merged_df), None)
merged_df['employee_id'] = merged_df['employee_id'].fillna(0).astype(int).astype(str)
# merged_df.to_excel("temp/merged_df.xlsx", index=False)
merged_df_json = merged_df.to_json(orient='records', force_ascii=False, date_format='iso')
# 合并数据
merged_data = pd.merge(
left=grouped_data,
right=bp_pivot,
on='year_month',
how='left'
)
merged_data = pd.merge(
left=merged_data,
right=bmi_pivot,
on='year_month',
how='left'
)
# 合并HR数据(员工总数)
merged_data = pd.merge(
left=merged_data,
right=hr_res,
left_on='year_month',
right_on='年月',
how='left'
)
# 填充缺失值
merged_data.fillna(0, inplace=True)
# 计算量测率
merged_data['量测率'] = merged_data['量测人数'] / merged_data['员工总数']
merged_data.loc[merged_data['员工总数'] == 0, '量测率'] = 0
# 确保所有血压分级列都存在
blood_columns = ['正常血压', '正常高值', '一级高血压(轻度)', '二级高血压(中度)', '三级高血压(重度)']
for col in blood_columns:
if col not in merged_data.columns:
merged_data[col] = 0
# 确保所有BMI分级列都存在
bmi_columns = ['较瘦', '正常', '超重', '肥胖']
for col in bmi_columns:
if col not in merged_data.columns:
merged_data[col] = 0
# 标记体检记录
merged_df['体检标记'] = merged_df['emp_id'].notna().astype(int)
# 标记异常记录(分析意见非空且不为空字符串)
# merged_df['异常标记'] = merged_df['分析意见'].apply(lambda x: 1 if x and str(x).strip() not in ['', '[]'] else 0)
merged_df['异常标记'] = merged_df.apply(lambda row:
1 if (row['体检标记'] == 1 and row['异常项目详情'] not in ['', '无异常']) else
0 if (row['体检标记'] == 1 and row['异常项目详情'] in ['', '无异常']) else 0, axis=1)
# merged_df.to_excel("temp/merged_df2.xlsx", index=False)
# 按年月分组统计
pe_stats = merged_df.groupby('年月').agg(
体检人数=('体检标记', 'sum'), # 统计体检人数
异常人数=('异常标记', 'sum') # 统计异常人数
).reset_index()
pe_stats = pe_stats.rename(columns={'年月': 'year_month'})
# 计算异常率
pe_stats['异常率'] = pe_stats['异常人数'] / pe_stats['体检人数']
all_data1 = pd.merge(
left=merged_data,
right=monthly_stats,
left_on='year_month',
right_on='year_month',
how='outer'
)
all_data = pd.merge(
left=all_data1,
right=pe_stats,
left_on='year_month',
right_on='year_month',
how='outer'
)
all_data_sorted = all_data.sort_values(by='year_month', ascending=False)
all_data_sorted = all_data_sorted.fillna(0)
# all_data_sorted.to_excel("temp/all_data.xlsx", index=False)
# 转换为json
for col in all_data_sorted.select_dtypes(include=['datetime64']).columns:
all_data_sorted[col] = all_data_sorted[col].astype(str)
all_data_sorted = all_data_sorted.where(pd.notnull(all_data), None)
all_data_json = all_data_sorted.to_json(orient='records', force_ascii=False, date_format='iso')
# print(all_data_json)
# 统一部门信息(优先使用体检数据中的大部门,若为空则使用血压数据中的部门)
merged_df['统一部门'] = merged_df['ldept'].combine_first(merged_df['department'])
# 按年月、统一部门、健康等级分组统计人数
dept_health_stats = (
merged_df.groupby(['year_month', '统一部门', '健康等级'])
.size()
.unstack(fill_value=0)
.reset_index()
)
dept_health_stats.to_excel("temp/柱状图.xlsx", index=False)
# 处理缺失的健康等级列(确保所有等级都存在)
for level in ['健康', '亚健康', '风险']:
if level not in dept_health_stats.columns:
dept_health_stats[level] = 0
# 重命名列并转换数据类型
dept_health_stats = dept_health_stats.rename(columns={
'year_month': '年月',
'统一部门': '部门'
})[['年月', '部门', '健康', '亚健康', '风险']]
# 转换为JSON格式(按年月分组)
json_output = {}
for (year_month, group) in dept_health_stats.groupby('年月'):
# 转换部门数据为字典列表
departments = group.drop(columns='年月').to_dict('records')
# 添加到结果字典
json_output[str(year_month)] = departments
final_json = json.dumps(json_output, indent=2, ensure_ascii=False)
# print(final_json)
function updateRiskTable(yearMonth, level, dept = null) {
const currentUser = window.currentUser || { role: 'user', dept: 'all' };
const userRole = currentUser.role;
const userDept = currentUser.dept;
// 如果不是 admin,隐藏整个表格区域并提示
if (userRole !== 'admin') {
riskTable.innerHTML = `
<tr>
<td colspan="7" class="text-center text-muted">
<i class="fas fa-lock me-2"></i>
您没有权限查看详细人员名单
</td>
</tr>
`;
tableTitle.textContent = `${yearMonth} ${level}人员明细`;
return;
}
// admin 用户:允许查看指定部门
let filterDept = dept;
if (userDept === 'all') {
// dept=all 的 admin 可以查看任何部门(包括全部)
filterDept = dept || 'all'; // 若未选,则视为“全部”
} else {
// 非 all 的 admin 只能查看自己部门
filterDept = userDept;
}
// 过滤数据
let filteredData = riskData.filter(item =>
item.year_month === yearMonth &&
item.健康等级 === level
);
// 再次按部门过滤
if (filterDept !== 'all') {
filteredData = filteredData.filter(item => item.department === filterDept);
}
// 更新标题
const displayDept = filterDept === 'all' ? '全部部门' : filterDept;
tableTitle.textContent = `${yearMonth} ${level}人员明细 (${displayDept})`;
// 清空表格
riskTable.innerHTML = '';
if (filteredData.length === 0) {
riskTable.innerHTML = `<tr><td colspan="7" class="text-center">当前时间段无${level}人员数据</td></tr>`;
return;
}
// 创建表头
const headerRow = document.createElement('tr');
const headers = ['工号', '姓名', '部门', '血压等级', 'BMI等级', '体检结果', '健康等级'];
headers.forEach(headerText => {
const th = document.createElement('th');
th.textContent = headerText;
headerRow.appendChild(th);
});
riskTable.appendChild(headerRow);
// 添加数据行
filteredData.forEach(item => {
const row = document.createElement('tr');
const fields = ['employee_id', 'name', 'department', 'bp_level', 'bmi_level', '检查结果', '健康等级'];
fields.forEach(field => {
const cell = document.createElement('td');
cell.textContent = safeDisplay(item[field]);
row.appendChild(cell);
});
riskTable.appendChild(row);
});
}
最新发布