|
|
@@ -1,71 +1,239 @@
|
|
|
<template>
|
|
|
- <div class="size-full flex p-4 gap-4 flex-col overflow-y-auto">
|
|
|
- <el-card class="card-1 h-[430px]">
|
|
|
- <div class="flex flex-col gap-4">
|
|
|
- <div class="flex items-center gap-4">
|
|
|
- <span class="text-[#2E3238] text-xl font-bold">离岛旅客总量统计</span>
|
|
|
- <div>
|
|
|
- <el-date-picker v-model="state.time" type="daterange" value-format="YYYY-MM-DD" />
|
|
|
+ <div class="size-full flex p-4 gap-4 flex-col overflow-hidden">
|
|
|
+ <el-scrollbar>
|
|
|
+ <el-card class="card-1 h-[430px]">
|
|
|
+ <div class="flex flex-col gap-4">
|
|
|
+ <div class="flex items-center gap-4">
|
|
|
+ <span class="text-[#2E3238] text-xl font-bold">离岛旅客总量统计</span>
|
|
|
+ <div>
|
|
|
+ <el-date-picker v-model="state.top.time" type="daterange" value-format="YYYY-MM-DD" @change="initTop" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex gap-4">
|
|
|
+ <div class="flex-1 flex flex-col gap-4">
|
|
|
+ <div
|
|
|
+ class="h-[110px] rounded-sm relative bg-[url('@/assets/images/bg-1.png')] bg-no-repeat bg-[length:100%_100%] w-full flex items-center pl-4"
|
|
|
+ >
|
|
|
+ <div class="flex flex-col gap-2">
|
|
|
+ <div class="text-base text-white">离岛旅客总量</div>
|
|
|
+ <digits v-model="state.top.total" />
|
|
|
+ </div>
|
|
|
+ <img src="@/assets/images/icon-1.png" class="absolute right-4" />
|
|
|
+ </div>
|
|
|
+ <div class="grid grid-cols-4 gap-x-4 gap-y-9">
|
|
|
+ <template v-for="(item, index) in state.top.data" :key="index">
|
|
|
+ <div class="col-span-1 text-base flex flex-col">
|
|
|
+ <div class="text-[#606266]">{{ item.name }}</div>
|
|
|
+ <div class="flex items-center gap-4">
|
|
|
+ <img v-if="item.name.includes('机场')" src="@/assets/images/icon-3.png" />
|
|
|
+ <img v-else src="@/assets/images/icon-4.png" />
|
|
|
+ <div>
|
|
|
+ <span class="text-[#606266] text-[28px] font-bold" style="font-family: cursive">{{
|
|
|
+ item.value
|
|
|
+ }}</span>
|
|
|
+ <span class="text-[#909399]">/个</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <pieChart :data="state.top.data" :total="state.top.total" />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="flex gap-4">
|
|
|
- <div class="flex-1 flex flex-col gap-4">
|
|
|
- <div
|
|
|
- class="h-[110px] rounded-sm relative bg-[url('@/assets/images/bg-1.png')] bg-no-repeat bg-[length:100%_100%] w-full flex items-center pl-4"
|
|
|
+ </el-card>
|
|
|
+ <el-card class="card-2" style="margin-top: 16px">
|
|
|
+ <div class="flex flex-col gap-4">
|
|
|
+ <div class="flex items-center">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="state.bottom.checkAll"
|
|
|
+ :indeterminate="state.bottom.isIndeterminate"
|
|
|
+ @change="handleCheckAllChange"
|
|
|
+ class="pr-4"
|
|
|
>
|
|
|
- <div class="flex flex-col gap-2">
|
|
|
- <div class="text-base text-white">离岛旅客总量</div>
|
|
|
- <digits v-model="state.guestTotal" />
|
|
|
+ 全选
|
|
|
+ </el-checkbox>
|
|
|
+ <el-checkbox-group v-model="state.bottom.areas" @change="handleCheckedChange">
|
|
|
+ <template v-for="item in areasDictCpt" :key="item.dictValue">
|
|
|
+ <el-checkbox :label="item.dictLabel" :value="item.dictValue" />
|
|
|
+ </template>
|
|
|
+ </el-checkbox-group>
|
|
|
+ <el-button type="primary" style="margin-left: auto" @click="initLines(false)">查询</el-button>
|
|
|
+ <el-button type="info" @click="initLines(true)">重置</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="grid grid-cols-2 gap-4">
|
|
|
+ <div class="h-80 shadow border/20 p-4 rounded-sm bg-white flex flex-col gap-4">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <span class="text-[#2E3238] text-[20px] font-bold">旅客日流量分析</span>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="state.bottom.chart1.time"
|
|
|
+ type="date"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ style="width: 140px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <lineChart :data="state.bottom.chart1.data" />
|
|
|
</div>
|
|
|
- <img src="@/assets/images/icon-1.png" class="absolute right-4" />
|
|
|
</div>
|
|
|
- <div class="grid grid-cols-4 gap-x-4 gap-y-9">
|
|
|
- <template v-for="(item, index) in state.topArr" :key="index">
|
|
|
- <div class="col-span-1 text-base flex flex-col">
|
|
|
- <div class="text-[#606266]">{{ item.name }}</div>
|
|
|
- <div class="flex items-center gap-4">
|
|
|
- <img v-if="item.name.includes('机场')" src="@/assets/images/icon-3.png" />
|
|
|
- <img v-else src="@/assets/images/icon-4.png" />
|
|
|
- <div>
|
|
|
- <span class="text-[#606266] text-[28px] font-bold" style="font-family: cursive">{{
|
|
|
- item.value
|
|
|
- }}</span>
|
|
|
- <span class="text-[#909399]">/个</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div class="h-80 shadow border/20 p-4 rounded-sm bg-white flex flex-col gap-4">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <span class="text-[#2E3238] text-[20px] font-bold">旅客月流量分析</span>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="state.bottom.chart2.time"
|
|
|
+ type="month"
|
|
|
+ value-format="YYYY-MM"
|
|
|
+ style="width: 120px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <lineChart :data="state.bottom.chart2.data" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="h-80 shadow border/20 p-4 rounded-sm bg-white flex flex-col gap-4">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <span class="text-[#2E3238] text-[20px] font-bold">查验成功率分析</span>
|
|
|
+ <div>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="state.bottom.chart3.time"
|
|
|
+ type="daterange"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ style="width: 220px"
|
|
|
+ />
|
|
|
</div>
|
|
|
- </template>
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <lineChart :data="state.bottom.chart3.data" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="h-80 shadow border/20 p-4 rounded-sm bg-white flex flex-col gap-4">
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <span class="text-[#2E3238] text-[20px] font-bold">拦截成功率分析</span>
|
|
|
+ <div>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="state.bottom.chart4.time"
|
|
|
+ type="daterange"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ style="width: 220px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <lineChart :data="state.bottom.chart4.data" />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div class="flex-1">
|
|
|
- <pieChart :data="state.topArr" />
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- <el-card class="card-2"> </el-card>
|
|
|
+ </el-card>
|
|
|
+ </el-scrollbar>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { onMounted, reactive } from 'vue'
|
|
|
+import { computed, onMounted, reactive } from 'vue'
|
|
|
import dayjs from 'dayjs'
|
|
|
import digits from './digits.vue'
|
|
|
import { passengerstatisticsList } from '@/apis/lvke'
|
|
|
import pieChart from './chart/pie.vue'
|
|
|
+import lineChart from './chart/line.vue'
|
|
|
|
|
|
const state: any = reactive({
|
|
|
- time: [dayjs(new Date()).format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')],
|
|
|
- guestTotal: 0,
|
|
|
- topArr: []
|
|
|
+ top: {
|
|
|
+ time: [dayjs(new Date()).format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')],
|
|
|
+ total: 0,
|
|
|
+ data: []
|
|
|
+ },
|
|
|
+ bottom: {
|
|
|
+ checkAll: false,
|
|
|
+ isIndeterminate: false,
|
|
|
+ area: [],
|
|
|
+ chart1: {
|
|
|
+ time: dayjs(new Date()).format('YYYY-MM-DD'),
|
|
|
+ data: []
|
|
|
+ },
|
|
|
+ chart2: {
|
|
|
+ time: dayjs(new Date()).format('YYYY-MM-DD'),
|
|
|
+ data: []
|
|
|
+ },
|
|
|
+ chart3: {
|
|
|
+ time: [
|
|
|
+ dayjs(new Date().getTime() - 60 * 60 * 24 * 7).format('YYYY-MM-DD'),
|
|
|
+ dayjs(new Date()).format('YYYY-MM-DD')
|
|
|
+ ],
|
|
|
+ data: []
|
|
|
+ },
|
|
|
+ chart4: {
|
|
|
+ time: [
|
|
|
+ dayjs(new Date().getTime() - 60 * 60 * 24 * 7).format('YYYY-MM-DD'),
|
|
|
+ dayjs(new Date()).format('YYYY-MM-DD')
|
|
|
+ ],
|
|
|
+ data: []
|
|
|
+ }
|
|
|
+ }
|
|
|
})
|
|
|
-onMounted(() => {
|
|
|
+const areasDictCpt = computed(() => {
|
|
|
+ return [
|
|
|
+ { dictLabel: '青龙机场', dictValue: 1 },
|
|
|
+ { dictLabel: '白虎机场', dictValue: 2 },
|
|
|
+ { dictLabel: '朱雀机场', dictValue: 3 },
|
|
|
+ { dictLabel: '玄武机场', dictValue: 4 }
|
|
|
+ ]
|
|
|
+})
|
|
|
+const handleCheckAllChange = (val: any) => {
|
|
|
+ state.bottom.areas = val ? areasDictCpt.value.map((v) => v.dictValue) : []
|
|
|
+ state.bottom.isIndeterminate = false
|
|
|
+}
|
|
|
+const handleCheckedChange = (value: any) => {
|
|
|
+ const checkedCount = value.length
|
|
|
+ state.bottom.checkAll = checkedCount === areasDictCpt.value.length
|
|
|
+ state.bottom.isIndeterminate = checkedCount > 0 && checkedCount < areasDictCpt.value.length
|
|
|
+}
|
|
|
+const initTop = () => {
|
|
|
passengerstatisticsList({ type: 1 }).then((res) => {
|
|
|
- state.topArr = res.data || []
|
|
|
- })
|
|
|
- passengerstatisticsList({ type: 2 }).then((res) => {
|
|
|
- console.log(res)
|
|
|
+ state.top.data = res.data || []
|
|
|
+ let total = 0
|
|
|
+ state.top.data.forEach((v) => {
|
|
|
+ total += Number(v.value)
|
|
|
+ })
|
|
|
+ state.top.total = total
|
|
|
})
|
|
|
+}
|
|
|
+const initLines = (reset = true) => {
|
|
|
+ if (reset) {
|
|
|
+ }
|
|
|
+ state.bottom.chart1.data = areasDictCpt.value.map((v) => ({ name: v.dictLabel, data: [] }))
|
|
|
+ for (let i = 1; i <= 24; i++) {
|
|
|
+ state.bottom.chart1.data.forEach((v) => {
|
|
|
+ v.data.push({ name: String(i), value: Math.ceil(Math.random() * 100000) })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ state.bottom.chart2.data = areasDictCpt.value.map((v) => ({ name: v.dictLabel, data: [] }))
|
|
|
+ for (let i = 1; i <= 31; i++) {
|
|
|
+ state.bottom.chart2.data.forEach((v) => {
|
|
|
+ v.data.push({ name: String(i), value: Math.ceil(Math.random() * 100000) })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ state.bottom.chart3.data = areasDictCpt.value.map((v) => ({ name: v.dictLabel, data: [] }))
|
|
|
+ for (let i = 1; i <= 31; i++) {
|
|
|
+ state.bottom.chart3.data.forEach((v) => {
|
|
|
+ v.data.push({ name: `2025-10-${i < 10 ? '0' + i : i}`, value: Math.ceil(Math.random() * 100000) })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ state.bottom.chart4.data = areasDictCpt.value.map((v) => ({ name: v.dictLabel, data: [] }))
|
|
|
+ for (let i = 1; i <= 31; i++) {
|
|
|
+ state.bottom.chart4.data.forEach((v) => {
|
|
|
+ v.data.push({ name: `2025-10-${i < 10 ? '0' + i : i}`, value: Math.ceil(Math.random() * 100000) })
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+onMounted(() => {
|
|
|
+ initTop()
|
|
|
+ initLines()
|
|
|
})
|
|
|
</script>
|
|
|
|