index.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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="24h"></el-option>
  14. <el-option label="三天" value="3d"></el-option>
  15. <el-option label="五天" value="5d"></el-option>
  16. <el-option label="七天" value="7d"></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. export default {
  40. name: 'SampleStatistics',
  41. data() {
  42. return {
  43. selectedRange: '24h',
  44. totalSamples: 1234,
  45. lineChart: null,
  46. typePieChart: null,
  47. detectedPieChart: null,
  48. lineData: [],
  49. typePieData: [],
  50. detectedPieData: [],
  51. }
  52. },
  53. mounted() {
  54. this.initCharts()
  55. this.fetchData()
  56. },
  57. methods: {
  58. onRangeChange() {
  59. this.fetchData()
  60. },
  61. fetchData() {
  62. // 模拟数据,根据selectedRange更新
  63. const now = new Date()
  64. let days = 1
  65. if (this.selectedRange === '3d') days = 3
  66. if (this.selectedRange === '5d') days = 5
  67. if (this.selectedRange === '7d') days = 7
  68. // 生成日期
  69. const xData = []
  70. const analysisData = []
  71. const adoptionData = []
  72. for (let i = days - 1; i >= 0; i--) {
  73. const d = new Date(now)
  74. d.setDate(now.getDate() - i)
  75. xData.push(`${d.getMonth() + 1}-${d.getDate()}`)
  76. analysisData.push(Math.floor(Math.random() * 100 + 100))
  77. adoptionData.push(Math.floor(Math.random() * 80 + 50))
  78. }
  79. this.lineData = { xData, analysisData, adoptionData }
  80. // 饼图数据
  81. this.typePieData = [
  82. { value: 335, name: '血液' },
  83. { value: 310, name: '尿液' },
  84. { value: 234, name: '唾液' },
  85. { value: 135, name: '其他' }
  86. ]
  87. this.detectedPieData = [
  88. { value: 400, name: '物质A' },
  89. { value: 335, name: '物质B' },
  90. { value: 310, name: '物质C' },
  91. { value: 234, name: '其他' }
  92. ]
  93. this.totalSamples = analysisData.reduce((a, b) => a + b, 0)
  94. this.updateCharts()
  95. },
  96. initCharts() {
  97. this.lineChart = echarts.init(this.$refs.lineChart)
  98. this.typePieChart = echarts.init(this.$refs.typePieChart)
  99. this.detectedPieChart = echarts.init(this.$refs.detectedPieChart)
  100. },
  101. updateCharts() {
  102. // 折线图
  103. this.lineChart.setOption({
  104. tooltip: { trigger: 'axis' },
  105. legend: { data: ['数据分析量', '收养量'] },
  106. xAxis: { type: 'category', data: this.lineData.xData },
  107. yAxis: { type: 'value', name: '数量' },
  108. series: [
  109. {
  110. name: '数据分析量',
  111. type: 'line',
  112. smooth: true,
  113. data: this.lineData.analysisData
  114. },
  115. {
  116. name: '收养量',
  117. type: 'line',
  118. smooth: true,
  119. data: this.lineData.adoptionData
  120. }
  121. ]
  122. })
  123. // 样本类型饼图
  124. this.typePieChart.setOption({
  125. tooltip: { trigger: 'item' },
  126. legend: { bottom: 0 },
  127. series: [
  128. {
  129. name: '样本类型',
  130. type: 'pie',
  131. radius: '60%',
  132. data: this.typePieData,
  133. emphasis: {
  134. itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
  135. }
  136. }
  137. ]
  138. })
  139. // 检出物饼图
  140. this.detectedPieChart.setOption({
  141. tooltip: { trigger: 'item' },
  142. legend: { bottom: 0 },
  143. series: [
  144. {
  145. name: '检出物',
  146. type: 'pie',
  147. radius: '60%',
  148. data: this.detectedPieData,
  149. emphasis: {
  150. itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }
  151. }
  152. }
  153. ]
  154. })
  155. }
  156. }
  157. }
  158. </script>
  159. <style scoped>
  160. .sample-statistics {
  161. padding: 24px;
  162. background: #fff;
  163. }
  164. .top-bar {
  165. margin-bottom: 24px;
  166. align-items: center;
  167. }
  168. .stat-box {
  169. display: flex;
  170. flex-direction: column;
  171. justify-content: center;
  172. height: 60px;
  173. }
  174. .stat-title {
  175. font-size: 16px;
  176. color: #888;
  177. }
  178. .stat-value {
  179. font-size: 28px;
  180. font-weight: bold;
  181. color: #409EFF;
  182. }
  183. .filter-col {
  184. display: flex;
  185. align-items: center;
  186. justify-content: flex-end;
  187. }
  188. .chart-section {
  189. margin-bottom: 24px;
  190. }
  191. .line-chart {
  192. width: 100%;
  193. height: 320px;
  194. }
  195. .pie-row {
  196. margin-top: 12px;
  197. }
  198. .pie-chart {
  199. width: 100%;
  200. height: 260px;
  201. }
  202. .pie-title {
  203. text-align: center;
  204. font-size: 16px;
  205. margin-bottom: 8px;
  206. color: #333;
  207. }
  208. </style>