| | |
| | | <script lang="ts" setup> |
| | | import { computed, ref } from 'vue'; |
| | | import { computed, ref, watch } from 'vue'; |
| | | |
| | | import { Page } from '@vben/common-ui'; |
| | | |
| | | import { Card, Col, DatePicker, Row } from 'ant-design-vue'; |
| | | import { Card, Col, DatePicker, Input, Row, Table } from 'ant-design-vue'; |
| | | import dayjs from 'dayjs'; |
| | | |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | import { getTraceLocationDistribution, getTraceLocationVisits } from '#/api/mes/trace-consumer-scan'; |
| | | import type { MesTraceConsumerScanApi } from '#/api/mes/trace-consumer-scan'; |
| | | |
| | | import DistributionChart from './modules/distribution-chart.vue'; |
| | | import SummaryCards from './modules/summary-cards.vue'; |
| | |
| | | |
| | | const startTime = computed(() => dateRange.value?.[0]); |
| | | const endTime = computed(() => dateRange.value?.[1]); |
| | | |
| | | const traceCode = ref(''); |
| | | const pageNo = ref(1); |
| | | const locationLoading = ref(false); |
| | | const locationRows = ref<MesTraceConsumerScanApi.LocationVisit[]>([]); |
| | | const locationDistribution = ref<MesTraceConsumerScanApi.LocationDistribution[]>([]); |
| | | const locationTotal = ref(0); |
| | | const locationColumns = [ |
| | | { title: '访问时间', dataIndex: 'visitTime', key: 'visitTime' }, |
| | | { title: '追溯码', dataIndex: 'traceCode', key: 'traceCode' }, |
| | | { title: '纬度', dataIndex: 'latitude', key: 'latitude' }, |
| | | { title: '经度', dataIndex: 'longitude', key: 'longitude' }, |
| | | { title: '精度(米)', dataIndex: 'accuracy', key: 'accuracy' }, |
| | | { title: '位置', key: 'map' }, |
| | | ]; |
| | | |
| | | async function loadLocationVisits() { |
| | | locationLoading.value = true; |
| | | try { |
| | | const page = await getTraceLocationVisits({ |
| | | pageNo: pageNo.value, |
| | | pageSize: 20, |
| | | startTime: startTime.value, |
| | | endTime: endTime.value, |
| | | traceCode: traceCode.value.trim() || undefined, |
| | | }); |
| | | locationRows.value = page.list; |
| | | locationTotal.value = page.total; |
| | | locationDistribution.value = await getTraceLocationDistribution({ |
| | | startTime: startTime.value, |
| | | endTime: endTime.value, |
| | | traceCode: traceCode.value.trim() || undefined, |
| | | }); |
| | | } finally { |
| | | locationLoading.value = false; |
| | | } |
| | | } |
| | | |
| | | watch([startTime, endTime, traceCode], () => { |
| | | pageNo.value = 1; |
| | | loadLocationVisits(); |
| | | }, { immediate: true }); |
| | | |
| | | function mapUrl(row: Record<string, any>) { |
| | | const lat = Number(row.latitude); |
| | | const lon = Number(row.longitude); |
| | | return `https://www.openstreetmap.org/?mlat=${lat}&mlon=${lon}#map=16/${lat}/${lon}`; |
| | | } |
| | | |
| | | function handleLocationPageChange(pagination: { current?: number }) { |
| | | pageNo.value = pagination.current || 1; |
| | | loadLocationVisits(); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | <DistributionChart :start-time="startTime" :end-time="endTime" /> |
| | | </Col> |
| | | </Row> |
| | | |
| | | <Card title="定位授权访问" class="mb-4"> |
| | | <p class="mb-3 text-sm text-muted-foreground"> |
| | | 当前筛选条件下共 {{ locationTotal }} 次授权定位访问;下表显示用户授权后上传的位置及定位精度。 |
| | | </p> |
| | | <Input v-model:value="traceCode" class="mb-3 max-w-xs" allow-clear placeholder="按追溯码筛选" /> |
| | | <div v-if="locationDistribution.length" class="mb-4"> |
| | | <div class="mb-2 font-medium">热门位置(坐标保留两位小数,最多 20 处)</div> |
| | | <div class="flex flex-wrap gap-2"> |
| | | <span v-for="item in locationDistribution" :key="`${item.latitude},${item.longitude}`" class="rounded bg-green-50 px-3 py-1 text-sm text-green-800"> |
| | | {{ item.latitude }}, {{ item.longitude }}:{{ item.count }} 次 |
| | | </span> |
| | | </div> |
| | | </div> |
| | | <Table |
| | | :columns="locationColumns" |
| | | :data-source="locationRows" |
| | | :loading="locationLoading" |
| | | :pagination="{ current: pageNo, pageSize: 20, total: locationTotal, showSizeChanger: false }" |
| | | :row-key="(row: MesTraceConsumerScanApi.LocationVisit) => row.id" |
| | | :scroll="{ x: 850 }" |
| | | @change="handleLocationPageChange" |
| | | > |
| | | <template #bodyCell="{ column, record }"> |
| | | <a v-if="column.key === 'map'" :href="mapUrl(record)" target="_blank" rel="noopener noreferrer">查看地图</a> |
| | | </template> |
| | | </Table> |
| | | </Card> |
| | | </Page> |
| | | </template> |