unified_dashboard/wwwroot/api/dashboard_kpi.dspy
yumoqing aec650dcef sync: local modifications to unified_dashboard
- Updated core.py, init.py, mysql.ddl.sql
- Added __init__.py
- Added API files: dashboard_kpi, report_list
- Added UI files: base.ui, dashboard.ui, reports.ui
2026-04-28 18:55:07 +08:00

85 lines
3.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Dashboard KPI and chart data API"""
import json
result = {'success': False, 'rows': [], 'total': 0}
try:
kpi_type = params_kw.get('type', '').strip()
if kpi_type == 'sales_funnel':
dbname = get_module_dbname('opportunity_management')
async with DBPools().sqlorContext(dbname) as sor:
stages = await sor.sqlExe("SELECT id, stage_name, stage_order FROM sales_stages ORDER BY stage_order ASC")
funnel_data = []
for stage in stages:
rows = await sor.sqlExe("SELECT COUNT(*) as cnt, COALESCE(SUM(estimated_amount),0) as amt FROM opportunities WHERE current_stage = ${stage_id}$", {'stage_id': stage['id']})
funnel_data.append({
'stage': stage['stage_name'],
'count': rows[0]['cnt'] if rows else 0,
'amount': float(rows[0]['amt'] or 0) if rows else 0
})
result['rows'] = funnel_data
result['total'] = len(funnel_data)
result['success'] = True
elif kpi_type == 'recent_opportunities':
dbname = get_module_dbname('opportunity_management')
async with DBPools().sqlorContext(dbname) as sor:
rows = await sor.sqlExe("SELECT customer_name, estimated_amount, current_stage FROM opportunities ORDER BY created_at DESC LIMIT 10")
result['rows'] = [dict(r) for r in (rows or [])]
result['total'] = len(result['rows'])
result['success'] = True
elif kpi_type == 'kpi_summary':
# Aggregate KPIs from all modules
kpis = {}
# Customer count
try:
dbname = get_module_dbname('customer_management')
async with DBPools().sqlorContext(dbname) as sor:
rows = await sor.sqlExe("SELECT COUNT(*) as cnt FROM customers")
kpis['total_customers'] = rows[0]['cnt'] if rows else 0
except:
kpis['total_customers'] = 0
# Active opportunities
try:
dbname = get_module_dbname('opportunity_management')
async with DBPools().sqlorContext(dbname) as sor:
rows = await sor.sqlExe("SELECT COUNT(*) as cnt FROM opportunities WHERE status = 'active'")
kpis['active_opportunities'] = rows[0]['cnt'] if rows else 0
except:
kpis['active_opportunities'] = 0
# Contract count
try:
dbname = get_module_dbname('contract_management')
async with DBPools().sqlorContext(dbname) as sor:
rows = await sor.sqlExe("SELECT COUNT(*) as cnt FROM contract")
kpis['total_contracts'] = rows[0]['cnt'] if rows else 0
except:
kpis['total_contracts'] = 0
# Total receivables
try:
dbname = get_module_dbname('financial_management')
async with DBPools().sqlorContext(dbname) as sor:
rows = await sor.sqlExe("SELECT COALESCE(SUM(receivable_amount),0) as total FROM receivables")
kpis['total_receivables'] = float(rows[0]['total'] or 0) if rows else 0
except:
kpis['total_receivables'] = 0
result['success'] = True
result['data'] = kpis
else:
result['error'] = f'Unknown KPI type: {kpi_type}'
except Exception as e:
result['error'] = str(e)
return json.dumps(result, ensure_ascii=False, default=str)