feat(reportmanage): T11.3 可视化仪表盘 - AppService + Controller + Frontend
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.web.reportmanage.appservice;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IDashboardAppService {
|
||||
R<?> getDashboardData(Map<String, Object> params);
|
||||
R<?> getCharts(Map<String, Object> params);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.healthlink.his.web.reportmanage.appservice.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.basicmanage.domain.DashboardConfig;
|
||||
import com.healthlink.his.basicmanage.service.IDashboardConfigService;
|
||||
import com.healthlink.his.quality.domain.BusinessAnalytics;
|
||||
import com.healthlink.his.quality.service.IBusinessAnalyticsService;
|
||||
import com.healthlink.his.crossmodule.domain.DrgPerformance;
|
||||
import com.healthlink.his.crossmodule.service.IDrgPerformanceService;
|
||||
import com.healthlink.his.mrhomepage.domain.MrDrgGrouping;
|
||||
import com.healthlink.his.mrhomepage.service.IMrDrgGroupingService;
|
||||
import com.healthlink.his.web.reportmanage.appservice.IDashboardAppService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class DashboardAppServiceImpl implements IDashboardAppService {
|
||||
|
||||
private final IDashboardConfigService dashboardConfigService;
|
||||
private final IBusinessAnalyticsService analyticsService;
|
||||
private final IDrgPerformanceService drgPerformanceService;
|
||||
private final IMrDrgGroupingService drgGroupingService;
|
||||
|
||||
@Override
|
||||
public R<?> getDashboardData(Map<String, Object> params) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
|
||||
List<BusinessAnalytics> analyticsList = analyticsService.list();
|
||||
BigDecimal totalRevenue = BigDecimal.ZERO;
|
||||
BigDecimal totalCost = BigDecimal.ZERO;
|
||||
int totalPatients = 0;
|
||||
for (BusinessAnalytics ba : analyticsList) {
|
||||
if (ba.getRevenue() != null) totalRevenue = totalRevenue.add(ba.getRevenue());
|
||||
if (ba.getCost() != null) totalCost = totalCost.add(ba.getCost());
|
||||
if (ba.getPatientCount() != null) totalPatients += ba.getPatientCount();
|
||||
}
|
||||
data.put("totalRevenue", totalRevenue);
|
||||
data.put("totalCost", totalCost);
|
||||
data.put("totalProfit", totalRevenue.subtract(totalCost));
|
||||
data.put("totalPatients", totalPatients);
|
||||
data.put("totalRecords", analyticsList.size());
|
||||
|
||||
LambdaQueryWrapper<DashboardConfig> configW = new LambdaQueryWrapper<>();
|
||||
configW.eq(DashboardConfig::getIsDefault, true);
|
||||
List<DashboardConfig> defaultConfigs = dashboardConfigService.list(configW);
|
||||
data.put("defaultDashboard", defaultConfigs.isEmpty() ? null : defaultConfigs.get(0));
|
||||
|
||||
LambdaQueryWrapper<DrgPerformance> perfW = new LambdaQueryWrapper<>();
|
||||
perfW.orderByDesc(DrgPerformance::getStatMonth).last("LIMIT 1");
|
||||
List<DrgPerformance> latestPerf = drgPerformanceService.list(perfW);
|
||||
if (!latestPerf.isEmpty()) {
|
||||
DrgPerformance p = latestPerf.get(0);
|
||||
data.put("latestDrgCases", p.getTotalCases());
|
||||
data.put("latestCmiValue", p.getCmiValue());
|
||||
data.put("latestCostControlRate", p.getCostControlRate());
|
||||
}
|
||||
|
||||
long totalDrgCases = drgGroupingService.count();
|
||||
data.put("totalDrgCases", totalDrgCases);
|
||||
|
||||
return R.ok(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<?> getCharts(Map<String, Object> params) {
|
||||
Map<String, Object> charts = new HashMap<>();
|
||||
|
||||
List<BusinessAnalytics> analyticsList = analyticsService.list();
|
||||
Map<String, BigDecimal> monthlyRevenue = new LinkedHashMap<>();
|
||||
Map<String, BigDecimal> monthlyCost = new LinkedHashMap<>();
|
||||
for (BusinessAnalytics ba : analyticsList) {
|
||||
String month = ba.getStatDate();
|
||||
if (StringUtils.hasText(month) && month.length() >= 7) {
|
||||
month = month.substring(0, 7);
|
||||
} else {
|
||||
month = "未知";
|
||||
}
|
||||
monthlyRevenue.merge(month, ba.getRevenue() != null ? ba.getRevenue() : BigDecimal.ZERO, BigDecimal::add);
|
||||
monthlyCost.merge(month, ba.getCost() != null ? ba.getCost() : BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
List<Map<String, Object>> revenueChart = new ArrayList<>();
|
||||
monthlyRevenue.forEach((k, v) -> {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("month", k);
|
||||
item.put("revenue", v);
|
||||
item.put("cost", monthlyCost.getOrDefault(k, BigDecimal.ZERO));
|
||||
revenueChart.add(item);
|
||||
});
|
||||
charts.put("revenueChart", revenueChart);
|
||||
|
||||
Map<String, BigDecimal> deptRevenue = analyticsList.stream()
|
||||
.filter(ba -> StringUtils.hasText(ba.getDepartmentName()))
|
||||
.collect(Collectors.groupingBy(
|
||||
BusinessAnalytics::getDepartmentName,
|
||||
Collectors.reducing(BigDecimal.ZERO, ba -> ba.getRevenue() != null ? ba.getRevenue() : BigDecimal.ZERO, BigDecimal::add)));
|
||||
List<Map<String, Object>> deptChart = new ArrayList<>();
|
||||
deptRevenue.forEach((k, v) -> {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("department", k);
|
||||
item.put("revenue", v);
|
||||
deptChart.add(item);
|
||||
});
|
||||
charts.put("departmentChart", deptChart);
|
||||
|
||||
LambdaQueryWrapper<DrgPerformance> perfW = new LambdaQueryWrapper<>();
|
||||
perfW.orderByAsc(DrgPerformance::getStatMonth);
|
||||
List<DrgPerformance> perfList = drgPerformanceService.list(perfW);
|
||||
List<Map<String, Object>> cmiChart = new ArrayList<>();
|
||||
for (DrgPerformance p : perfList) {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("month", p.getStatMonth());
|
||||
item.put("cmiValue", p.getCmiValue());
|
||||
item.put("costControlRate", p.getCostControlRate());
|
||||
item.put("totalCases", p.getTotalCases());
|
||||
cmiChart.add(item);
|
||||
}
|
||||
charts.put("cmiChart", cmiChart);
|
||||
|
||||
return R.ok(charts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.healthlink.his.web.reportmanage.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.web.reportmanage.appservice.IDashboardAppService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/dashboard")
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class DashboardDataController {
|
||||
|
||||
private final IDashboardAppService dashboardAppService;
|
||||
|
||||
@GetMapping("/data")
|
||||
@PreAuthorize("hasAuthority('infection:report:list')")
|
||||
public R<?> getDashboardData(@RequestParam(required = false) String dashboardType) {
|
||||
Map<String, Object> params = new java.util.HashMap<>();
|
||||
params.put("dashboardType", dashboardType);
|
||||
return dashboardAppService.getDashboardData(params);
|
||||
}
|
||||
|
||||
@GetMapping("/charts")
|
||||
@PreAuthorize("hasAuthority('infection:report:list')")
|
||||
public R<?> getCharts(@RequestParam(required = false) String dashboardType) {
|
||||
Map<String, Object> params = new java.util.HashMap<>();
|
||||
params.put("dashboardType", dashboardType);
|
||||
return dashboardAppService.getCharts(params);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
export function getDashboardOverview(){return request({url:'/dashboard/overview',method:'get'})}
|
||||
export function getDashboardList(p){return request({url:'/dashboard/list',method:'get',params:p})}
|
||||
export function getDashboardData(p){return request({url:'/dashboard/data',method:'get',params:p})}
|
||||
export function getDashboardCharts(p){return request({url:'/dashboard/charts',method:'get',params:p})}
|
||||
|
||||
@@ -62,6 +62,42 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 数据仪表盘 -->
|
||||
<el-row :gutter="16" style="margin-bottom:16px" v-if="dashData.totalRecords > 0">
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" :body-style="{padding:'12px'}">
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:20px;font-weight:bold;color:#409eff">{{ formatMoney(dashData.totalRevenue) }}</div>
|
||||
<div style="font-size:12px;color:#999">总收入(万)</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" :body-style="{padding:'12px'}">
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:20px;font-weight:bold;color:#67c23a">{{ formatMoney(dashData.totalProfit) }}</div>
|
||||
<div style="font-size:12px;color:#999">总利润(万)</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" :body-style="{padding:'12px'}">
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:20px;font-weight:bold;color:#e6a23c">{{ dashData.totalPatients || 0 }}</div>
|
||||
<div style="font-size:12px;color:#999">总患者数</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" :body-style="{padding:'12px'}">
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:20px;font-weight:bold;color:#f56c6c">{{ dashData.totalDrgCases || 0 }}</div>
|
||||
<div style="font-size:12px;color:#999">DRG病例数</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 功能模块 -->
|
||||
<el-card
|
||||
shadow="never"
|
||||
@@ -185,9 +221,10 @@
|
||||
<script setup>
|
||||
import {ref, onMounted} from 'vue'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {getDashboardOverview} from './api'
|
||||
import {getDashboardOverview, getDashboardData, getDashboardCharts} from './api'
|
||||
|
||||
const overview = ref({})
|
||||
const dashData = ref({})
|
||||
const showSystemInfo = ref(false)
|
||||
|
||||
const statCards = ref([
|
||||
@@ -231,10 +268,16 @@ const recentLogs = ref([
|
||||
{content:'危急值处理完成', time:'20分钟前', type:'danger'}
|
||||
])
|
||||
|
||||
function formatMoney(val) {
|
||||
if (!val) return '0.00'
|
||||
return (val / 10000).toFixed(2)
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const r = await getDashboardOverview()
|
||||
const [r, d] = await Promise.all([getDashboardOverview(), getDashboardData()])
|
||||
overview.value = r.data || {}
|
||||
dashData.value = d.data || {}
|
||||
statCards.value[0].value = overview.value.totalTables || 0
|
||||
statCards.value[1].value = overview.value.totalApis || 0
|
||||
statCards.value[2].value = modules.value.length
|
||||
|
||||
Reference in New Issue
Block a user