1
0
lsw 1 день назад
Родитель
Сommit
bdd8763495

+ 3 - 3
admin-ui/src/views/dashboard/BarChart.vue

@@ -77,7 +77,7 @@ export default {
 			if (chartData) {
 				chartData.forEach((item, index) => {
 					xAxisData.push(item.name + '月份');
-					seriesData.push(item.value?item.value.toFixed(2):'');
+					seriesData.push(item.value);
 				});
 			}
 			this.chart.setOption({
@@ -87,7 +87,7 @@ export default {
 					axisPointer: {
 						type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
 					},
-					formatter: '{b} : {c}'
+					formatter: '{b} : {c}'
 				},
 				grid: {
 					top: '10%',
@@ -166,7 +166,7 @@ export default {
 										color: '#545555',
 										fontSize: 14
 									},
-                  formatter: '{c}'
+                  formatter: '{c}'
 								}
 							}
 						}

+ 146 - 0
admin-ui/src/views/dashboard/BarChart2.vue

@@ -0,0 +1,146 @@
+<template>
+  <div :class="className" :style="{ height: height, width: width }" />
+</template>
+
+<script>
+import echarts from 'echarts';
+require('echarts/theme/macarons'); // echarts theme
+import resize from './mixins/resize';
+
+const animationDuration = 6000;
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    type: {
+      type: String,
+      default: 'bar'
+    },
+    rotate: {
+      type: Number,
+      default: 0
+    },
+    legend: {
+      type: Array,
+      default: () => ['']
+    },
+    barWidth: {
+      type: String,
+      default: '15px'
+    },
+    chartData: {
+      type: Array,
+      required: true
+    },
+    height: {
+      type: String,
+      default: '240px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    };
+  },
+  watch: {
+    chartData: {
+      deep: true,
+      handler(val) {
+        this.setOptions(val);
+      }
+    },
+    type: {
+      deep: true,
+      handler(val) {
+        this.setOptions(this.chartData);
+      }
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return;
+    }
+    this.chart.dispose();
+    this.chart = null;
+  },
+  methods: {
+    initChart() {
+      setTimeout(() => {
+        this.chart = echarts.init(this.$el, 'macarons');
+        this.setOptions(this.chartData);
+      }, 300);
+    },
+    setOptions(chartData) {
+      let series = [];
+      let legendData = [];
+      let yAxis = [];
+      let data = [];
+      chartData.forEach((item) => {
+        yAxis.unshift(item.name);
+        data.unshift(item.value);
+      });
+
+      this.chart.setOption({
+        color: ['rgba(37, 97, 239, 1)'],
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          }
+        },
+        grid: {
+          top: '0%',
+          left: '1%',
+          right: '1%',
+          bottom: '1%',
+          containLabel: true,
+          show: false
+        },
+        xAxis: {
+          type: 'value',
+          axisLine: {
+            lineStyle: {
+              color: '#e6e6e6'
+            }
+          }
+        },
+        yAxis: {
+          type: 'category',
+          data: yAxis,
+          axisLine: {
+            lineStyle: {
+              color: '#909090'
+            }
+          }
+        },
+        series: [
+          {
+            type: 'bar',
+            barWidth: this.barWidth,
+            data: data,
+            itemStyle: {
+              normal: {
+                opacity: 1,
+                barBorderRadius: [0, 0, 0, 0]
+              }
+            }
+          }
+        ]
+      });
+    }
+  }
+};
+</script>

+ 34 - 0
admin-ui/src/views/work/statistics/department.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="app-container" style="overflow-y: auto;">
+    <div class="bos">
+      <div class="lab">
+        <div class="bsg"></div>
+        <div class="tit">按科室随访排行统计</div>
+      </div>
+      <BarChart :chartData="chartData" height="6500px"></BarChart>
+    </div>
+  </div>
+</template>
+
+<script>
+import BarChart from '@/views/dashboard/BarChart2';
+export default {
+  components: { BarChart },
+  data() {
+    return {
+      chartData: [],
+      queryParams: {}
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    getList() {
+      this.ajax({ url: '/work/statistics/selectByDepartment', data: this.queryParams }).then((response) => {
+        this.chartData = response.data.data;
+      });
+    }
+  }
+};
+</script>

+ 34 - 0
admin-ui/src/views/work/statistics/doctor.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="app-container" style="overflow-y: auto">
+    <div class="bos">
+      <div class="lab">
+        <div class="bsg"></div>
+        <div class="tit">按医生随访排行统计</div>
+      </div>
+      <BarChart :chartData="chartData" height="3000px"></BarChart>
+    </div>
+  </div>
+</template>
+
+<script>
+import BarChart from '@/views/dashboard/BarChart2';
+export default {
+  components: { BarChart },
+  data() {
+    return {
+      chartData: [],
+      queryParams: {}
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    getList() {
+      this.ajax({ url: '/work/statistics/selectByDoctor' }).then((response) => {
+        this.chartData = response.data.data;
+      });
+    }
+  }
+};
+</script>

+ 34 - 0
admin-ui/src/views/work/statistics/month.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="app-container" style="overflow-y: auto">
+    <div class="bos">
+      <div class="lab">
+        <div class="bsg"></div>
+        <div class="tit">按年月统计</div>
+      </div>
+      <BarChart :chartData="chartData" height="500px"></BarChart>
+    </div>
+  </div>
+</template>
+
+<script>
+import BarChart from '@/views/dashboard/BarChart';
+export default {
+  components: { BarChart },
+  data() {
+    return {
+      chartData: [],
+      queryParams: {}
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    getList() {
+      this.ajax({ url: '/work/statistics/selectByMonth', data: { year: 2025 } }).then((response) => {
+        this.chartData = response.data.data;
+      });
+    }
+  }
+};
+</script>

+ 45 - 0
admin-ui/src/views/work/statistics/user.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="app-container" style="overflow-y: auto">
+    <div class="bos">
+      <div class="lab">
+        <div class="bsg"></div>
+        <div class="tit">每月关注用户</div>
+      </div>
+      <BarChart :chartData="chartData" height="300px"></BarChart>
+    </div>
+    <div class="bos">
+      <div class="lab">
+        <div class="bsg"></div>
+        <div class="tit">用户绑定占比</div>
+      </div>
+      <PieChart :chartData="chartData2" height="300px"></PieChart>
+    </div>
+  </div>
+</template>
+
+<script>
+import BarChart from '@/views/dashboard/BarChart';
+import PieChart from '@/views/dashboard/PieChart';
+export default {
+  components: { BarChart, PieChart },
+  data() {
+    return {
+      chartData: [],
+      chartData2: [],
+      queryParams: {}
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    getList() {
+      this.ajax({ url: '/work/statistics/selectByUser', data: { year: 2025 } }).then((response) => {
+        this.chartData = response.data.user;
+        this.chartData2.push({ name: '已绑定患者', value: response.data.follow.follow });
+        this.chartData2.push({ name: '未绑定患者', value: response.data.follow.allUser - response.data.follow.follow });
+      });
+    }
+  }
+};
+</script>

+ 5 - 0
admin-ui/src/views/work/visit/index.vue

@@ -22,6 +22,7 @@
             <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
             <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
           </el-form-item>
+          <el-button type="primary" icon="el-icon-download" @click="handleExport" style="float: right;">导出</el-button>
         </el-form>
         <el-table :data="response.rows" border height="calc(100vh - 240px)" v-loading="loading">
           <el-table-column type="selection" width="55" align="center" />
@@ -132,6 +133,10 @@ export default {
       this.resetForm('queryForm');
       this.dateRange = [];
       this.handleQuery();
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('/work/visit/export', { ...this.queryParams }, '患者信息.xlsx');
     }
   }
 };

+ 47 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/controller/StatisticsController.java

@@ -0,0 +1,47 @@
+package com.ruoyi.web.work.controller;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.web.work.domain.dto.StatisticsDto;
+import com.ruoyi.web.work.mapper.StatisticsMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * 统计管理
+ */
+@RestController
+@RequestMapping("/work/statistics")
+public class StatisticsController extends BaseController {
+
+    @Autowired
+    private StatisticsMapper mapper;
+
+    @GetMapping("/selectByDepartment")
+    public AjaxResult selectByDepartment() {
+        AjaxResult res = new AjaxResult();
+        res.put("data", mapper.selectByDepartment());
+        return AjaxResult.success(res);
+    }
+    @GetMapping("/selectByDoctor")
+    public AjaxResult selectByDoctor() {
+        AjaxResult res = new AjaxResult();
+        res.put("data", mapper.selectByDoctor());
+        return AjaxResult.success(res);
+    }
+
+    @GetMapping("/selectByMonth")
+    public AjaxResult selectByMonth(StatisticsDto dto) {
+        AjaxResult res = new AjaxResult();
+        res.put("data", mapper.selectByMonth(dto));
+        return AjaxResult.success(res);
+    }
+    @GetMapping("/selectByUser")
+    public AjaxResult selectByUser(StatisticsDto dto) {
+        AjaxResult res = new AjaxResult();
+        res.put("user", mapper.selectByUser());
+        res.put("follow", mapper.selectFollow());
+        return AjaxResult.success(res);
+    }
+}

+ 13 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/controller/VisitController.java

@@ -5,6 +5,9 @@ import java.util.Arrays;
 import java.util.List;
 
 import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.web.work.domain.FollowRecord;
 import com.ruoyi.web.work.domain.Visit;
 import com.ruoyi.web.work.domain.dto.PatientCardDto;
 import com.ruoyi.web.work.domain.vo.VisitVoList;
@@ -20,6 +23,8 @@ import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.core.page.TableDataInfo;
 
+import javax.servlet.http.HttpServletResponse;
+
 /**
  * 住院信息
  * @author lsw
@@ -80,4 +85,12 @@ public class VisitController extends BaseController {
     public AjaxResult remove(@PathVariable Long[] ids){
         return toAjax(visitService.removeByIds(Arrays.asList(ids)));
     }
+
+    @Log(title = "住院信息", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, PatientCardDto patientCardDto) {
+        List<VisitVoList> list = visitService.getPatientCardByNameOrDepartmentOrPhysician(patientCardDto);
+        ExcelUtil<VisitVoList> util = new ExcelUtil<VisitVoList>(VisitVoList.class);
+        util.exportExcel(response, list, "患者信息");
+    }
 }

+ 18 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/domain/dto/StatisticsDto.java

@@ -0,0 +1,18 @@
+package com.ruoyi.web.work.domain.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class StatisticsDto {
+
+
+    private Long userId;
+
+    private String year;
+
+}

+ 12 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/work/domain/vo/VisitVoList.java

@@ -1,6 +1,7 @@
 package com.ruoyi.web.work.domain.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
@@ -20,43 +21,53 @@ public class VisitVoList {
 
 
     @ApiModelProperty(value = "患者姓名")
+    @Excel(name = "患者姓名",sort =1)
     private String name;
 
     @ApiModelProperty(value = "性别")
+    @Excel(name = "是否关注小程序", readConverterExp = "F=女,M=男",sort =2)
     private String sex;
 
     @ApiModelProperty(value = "电话")
     private String phone;
 
     @ApiModelProperty(value = "主治医师")
+    @Excel(name = "管床医生",sort =9)
     private String physician;
 
     @ApiModelProperty(value = "科室")
+    @Excel(name = "所属科室",sort =10)
     private String department;
 
     @ApiModelProperty(value = "病历号")
+    @Excel(name = "病历号",sort =3)
     private String blh;
 
     @ApiModelProperty(value = "入院时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "入院时间",dateFormat = "yyyy-MM-dd HH:mm",sort =4,width=30)
     private Date admissionTime;
 
     @ApiModelProperty(value = "出院时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "出院时间",dateFormat = "yyyy-MM-dd HH:mm",sort =5,width=30)
     private Date dischargeTime;
 
     @ApiModelProperty(value = "复诊提醒")
+    @Excel(name = "复诊提醒",sort =8)
     private Integer up = 0;
 
     @ApiModelProperty(value = "复诊提醒已读")
     private Integer upRead = 0;
 
     @ApiModelProperty(value = "随访记录")
+    @Excel(name = "随访记录",sort =7)
     private Integer record = 0;
 
     @ApiModelProperty(value = "随访记录已填")
     private Integer recordRead = 0;
 
-    @ApiModelProperty(value = "是否绑定小程序")
+    @ApiModelProperty(value = "是否关注小程序")
+    @Excel(name = "是否关注小程序", readConverterExp = "0=未关注,1=已关注",sort =6)
     private Integer isBindWx;
 }

+ 29 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/work/mapper/StatisticsMapper.java

@@ -0,0 +1,29 @@
+package com.ruoyi.web.work.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.web.work.domain.User;
+import com.ruoyi.web.work.domain.dto.StatisticsDto;
+import com.ruoyi.web.work.domain.vo.ExpertVoList;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author lsw
+ * @date 2024-07-16
+ */
+public interface StatisticsMapper extends BaseMapper<User> {
+
+    List<Map<String, Object>> selectByDepartment();
+
+    List<Map<String, Object>> selectByDoctor();
+
+
+    List<Map<String, Object>> selectByMonth(StatisticsDto dto);
+
+    List<Map<String, Object>> selectByUser();
+
+    Map<String, Object> selectFollow();
+}

+ 86 - 0
ruoyi-admin/src/main/resources/mapper/work/StatisticsMapper.xml

@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.web.work.mapper.StatisticsMapper">
+    
+    <!--按科室统计-->
+    <select id="selectByDepartment" resultType="java.util.Map">
+        SELECT d.dept_id,d.dept_name AS name,(SELECT COUNT( r.id ) FROM tb_follow_record r WHERE r.dept_id = d.dept_id ) AS value FROM sys_dept d ORDER BY value DESC
+    </select>
+
+    <!--按医生统计-->
+    <select id="selectByDoctor" resultType="java.util.Map">
+        SELECT u.user_id,u.nick_name AS name,(SELECT COUNT( r.id ) FROM tb_follow_record r WHERE r.user_id =u.user_id) AS value FROM sys_user u ORDER BY value DESC LIMIT 100
+    </select>
+
+    <!--关注人数统计-->
+    <select id="selectByFollow" resultType="java.util.Map">
+        SELECT COUNT(u.id) AS allUser, COUNT(CASE WHEN u.patient_id IS NOT NULL THEN 1 END) AS follow FROM tb_user u
+    </select>
+
+    <!--关注人数统计-->
+    <select id="selectFollow" resultType="java.util.Map">
+        SELECT COUNT(u.id) AS allUser, COUNT(CASE WHEN u.patient_id IS NOT NULL THEN 1 END) AS follow FROM tb_user u
+    </select>
+
+
+    <!--按年月统计-->
+    <select id="selectByMonth" resultType="java.util.Map">
+        SELECT
+            months.month AS name,
+            COUNT(tb_follow_record.id) AS value
+        FROM
+            (
+            SELECT 1 AS month UNION ALL
+            SELECT 2 AS month UNION ALL
+            SELECT 3 AS month UNION ALL
+            SELECT 4 AS month UNION ALL
+            SELECT 5 AS month UNION ALL
+            SELECT 6 AS month UNION ALL
+            SELECT 7 AS month UNION ALL
+            SELECT 8 AS month UNION ALL
+            SELECT 9 AS month UNION ALL
+            SELECT 10 AS month UNION ALL
+            SELECT 11 AS month UNION ALL
+            SELECT 12 AS month
+            ) AS months
+            LEFT JOIN
+            tb_follow_record ON
+            MONTH(tb_follow_record.create_time) = months.month AND YEAR(tb_follow_record.create_time) =#{year}
+            <if test="userId != null ">AND tb_follow_record.user_id=#{userId}</if>
+        GROUP BY
+            months.month
+        ORDER BY
+            months.month
+    </select>
+
+    <!--按患者统计-->
+    <select id="selectByUser" resultType="java.util.Map">
+        SELECT
+            months.month AS name,
+            COUNT(tb_user.id) AS value
+        FROM
+            (
+            SELECT 1 AS month UNION ALL
+            SELECT 2 AS month UNION ALL
+            SELECT 3 AS month UNION ALL
+            SELECT 4 AS month UNION ALL
+            SELECT 5 AS month UNION ALL
+            SELECT 6 AS month UNION ALL
+            SELECT 7 AS month UNION ALL
+            SELECT 8 AS month UNION ALL
+            SELECT 9 AS month UNION ALL
+            SELECT 10 AS month UNION ALL
+            SELECT 11 AS month UNION ALL
+            SELECT 12 AS month
+            ) AS months
+            LEFT JOIN
+            tb_user ON
+            MONTH(tb_user.create_time) = months.month AND YEAR(tb_user.create_time) =2025
+        GROUP BY
+            months.month
+        ORDER BY
+            months.month
+    </select>
+</mapper>