index.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <template>
  2. <div class="sample-statistics">
  3. <!-- Top: Statistics & Time Filter -->
  4. <el-row :gutter="20" class="top-bar">
  5. <el-col :span="12">
  6. <div class="stat-box">
  7. <div class="stat-title">样本统计</div>
  8. <!-- <div class="stat-value">{{ totalSamples }}</div> -->
  9. </div>
  10. </el-col>
  11. <el-col :span="12" class="filter-col">
  12. <el-select v-model="selectedRange" placeholder="选择时间范围" @change="onRangeChange" size="small">
  13. <el-option label="近24小时" value="1"></el-option>
  14. <el-option label="近3天(72小时)" value="2"></el-option>
  15. <el-option label="近7天" value="3"></el-option>
  16. <el-option label="近30天" value="4"></el-option>
  17. </el-select>
  18. </el-col>
  19. </el-row>
  20. <!-- Middle: Line Chart -->
  21. <div class="chart-section">
  22. <div ref="lineChart" class="line-chart"></div>
  23. </div>
  24. <!-- Bottom: Pie Charts -->
  25. <el-row :gutter="20" class="pie-row">
  26. <el-col :span="12">
  27. <div class="pie-title">样本类型占比</div>
  28. <div ref="typePieChart" class="pie-chart"></div>
  29. </el-col>
  30. <el-col :span="12">
  31. <div class="pie-title">检出物占比</div>
  32. <div ref="detectedPieChart" class="pie-chart"></div>
  33. </el-col>
  34. </el-row>
  35. </div>
  36. </template>
  37. <script>
  38. import * as echarts from 'echarts';
  39. import {getjcwzbInfo, getyblxtjInfo, getybtjInfo} from '@/api/statistics/report';
  40. export default {
  41. name: 'SampleStatistics',
  42. data() {
  43. return {
  44. selectedRange: '1',
  45. totalSamples: 1234,
  46. lineChart: null,
  47. typePieChart: null,
  48. detectedPieChart: null,
  49. lineData: [],
  50. typePieData: [],
  51. detectedPieData: [],
  52. }
  53. },
  54. mounted() {
  55. this.initCharts()
  56. this.fetchData()
  57. },
  58. methods: {
  59. onRangeChange() {
  60. this.fetchData()
  61. },
  62. async fetchData() {
  63. const response = await getjcwzbInfo(this.selectedRange)
  64. if (response.data ) {
  65. let arr = []
  66. for(let k in response.data) {
  67. arr.push({
  68. name: k,
  69. value: response.data[k]
  70. })
  71. }
  72. this.detectedPieData = [...arr];
  73. }
  74. const res = await getyblxtjInfo(this.selectedRange)
  75. if (res.data ) {
  76. let arr = []
  77. for(let k in res.data) {
  78. arr.push({
  79. name: k,
  80. value: res.data[k]
  81. })
  82. }
  83. this.typePieData = [...arr];
  84. }
  85. const result = await getybtjInfo(this.selectedRange)
  86. const analysisData = []
  87. const adoptionData = []
  88. // 生成日期
  89. const xData = []
  90. if (result.data ) {
  91. result.data.forEach(item => {
  92. analysisData.push(item.fxl)
  93. adoptionData.push(item.ybl)
  94. xData.push(item.hour)
  95. })
  96. }
  97. // 模拟数据,根据selectedRange更新
  98. // const now = new Date()
  99. // let days = 1
  100. // if (this.selectedRange === '2') days = 3
  101. // if (this.selectedRange === '3') days = 7
  102. // if (this.selectedRange === '4') days = 30
  103. // for (let i = days - 1; i >= 0; i--) {
  104. // const d = new Date(now)
  105. // d.setDate(now.getDate() - i)
  106. // xData.push(`${d.getMonth() + 1}-${d.getDate()}`)
  107. // analysisData.push(Math.floor(Math.random() * 100 + 100))
  108. // adoptionData.push(Math.floor(Math.random() * 80 + 50))
  109. // }
  110. this.lineData = { xData, analysisData, adoptionData }
  111. // // 饼图数据
  112. // this.typePieData = [
  113. // { value: 335, name: '血液' },
  114. // { value: 310, name: '尿液' },
  115. // { value: 234, name: '唾液' },
  116. // { value: 135, name: '其他' }
  117. // ]
  118. // this.detectedPieData = [
  119. // { value: 400, name: '物质A' },
  120. // { value: 335, name: '物质B' },
  121. // { value: 310, name: '物质C' },
  122. // { value: 234, name: '其他' }
  123. // ]
  124. // this.totalSamples = analysisData.reduce((a, b) => a + b, 0)
  125. this.updateCharts()
  126. },
  127. initCharts() {
  128. this.lineChart = echarts.init(this.$refs.lineChart)
  129. this.typePieChart = echarts.init(this.$refs.typePieChart)
  130. this.detectedPieChart = echarts.init(this.$refs.detectedPieChart)
  131. },
  132. updateCharts() {
  133. // 折线图
  134. this.lineChart.setOption({
  135. tooltip: { trigger: 'axis' },
  136. legend: { data: ['数据分析量', '收样量'] },
  137. xAxis: { type: 'category', data: this.lineData.xData },
  138. yAxis: { type: 'value', name: '数量' },
  139. series: [
  140. {
  141. name: '数据分析量',
  142. type: 'line',
  143. smooth: true,
  144. data: this.lineData.analysisData
  145. },
  146. {
  147. name: '收样量',
  148. type: 'line',
  149. smooth: true,
  150. data: this.lineData.adoptionData
  151. }
  152. ]
  153. })
  154. // 样本类型饼图
  155. this.typePieChart.setOption({
  156. tooltip: { trigger: 'item' },
  157. legend: { bottom: 0 },
  158. series: [
  159. {
  160. name: '样本类型',
  161. type: 'pie',
  162. radius: '60%',
  163. data: this.typePieData,
  164. emphasis: {
  165. itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
  166. }
  167. }
  168. ]
  169. })
  170. // 检出物饼图
  171. this.detectedPieChart.setOption({
  172. tooltip: { trigger: 'item' },
  173. legend: { bottom: 0 },
  174. series: [
  175. {
  176. name: '检出物',
  177. type: 'pie',
  178. radius: '60%',
  179. data: this.detectedPieData,
  180. emphasis: {
  181. itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
  182. }
  183. }
  184. ]
  185. })
  186. }
  187. }
  188. }
  189. </script>
  190. <style scoped>
  191. .sample-statistics {
  192. padding: 24px;
  193. background: #fff;
  194. }
  195. .top-bar {
  196. margin-bottom: 24px;
  197. align-items: center;
  198. }
  199. .stat-box {
  200. display: flex;
  201. flex-direction: column;
  202. justify-content: center;
  203. height: 60px;
  204. }
  205. .stat-title {
  206. font-size: 16px;
  207. color: #888;
  208. }
  209. .stat-value {
  210. font-size: 28px;
  211. font-weight: bold;
  212. color: #409EFF;
  213. }
  214. .filter-col {
  215. display: flex;
  216. align-items: center;
  217. justify-content: flex-end;
  218. }
  219. .chart-section {
  220. margin-bottom: 24px;
  221. }
  222. .line-chart {
  223. width: 100%;
  224. height: 320px;
  225. }
  226. .pie-row {
  227. margin-top: 12px;
  228. }
  229. .pie-chart {
  230. width: 100%;
  231. height: 260px;
  232. }
  233. .pie-title {
  234. text-align: center;
  235. font-size: 16px;
  236. margin-bottom: 8px;
  237. color: #333;
  238. }
  239. </style>