index.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <template>
  2. <com-head :options="[{ name: '数据统计', value: '1' }]" class="static-head frame-head">
  3. <el-form label-width="84px">
  4. <el-form-item label="统计区间:" style="grid-area: 1/1/2/2">
  5. <p style="margin-top: -6px">{{ range }}</p>
  6. </el-form-item>
  7. <el-form-item label="统计区间:" style="grid-area: 1/2/2/4">
  8. <el-date-picker
  9. type="daterange"
  10. v-model="params"
  11. range-separator="-"
  12. placeholder="请选择"
  13. style="width: 400px"
  14. />
  15. </el-form-item>
  16. </el-form>
  17. </com-head>
  18. <div class="statistics-layer">
  19. <div v-for="(config, ndx) in statisticsConfigs" class="statistics-item">
  20. <div class="statistics-content">
  21. <p class="title">{{ config.title }}</p>
  22. <div class="graphics" :ref="(dom: any) => updateDom(ndx, dom)"></div>
  23. </div>
  24. </div>
  25. </div>
  26. </template>
  27. <script setup lang="ts">
  28. import comHead from "@/components/head/index.vue";
  29. import {
  30. markRaw,
  31. nextTick,
  32. onMounted,
  33. onUnmounted,
  34. reactive,
  35. ref,
  36. watch,
  37. watchEffect,
  38. } from "vue";
  39. import {
  40. statisticsConfigs,
  41. echarts,
  42. EChartsType,
  43. ConfigItem,
  44. updateParams,
  45. } from "./statisticsInject";
  46. import { dateFormat } from "@/util";
  47. import { user } from "@/store/user";
  48. const prevYearDate = new Date();
  49. prevYearDate.setFullYear(prevYearDate.getFullYear() - 1);
  50. const params = ref<Date[]>([prevYearDate, new Date()]);
  51. const range = [
  52. "全部火调队伍数据",
  53. "总队及下级队伍数据",
  54. "支队及下级队伍数据",
  55. "当前队伍数据",
  56. ][user.value.info.deptLevel];
  57. watchEffect(() => {
  58. updateParams({
  59. startTime: dateFormat(params.value[0], "yyyy-MM-dd"),
  60. endTime: dateFormat(params.value[1], "yyyy-MM-dd"),
  61. });
  62. });
  63. const doms = statisticsConfigs.map(() => ref<HTMLDivElement>());
  64. const updateDom = (ndx: number, dom: HTMLDivElement) => {
  65. nextTick(() => (doms[ndx].value = dom));
  66. };
  67. const charts = reactive([]) as (EChartsType | null)[];
  68. doms.forEach((dom, ndx) => {
  69. watchEffect((onCleanup) => {
  70. if (dom.value) {
  71. const chart = echarts.init(dom.value);
  72. markRaw(chart);
  73. charts[ndx] = chart;
  74. onCleanup(() => {
  75. echarts.dispose(charts[ndx]!);
  76. charts[ndx] = null;
  77. });
  78. }
  79. });
  80. });
  81. type WData = [ConfigItem[], (EChartsType | null)[]];
  82. watch(
  83. () => [statisticsConfigs, charts] as WData,
  84. (nInstalls) => {
  85. const [nConfigs, nCharts] = nInstalls;
  86. for (let ndx = 0; ndx < nCharts.length; ndx++) {
  87. if (!nCharts[ndx]) continue;
  88. nCharts[ndx]!.setOption(nConfigs[ndx].data);
  89. }
  90. },
  91. { deep: true }
  92. );
  93. const resize = () => {
  94. for (const chart of charts) {
  95. chart?.resize();
  96. }
  97. };
  98. onMounted(() => window.addEventListener("resize", resize));
  99. onUnmounted(() => window.removeEventListener("resize", resize));
  100. </script>
  101. <style lang="scss" scoped>
  102. .statistics-layer {
  103. flex: 1;
  104. margin-top: 16px;
  105. overflow-y: auto;
  106. }
  107. .statistics-item {
  108. float: left;
  109. width: calc(50% - 8px);
  110. padding-top: 35%;
  111. position: relative;
  112. margin-bottom: 16px;
  113. .statistics-content {
  114. background-color: #fff;
  115. position: absolute;
  116. left: 0;
  117. top: 0;
  118. right: 0;
  119. bottom: 0;
  120. }
  121. &:nth-child(2n - 1) {
  122. margin-right: 8px;
  123. }
  124. &:nth-child(2n) {
  125. margin-left: 8px;
  126. }
  127. }
  128. .statistics-content {
  129. display: flex;
  130. flex-direction: column;
  131. .title {
  132. flex: 0 0 auto;
  133. line-height: 1;
  134. padding: 16px;
  135. border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  136. font-size: 16px;
  137. }
  138. .graphics {
  139. flex: 1;
  140. padding: 15px;
  141. }
  142. }
  143. </style>
  144. <style lang="scss">
  145. .static-head {
  146. .el-range-separator {
  147. display: initial !important;
  148. line-height: 38px;
  149. font-size: 16px;
  150. }
  151. .el-date-editor--daterange::after {
  152. display: none;
  153. }
  154. }
  155. </style>