ModuleFour.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <template>
  2. <module-container title="模块四 放行速率分析">
  3. <div class="module-four-content">
  4. <div class="chart-row">
  5. <div class="chart-item">
  6. <div class="chart-title">T1航站楼放行速率</div>
  7. <div ref="rateChart1" class="echarts"></div>
  8. </div>
  9. <div class="chart-item">
  10. <div class="chart-title">T2航站楼放行速率</div>
  11. <div ref="rateChart2" class="echarts"></div>
  12. </div>
  13. </div>
  14. <div class="chart-row">
  15. <div class="chart-item">
  16. <div class="chart-title">大队总平均速率对比(国内)</div>
  17. <div ref="rateChart3" class="echarts"></div>
  18. </div>
  19. <div class="chart-item">
  20. <div class="chart-title">大队总平均速率对比(国际+中转)</div>
  21. <div ref="rateChart4" class="echarts"></div>
  22. </div>
  23. </div>
  24. </div>
  25. </module-container>
  26. </template>
  27. <script setup>
  28. import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
  29. import * as echarts from 'echarts'
  30. import ModuleContainer from './ModuleContainer.vue'
  31. import { useEcharts } from '@/hooks/chart.js'
  32. import { t1RateStats, t2RateStats, insideRateStats, outsideRateStats } from '@/api/blockingData/blockingDataScreen.js'
  33. import { formatDateHy } from '@/utils/index.js'
  34. // 接收筛选参数
  35. const props = defineProps({
  36. filterParams: {
  37. type: Object,
  38. default: () => ({})
  39. }
  40. })
  41. const rateChart1 = ref(null)
  42. const rateChart2 = ref(null)
  43. const rateChart3 = ref(null)
  44. const rateChart4 = ref(null)
  45. const { setOption: setOption1 } = useEcharts(rateChart1)
  46. const { setOption: setOption2 } = useEcharts(rateChart2)
  47. const { setOption: setOption3 } = useEcharts(rateChart3)
  48. const { setOption: setOption4 } = useEcharts(rateChart4)
  49. // 处理filterParams,将dateRange拆分为startTime和endTime
  50. const processFilterParams = (params) => {
  51. const { dateRange, ...rest } = params
  52. const processed = { ...rest }
  53. if (dateRange && Array.isArray(dateRange) && dateRange.length === 2) {
  54. processed.startDate = formatDateHy(dateRange[0])
  55. processed.endDate = formatDateHy(dateRange[1])
  56. }
  57. if (processed.brigadeId == 'all') {
  58. delete processed.brigadeId
  59. }
  60. if (processed.terminalId == 'all') {
  61. delete processed.terminalId
  62. }
  63. return processed
  64. }
  65. // 数据加载函数
  66. const loadData = async () => {
  67. try {
  68. const queryParams = processFilterParams(props.filterParams)
  69. console.log('查询参数:', queryParams)
  70. // 并行请求所有速率数据
  71. const [t1RateRes, t2RateRes, insideRateRes, outsideRateRes] = await Promise.allSettled([
  72. t1RateStats(queryParams),
  73. t2RateStats(queryParams),
  74. insideRateStats(queryParams),
  75. outsideRateStats(queryParams)
  76. ])
  77. console.log('T1速率响应:', t1RateRes)
  78. console.log('T2速率响应:', t2RateRes)
  79. console.log('国内速率响应:', insideRateRes)
  80. console.log('国际中转速率响应:', outsideRateRes)
  81. // T1航站楼放行速率
  82. const t1RateData = t1RateRes?.value?.data || []
  83. console.log('T1速率数据:', t1RateData)
  84. console.log('T1速率数据长度:', t1RateData.length)
  85. console.log('T1速率数据类型:', typeof t1RateData)
  86. console.log('T1速率数据是否为数组:', Array.isArray(t1RateData))
  87. console.log('T1速率数据:', t1RateData)
  88. if (t1RateData.length > 0) {
  89. const dates = [...new Set(t1RateData.map(d => d.statDate))].sort()
  90. const seriesData = [
  91. {
  92. name: 'T1-A区速率(高峰期时段)',
  93. type: 'line',
  94. data: dates.map(date => {
  95. const item = t1RateData.find(d => d.statDate === date)
  96. return item ? item.t1AAreaRatePeak : 0
  97. }),
  98. itemStyle: { color: '#3b82f6' },
  99. lineStyle: { width: 3 },
  100. symbol: 'circle',
  101. symbolSize: 8
  102. },
  103. {
  104. name: 'T1-B区速率(高峰期时段)',
  105. type: 'line',
  106. data: dates.map(date => {
  107. const item = t1RateData.find(d => d.statDate === date)
  108. return item ? item.t1BAreaRatePeak : 0
  109. }),
  110. itemStyle: { color: '#22c55e' },
  111. lineStyle: { width: 3 },
  112. symbol: 'circle',
  113. symbolSize: 8
  114. }
  115. ]
  116. console.log('准备设置T1图表选项')
  117. console.log('日期数据:', dates)
  118. console.log('系列数据:', seriesData)
  119. setOption1({
  120. tooltip: {
  121. trigger: 'axis',
  122. formatter: function(params) {
  123. let result = params[0].name + '<br/>'
  124. params.forEach(param => {
  125. result += `${param.marker} ${param.seriesName}: ${param.value} 件/小时<br/>`
  126. })
  127. return result
  128. }
  129. },
  130. legend: {
  131. data: ['T1-A区速率(高峰期时段)', 'T1-B区速率(高峰期时段)']
  132. },
  133. grid: {
  134. left: '3%',
  135. right: '4%',
  136. bottom: '3%',
  137. containLabel: true
  138. },
  139. xAxis: {
  140. type: 'category',
  141. data: dates,
  142. axisLabel: {
  143. rotate: 45
  144. }
  145. },
  146. yAxis: {
  147. type: 'value',
  148. name: '速率',
  149. axisLabel: {
  150. formatter: '{value} 件/小时'
  151. }
  152. },
  153. series: seriesData
  154. })
  155. console.log('T1图表设置完成')
  156. }
  157. // T2航站楼放行速率
  158. const t2RateData = t2RateRes?.value?.data || []
  159. if (t2RateData.length > 0) {
  160. const dates = [...new Set(t2RateData.map(d => d.statDate))].sort()
  161. const seriesData = [
  162. {
  163. name: 'T2-国内速率(高峰期时段)',
  164. type: 'line',
  165. data: dates.map(date => {
  166. const item = t2RateData.find(d => d.statDate === date)
  167. return item ? item.t2DomesticRatePeak : 0
  168. }),
  169. itemStyle: { color: '#3b82f6' },
  170. lineStyle: { width: 3 },
  171. symbol: 'circle',
  172. symbolSize: 8
  173. },
  174. {
  175. name: 'T2-国际速率(高峰期时段)',
  176. type: 'line',
  177. data: dates.map(date => {
  178. const item = t2RateData.find(d => d.statDate === date)
  179. return item ? item.t2InternationalRatePeak : 0
  180. }),
  181. itemStyle: { color: '#22c55e' },
  182. lineStyle: { width: 3 },
  183. symbol: 'circle',
  184. symbolSize: 8
  185. }
  186. ]
  187. setOption2({
  188. tooltip: {
  189. trigger: 'axis',
  190. formatter: function(params) {
  191. let result = params[0].name + '<br/>'
  192. params.forEach(param => {
  193. result += `${param.marker} ${param.seriesName}: ${param.value} 件/小时<br/>`
  194. })
  195. return result
  196. }
  197. },
  198. legend: {
  199. data: ['T2-国内速率(高峰期时段)', 'T2-国际速率(高峰期时段)']
  200. },
  201. grid: {
  202. left: '3%',
  203. right: '4%',
  204. bottom: '3%',
  205. containLabel: true
  206. },
  207. xAxis: {
  208. type: 'category',
  209. data: dates,
  210. axisLabel: {
  211. rotate: 45
  212. }
  213. },
  214. yAxis: {
  215. type: 'value',
  216. name: '速率',
  217. axisLabel: {
  218. formatter: '{value} 件/小时'
  219. }
  220. },
  221. series: seriesData
  222. })
  223. }
  224. // 大队总平均速率对比(国内)
  225. const insideRateData = insideRateRes?.value?.data || []
  226. if (insideRateData.length > 0) {
  227. const dates = [...new Set(insideRateData.map(d => d.statDate))].sort()
  228. const brigadeNames = [...new Set(insideRateData.map(d => d.dutyBrigadeName))]
  229. const seriesData = brigadeNames.map((brigade, index) => ({
  230. name: brigade,
  231. type: 'line',
  232. data: dates.map(date => {
  233. const item = insideRateData.find(d => d.statDate === date && d.dutyBrigadeName === brigade)
  234. return item ? item.avgRatePeak : 0
  235. }),
  236. itemStyle: {
  237. color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6'][index % 5]
  238. },
  239. lineStyle: { width: 3 },
  240. symbol: 'circle',
  241. symbolSize: 8
  242. }))
  243. setOption3({
  244. tooltip: {
  245. trigger: 'axis',
  246. formatter: function(params) {
  247. let result = params[0].name + '<br/>'
  248. params.forEach(param => {
  249. result += `${param.marker} ${param.seriesName}: ${param.value} 件/小时<br/>`
  250. })
  251. return result
  252. }
  253. },
  254. legend: {
  255. data: brigadeNames
  256. },
  257. grid: {
  258. left: '3%',
  259. right: '4%',
  260. bottom: '3%',
  261. containLabel: true
  262. },
  263. xAxis: {
  264. type: 'category',
  265. data: dates,
  266. axisLabel: {
  267. rotate: 45
  268. }
  269. },
  270. yAxis: {
  271. type: 'value',
  272. name: '速率',
  273. axisLabel: {
  274. formatter: '{value} 件/小时'
  275. }
  276. },
  277. series: seriesData
  278. })
  279. }
  280. // 大队总平均速率对比(国际+中转)
  281. const outsideRateData = outsideRateRes?.value?.data || []
  282. if (outsideRateData.length > 0) {
  283. const dates = [...new Set(outsideRateData.map(d => d.statDate))].sort()
  284. const brigadeNames = [...new Set(outsideRateData.map(d => d.dutyBrigadeName))]
  285. const seriesData = brigadeNames.map((brigade, index) => ({
  286. name: brigade,
  287. type: 'line',
  288. data: dates.map(date => {
  289. const item = outsideRateData.find(d => d.statDate === date && d.dutyBrigadeName === brigade)
  290. return item ? item.avgRatePeak : 0
  291. }),
  292. itemStyle: {
  293. color: ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6'][index % 5]
  294. },
  295. lineStyle: { width: 3 },
  296. symbol: 'circle',
  297. symbolSize: 8
  298. }))
  299. setOption4({
  300. tooltip: {
  301. trigger: 'axis',
  302. formatter: function(params) {
  303. let result = params[0].name + '<br/>'
  304. params.forEach(param => {
  305. result += `${param.marker} ${param.seriesName}: ${param.value} 件/小时<br/>`
  306. })
  307. return result
  308. }
  309. },
  310. legend: {
  311. data: brigadeNames
  312. },
  313. grid: {
  314. left: '3%',
  315. right: '4%',
  316. bottom: '3%',
  317. containLabel: true
  318. },
  319. xAxis: {
  320. type: 'category',
  321. data: dates,
  322. axisLabel: {
  323. rotate: 45
  324. }
  325. },
  326. yAxis: {
  327. type: 'value',
  328. name: '速率',
  329. axisLabel: {
  330. formatter: '{value} 件/小时'
  331. }
  332. },
  333. series: seriesData
  334. })
  335. }
  336. } catch (error) {
  337. console.error('加载速率数据失败:', error)
  338. }
  339. }
  340. // 监听筛选参数变化
  341. watch(() => props.filterParams, () => {
  342. loadData()
  343. }, { deep: true })
  344. onMounted(() => {
  345. loadData()
  346. })
  347. </script>
  348. <style lang="less" scoped>
  349. .module-four-content {
  350. height: 100%;
  351. display: flex;
  352. flex-direction: column;
  353. gap: 10px;
  354. }
  355. .chart-row {
  356. flex: 1;
  357. display: flex;
  358. gap: 10px;
  359. min-height: 400px;
  360. height: 400px;
  361. }
  362. .chart-item {
  363. flex: 1;
  364. display: flex;
  365. flex-direction: column;
  366. background: #fff;
  367. border-radius: 6px;
  368. padding: 15px;
  369. border: 1px solid #eee;
  370. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  371. min-height: 400px; /* 400px */
  372. height: 100%;
  373. }
  374. .chart-title {
  375. font-size: 17px;
  376. color: black;
  377. margin-bottom: 5px;
  378. text-align: left;
  379. }
  380. .echarts {
  381. flex: 1;
  382. width: 100%;
  383. min-height: 400px; /* 400px */
  384. height: 400px;
  385. }
  386. </style>