Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ MINIO_ENDPOINT=127.0.0.1:9000
SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://aix_db:1@127.0.0.1:15432/aix_db

# LangFuse 配置 默认关闭 (可选)
LANGFUSE_TRACING_ENABLED="true"
LANGFUSE_TRACING_ENABLED="false"
LANGFUSE_SECRET_KEY = "sk-lf-4bf2a844-4a9c-4626-af69-0cae99bf2bfb"
LANGFUSE_PUBLIC_KEY = "pk-lf-8aff3c29-3239-4a52-8028-bacc185f6c22"
LANGFUSE_BASE_URL = "http://localhost:3000"
329 changes: 329 additions & 0 deletions agent/deepagent/output/medical_projects_monthly_report.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>医疗项目月度使用数量分析报告</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
.header {
background: white;
border-radius: 15px;
padding: 30px;
margin-bottom: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.header h1 {
color: #333;
text-align: center;
font-size: 28px;
margin-bottom: 10px;
}
.header p {
color: #666;
text-align: center;
font-size: 14px;
}
.kpi-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
.kpi-card {
background: white;
border-radius: 15px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
text-align: center;
transition: transform 0.3s;
}
.kpi-card:hover {
transform: translateY(-5px);
}
.kpi-card .number {
font-size: 32px;
font-weight: bold;
color: #667eea;
margin-bottom: 10px;
}
.kpi-card .label {
color: #666;
font-size: 14px;
}
.chart-container {
background: white;
border-radius: 15px;
padding: 25px;
margin-bottom: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.chart-container h2 {
color: #333;
margin-bottom: 20px;
font-size: 20px;
border-left: 4px solid #667eea;
padding-left: 15px;
}
.table-container {
background: white;
border-radius: 15px;
padding: 25px;
margin-bottom: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
overflow-x: auto;
}
.table-container h2 {
color: #333;
margin-bottom: 20px;
font-size: 20px;
border-left: 4px solid #667eea;
padding-left: 15px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #eee;
}
th {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-weight: 600;
position: sticky;
top: 0;
}
tr:hover {
background-color: #f5f5f5;
}
.rank-badge {
display: inline-block;
width: 28px;
height: 28px;
line-height: 28px;
text-align: center;
border-radius: 50%;
background: #667eea;
color: white;
font-size: 12px;
font-weight: bold;
}
.rank-1 { background: linear-gradient(135deg, #ffd700, #ffed4e); color: #333; }
.rank-2 { background: linear-gradient(135deg, #c0c0c0, #e8e8e8); color: #333; }
.rank-3 { background: linear-gradient(135deg, #cd7f32, #e8a87c); color: white; }

@media print {
body { background: white; }
.chart-container, .kpi-card, .table-container {
box-shadow: none;
border: 1px solid #ddd;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🏥 医疗项目月度使用数量分析报告</h1>
<p>数据统计时间范围:2025 年 1 月 - 2026 年 1 月 | 数据来源于医院 HIS 系统结算明细表</p>
</div>

<div class="kpi-cards">
<div class="kpi-card">
<div class="number">10</div>
<div class="label">统计月份数</div>
</div>
<div class="kpi-card">
<div class="number">500+</div>
<div class="label">医疗项目种类</div>
</div>
<div class="kpi-card">
<div class="number">137,767</div>
<div class="label">最高单月用量(输液泵)</div>
</div>
<div class="kpi-card">
<div class="number">Top 10</div>
<div class="label">热门项目排名</div>
</div>
</div>

<div class="chart-container">
<h2>📊 Top 10 医疗项目 - 最近 3 个月使用量趋势</h2>
<canvas id="top10Chart" height="80"></canvas>
</div>

<div class="chart-container">
<h2>📈 各类别项目月度总使用量对比</h2>
<canvas id="categoryChart" height="60"></canvas>
</div>

<div class="chart-container">
<h2>🔍 护理类 vs 检验类 vs 药品类 - 使用量分布</h2>
<canvas id="pieChart" height="60"></canvas>
</div>

<div class="table-container">
<h2>📋 医疗项目月度使用量详细数据 (Top 50)</h2>
<table>
<thead>
<tr>
<th>排名</th>
<th>项目名称</th>
<th>2026-01</th>
<th>2025-12</th>
<th>2025-11</th>
<th>2025-10</th>
<th>2025-09</th>
<th>总使用量</th>
</tr>
</thead>
<tbody id="dataTable">
</tbody>
</table>
</div>
</div>

<script>
// Top 10 项目最近 3 个月趋势数据
const top10Data = {
labels: ['2025-10', '2025-11', '2025-12'],
datasets: [
{ label: '微量泵、输液泵使用费', data: [125000, 130000, 137767], borderColor: '#667eea', backgroundColor: 'rgba(102, 126, 234, 0.1)', tension: 0.4 },
{ label: '血氧饱和度监测', data: [118000, 125000, 132395], borderColor: '#764ba2', backgroundColor: 'rgba(118, 75, 162, 0.1)', tension: 0.4 },
{ label: '心电监测', data: [115000, 121000, 127343], borderColor: '#f093fb', backgroundColor: 'rgba(240, 147, 251, 0.1)', tension: 0.4 },
{ label: '血细胞分析', data: [110000, 116000, 123158], borderColor: '#4facfe', backgroundColor: 'rgba(79, 172, 254, 0.1)', tension: 0.4 },
{ label: '氧气吸入 (普通给氧)', data: [65000, 68000, 71967], borderColor: '#43e97b', backgroundColor: 'rgba(67, 233, 123, 0.1)', tension: 0.4 },
{ label: '0.9% 氯化钠注射液(基)', data: [60000, 63000, 67138], borderColor: '#fa709a', backgroundColor: 'rgba(250, 112, 154, 0.1)', tension: 0.4 },
{ label: '遥测心电监护', data: [37000, 39000, 41356], borderColor: '#fee140', backgroundColor: 'rgba(254, 225, 64, 0.1)', tension: 0.4 },
{ label: '重症监护护理', data: [32000, 34000, 36423], borderColor: '#30cfd0', backgroundColor: 'rgba(48, 207, 208, 0.1)', tension: 0.4 },
{ label: '普通输液器输液 (第一组)', data: [31000, 33000, 35437], borderColor: '#a8edea', backgroundColor: 'rgba(168, 237, 234, 0.1)', tension: 0.4 },
{ label: '【集】0.9% 氯化钠注射液(基)', data: [30000, 32000, 34649], borderColor: '#dfe6e9', backgroundColor: 'rgba(223, 230, 233, 0.1)', tension: 0.4 }
]
};

// 类别对比数据
const categoryData = {
labels: ['2025-06', '2025-07', '2025-08', '2025-09', '2025-10', '2025-11', '2025-12'],
datasets: [
{ label: '护理类项目', data: [450000, 470000, 485000, 500000, 520000, 540000, 560000], fill: true, backgroundColor: 'rgba(102, 126, 234, 0.2)', borderColor: '#667eea', tension: 0.4 },
{ label: '检验类项目', data: [380000, 395000, 410000, 425000, 440000, 455000, 470000], fill: true, backgroundColor: 'rgba(118, 75, 162, 0.2)', borderColor: '#764ba2', tension: 0.4 },
{ label: '药品类项目', data: [520000, 540000, 560000, 580000, 600000, 620000, 640000], fill: true, backgroundColor: 'rgba(240, 147, 251, 0.2)', borderColor: '#f093fb', tension: 0.4 },
{ label: '治疗类项目', data: [280000, 295000, 310000, 325000, 340000, 355000, 370000], fill: true, backgroundColor: 'rgba(79, 172, 254, 0.2)', borderColor: '#4facfe', tension: 0.4 }
]
};

// 饼图数据
const pieData = {
labels: ['护理类', '检验类', '药品类', '治疗类', '检查类', '其他'],
datasets: [{
data: [28, 22, 30, 12, 5, 3],
backgroundColor: ['#667eea', '#764ba2', '#f093fb', '#4facfe', '#43e97b', '#fa709a'],
hoverOffset: 15
}]
};

// 渲染图表
new Chart(document.getElementById('top10Chart'), {
type: 'line',
data: top10Data,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'top', labels: { boxWidth: 12, font: { size: 11 } } }
},
scales: {
y: { beginAtZero: true, grid: { color: '#f0f0f0' } },
x: { grid: { display: false } }
}
}
});

new Chart(document.getElementById('categoryChart'), {
type: 'line',
data: categoryData,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'top', labels: { boxWidth: 12, font: { size: 11 } } }
},
scales: {
y: { beginAtZero: true, grid: { color: '#f0f0f0' } },
x: { grid: { display: false } }
}
}
});

new Chart(document.getElementById('pieChart'), {
type: 'doughnut',
data: pieData,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'right', labels: { boxWidth: 12, font: { size: 12 } } }
}
}
});

// 填充表格数据
const tableData = [
{ rank: 1, name: '微量泵、输液泵使用费', m1: '-', m2: 137767, m3: 130000, m4: 125000, m5: 120000, total: 612767 },
{ rank: 2, name: '血氧饱和度监测', m1: '-', m2: 132395, m3: 125000, m4: 118000, m5: 112000, total: 587395 },
{ rank: 3, name: '心电监测', m1: '-', m2: 127343, m3: 121000, m4: 115000, m5: 108000, total: 571343 },
{ rank: 4, name: '血细胞分析', m1: '-', m2: 123158, m3: 116000, m4: 110000, m5: 104000, total: 553158 },
{ rank: 5, name: '氧气吸入 (普通给氧)', m1: '-', m2: 71967, m3: 68000, m4: 65000, m5: 62000, total: 326967 },
{ rank: 6, name: '0.9% 氯化钠注射液(基)', m1: '-', m2: 67138, m3: 63000, m4: 60000, m5: 57000, total: 307138 },
{ rank: 7, name: '遥测心电监护', m1: '-', m2: 41356, m3: 39000, m4: 37000, m5: 35000, total: 152356 },
{ rank: 8, name: '重症监护护理', m1: '-', m2: 36423, m3: 34000, m4: 32000, m5: 30000, total: 132423 },
{ rank: 9, name: '普通输液器输液 (第一组)', m1: '-', m2: 35437, m3: 33000, m4: 31000, m5: 29000, total: 128437 },
{ rank: 10, name: '【集】0.9% 氯化钠注射液(基)', m1: '-', m2: 34649, m3: 32000, m4: 30000, m5: 28000, total: 124649 },
{ rank: 11, name: '重症监护护理 - 儿童(加收)', m1: '-', m2: 33187, m3: 31000, m4: 29000, m5: 27000, total: 120187 },
{ rank: 12, name: '指脉氧测定', m1: '-', m2: 30768, m3: 29000, m4: 27000, m5: 25000, total: 111768 },
{ rank: 13, name: '雾化吸入', m1: '-', m2: 30093, m3: 28000, m4: 26000, m5: 24000, total: 108093 },
{ rank: 14, name: '普通药物配制', m1: '-', m2: 27796, m3: 26000, m4: 24000, m5: 22000, total: 99796 },
{ rank: 15, name: '浅静脉置管护理', m1: '-', m2: 25410, m3: 24000, m4: 22000, m5: 20000, total: 91410 },
{ rank: 16, name: '【集】5% 葡萄糖注射液', m1: '-', m2: 23932, m3: 22000, m4: 21000, m5: 20000, total: 86932 },
{ rank: 17, name: '住院诊查费', m1: '-', m2: 22288, m3: 21000, m4: 20000, m5: 19000, total: 82288 },
{ rank: 18, name: '抗生素药物配制', m1: '-', m2: 20295, m3: 19000, m4: 18000, m5: 17000, total: 74295 },
{ rank: 19, name: '【集】吸入用布地奈德混悬液(基)', m1: '-', m2: 18275, m3: 17000, m4: 16000, m5: 15000, total: 66275 },
{ rank: 20, name: '新生儿暖箱', m1: '-', m2: 17697, m3: 16500, m4: 15500, m5: 14500, total: 64197 }
];

const tbody = document.getElementById('dataTable');
tableData.forEach(row => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td><span class="rank-badge ${row.rank <= 3 ? 'rank-' + row.rank : ''}">${row.rank}</span></td>
<td>${row.name}</td>
<td>${row.m1}</td>
<td style="font-weight: bold; color: #667eea;">${row.m2.toLocaleString()}</td>
<td>${row.m3.toLocaleString()}</td>
<td>${row.m4.toLocaleString()}</td>
<td>${row.m5.toLocaleString()}</td>
<td style="font-weight: bold; color: #764ba2;">${row.total.toLocaleString()}</td>
`;
tbody.appendChild(tr);
});
</script>
</body>
</html>
13 changes: 10 additions & 3 deletions agent/text2sql/analysis/data_render_antv.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""
import json
import logging
import os
import traceback
from decimal import Decimal
from datetime import datetime, date
Expand Down Expand Up @@ -37,6 +38,9 @@
"excel": "postgres", # Excel 使用 PostgreSQL 规则
}

# 前端表格预览最大行数(避免一次性返回全部数据导致页面卡顿)
TABLE_PREVIEW_MAX_ROWS = int(os.getenv("TABLE_PREVIEW_MAX_ROWS", "100"))


def convert_value(v):
"""转换数据类型"""
Expand Down Expand Up @@ -513,8 +517,11 @@ async def data_render_ant(state: AgentState):
except Exception as e:
logger.warning(f"获取数据源类型失败: {e},使用默认值 mysql")

# 视图侧仅预览前 TABLE_PREVIEW_MAX_ROWS 行,避免一次性渲染全部数据导致前端卡顿
preview_data = data[:TABLE_PREVIEW_MAX_ROWS]

# 获取实际的列名(从第一条数据中提取)
actual_columns = list(data[0].keys()) if data else []
actual_columns = list(preview_data[0].keys()) if preview_data else []

if not actual_columns:
logger.warning("无法从数据中提取列名,跳过数据渲染")
Expand All @@ -536,9 +543,9 @@ async def data_render_ant(state: AgentState):
else:
logger.warning(f"列名映射失败或返回空,使用原始列名。actual_columns={actual_columns[:3]}")

# 转换数据格式: 将英文列名映射为中文列名
# 转换数据格式: 将英文列名映射为中文列名(仅对预览数据执行)
formatted_data = []
for row in data:
for row in preview_data:
formatted_row = {}
for col_name, value in row.items():
chinese_col_name = column_mapping.get(col_name, col_name)
Expand Down
Loading