feat 历史报告
This commit is contained in:
@@ -10,7 +10,7 @@ defineProps<{
|
||||
<view class="device-header">
|
||||
<view class="device-info">
|
||||
<text class="device-code">
|
||||
备ID: {{ deviceCode }}
|
||||
设备ID: {{ deviceCode }}
|
||||
</text>
|
||||
<text class="device-time">
|
||||
{{ time }}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const props = defineProps<{
|
||||
id?: number
|
||||
title: string
|
||||
deviceCode: string
|
||||
status: string
|
||||
@@ -15,6 +16,7 @@ const props = defineProps<{
|
||||
function goToDetail() {
|
||||
const key = `report_${Date.now()}`
|
||||
storage.set(key, {
|
||||
id: props.id,
|
||||
title: props.title,
|
||||
deviceCode: props.deviceCode,
|
||||
status: props.status,
|
||||
@@ -24,8 +26,13 @@ function goToDetail() {
|
||||
areaCount: props.areaCount,
|
||||
passRate: props.passRate,
|
||||
})
|
||||
|
||||
const query = [`key=${key}`]
|
||||
if (props.id != null)
|
||||
query.push(`id=${props.id}`)
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/report/detail/index?key=${key}`,
|
||||
url: `/pages/report/detail/index?${query.join('&')}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { HistoryReport } from '@/service/historyReport'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
import { useDbStore } from '@/store/modules/db'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
definePage({
|
||||
@@ -8,35 +12,129 @@ definePage({
|
||||
},
|
||||
})
|
||||
|
||||
const reportData = ref<any>({
|
||||
deviceCode: 'ABC123',
|
||||
time: '2025-12-15 08:30-14:30',
|
||||
interface ReportDetailView {
|
||||
deviceCode: string
|
||||
time: string
|
||||
status: string
|
||||
duration: string
|
||||
areaCount: string
|
||||
passCount: string
|
||||
passRate: string
|
||||
avgSpeed: string
|
||||
avgFrequency: string
|
||||
avgAmplitude: string
|
||||
avgTemperature: string
|
||||
avgCompaction: string
|
||||
exceptionCount: string
|
||||
}
|
||||
|
||||
const db = useDbStore()
|
||||
const reportData = ref<ReportDetailView | null>(null)
|
||||
|
||||
function parseDate(value?: string) {
|
||||
if (!value)
|
||||
return null
|
||||
const date = new Date(value.replace(/-/g, '/'))
|
||||
return Number.isNaN(date.getTime()) ? null : date
|
||||
}
|
||||
|
||||
function pad(value: number) {
|
||||
return String(value).padStart(2, '0')
|
||||
}
|
||||
|
||||
function formatDateTimeRange(start?: string, end?: string) {
|
||||
const startDate = parseDate(start)
|
||||
const endDate = parseDate(end)
|
||||
if (!startDate)
|
||||
return '-'
|
||||
|
||||
const datePart = `${startDate.getFullYear()}年${pad(startDate.getMonth() + 1)}月${pad(startDate.getDate())}日`
|
||||
const startHm = `${pad(startDate.getHours())}:${pad(startDate.getMinutes())}`
|
||||
if (!endDate)
|
||||
return `${datePart}${startHm}`
|
||||
|
||||
const endHm = `${pad(endDate.getHours())}:${pad(endDate.getMinutes())}`
|
||||
if (startDate.toDateString() === endDate.toDateString())
|
||||
return `${datePart}${startHm}-${endHm}`
|
||||
|
||||
return `${datePart}${startHm}-${endDate.getFullYear()}年${pad(endDate.getMonth() + 1)}月${pad(endDate.getDate())}日${endHm}`
|
||||
}
|
||||
|
||||
function formatDuration(value?: number) {
|
||||
const hours = value ?? 0
|
||||
const text = Number.isInteger(hours) ? String(hours) : hours.toFixed(1)
|
||||
return `${text}H`
|
||||
}
|
||||
|
||||
function formatArea(value?: number) {
|
||||
return `${value ?? 0}m²`
|
||||
}
|
||||
|
||||
function formatRate(value?: number) {
|
||||
const rate = value ?? 0
|
||||
const text = Number.isInteger(rate) ? String(rate) : rate.toFixed(1)
|
||||
return `${text}%`
|
||||
}
|
||||
|
||||
function mapReportDetail(item: HistoryReport): ReportDetailView {
|
||||
return {
|
||||
deviceCode: item.device_id || '-',
|
||||
time: formatDateTimeRange(item.start_time, item.end_time),
|
||||
status: '作业已完成',
|
||||
duration: '6H',
|
||||
areaCount: '2580m²',
|
||||
passCount: '355',
|
||||
passRate: '96.8%',
|
||||
avgSpeed: '3.8km/h',
|
||||
avgFrequency: '34Hz',
|
||||
avgAmplitude: '2.1mm',
|
||||
avgTemperature: '42℃',
|
||||
avgCompaction: '96%',
|
||||
exceptionCount: '2',
|
||||
duration: formatDuration(item.duration),
|
||||
areaCount: formatArea(item.compaction_area),
|
||||
passCount: `${item.pass_count ?? 0}遍`,
|
||||
passRate: formatRate(item.qualified_rate),
|
||||
avgSpeed: item.avg_speed != null ? `${item.avg_speed}km/h` : '-',
|
||||
avgFrequency: '-',
|
||||
avgAmplitude: '-',
|
||||
avgTemperature: item.avg_paving_temp != null ? `${item.avg_paving_temp}℃` : '-',
|
||||
avgCompaction: item.avg_compaction != null ? formatRate(item.avg_compaction) : '-',
|
||||
exceptionCount: String(item.exception_count ?? 0),
|
||||
}
|
||||
}
|
||||
|
||||
function applyStoragePayload(data: Record<string, any>) {
|
||||
reportData.value = {
|
||||
deviceCode: data.deviceCode || '-',
|
||||
time: data.time || '-',
|
||||
status: data.status || '作业已完成',
|
||||
duration: data.duration || '-',
|
||||
areaCount: data.areaCount || '-',
|
||||
passCount: data.passCount || '-',
|
||||
passRate: data.passRate || '-',
|
||||
avgSpeed: data.avgSpeed || '-',
|
||||
avgFrequency: data.avgFrequency || '-',
|
||||
avgAmplitude: data.avgAmplitude || '-',
|
||||
avgTemperature: data.avgTemperature || '-',
|
||||
avgCompaction: data.avgCompaction || '-',
|
||||
exceptionCount: data.exceptionCount || '-',
|
||||
}
|
||||
}
|
||||
|
||||
onLoad(async (options) => {
|
||||
if (options?.key) {
|
||||
const data = storage.get(options.key)
|
||||
if (data)
|
||||
applyStoragePayload(data)
|
||||
storage.remove(options.key)
|
||||
}
|
||||
|
||||
const id = Number(options?.id)
|
||||
if (!id)
|
||||
return
|
||||
|
||||
if (!db.history_report.length)
|
||||
await db.loadAll()
|
||||
|
||||
const item = db.history_report.find(report => report.id === id)
|
||||
if (item)
|
||||
reportData.value = mapReportDetail(item)
|
||||
})
|
||||
|
||||
function handleDownload() {
|
||||
console.log('点击下载')
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
if (options?.key) {
|
||||
const data = storage.get(options.key)
|
||||
if (data) {
|
||||
reportData.value = data
|
||||
storage.remove(options.key)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -46,15 +144,18 @@ onLoad((options) => {
|
||||
</back-nav>
|
||||
|
||||
<view class="content">
|
||||
<view v-if="!reportData" class="empty-tip">
|
||||
暂无报告详情
|
||||
</view>
|
||||
|
||||
<template v-else>
|
||||
<report-device-header
|
||||
v-if="reportData"
|
||||
:device-code="reportData.deviceCode"
|
||||
:time="reportData.time"
|
||||
:status="reportData.status"
|
||||
/>
|
||||
|
||||
<report-stats-card
|
||||
v-if="reportData"
|
||||
:duration="reportData.duration"
|
||||
:area-count="reportData.areaCount"
|
||||
:pass-count="reportData.passCount"
|
||||
@@ -62,7 +163,6 @@ onLoad((options) => {
|
||||
/>
|
||||
|
||||
<report-detail-metrics
|
||||
v-if="reportData"
|
||||
:avg-speed="reportData.avgSpeed"
|
||||
:avg-frequency="reportData.avgFrequency"
|
||||
:avg-amplitude="reportData.avgAmplitude"
|
||||
@@ -70,6 +170,7 @@ onLoad((options) => {
|
||||
:avg-compaction="reportData.avgCompaction"
|
||||
:exception-count="reportData.exceptionCount"
|
||||
/>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -87,4 +188,11 @@ onLoad((options) => {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { HistoryReport } from '@/service/historyReport'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useDbStore } from '@/store/modules/db'
|
||||
|
||||
definePage({
|
||||
layout: false,
|
||||
style: {
|
||||
@@ -6,53 +10,148 @@ definePage({
|
||||
},
|
||||
})
|
||||
|
||||
const datetimerange = ref([])
|
||||
const db = useDbStore()
|
||||
|
||||
const datetimerange = ref<string[]>([])
|
||||
const reportStatus = ref('')
|
||||
const area = ref('')
|
||||
const project = ref('')
|
||||
|
||||
const appliedQuery = ref({
|
||||
datetimerange: [] as string[],
|
||||
reportStatus: '',
|
||||
area: '',
|
||||
project: '',
|
||||
})
|
||||
|
||||
const reportStatusOptions = [
|
||||
{ value: 'all', text: '全部' },
|
||||
{ value: 'completed', text: '已完成' },
|
||||
{ value: 'pending', text: '待审核' },
|
||||
]
|
||||
|
||||
const areaOptions = [
|
||||
{ value: 'area1', text: '区域1' },
|
||||
{ value: 'area2', text: '区域2' },
|
||||
]
|
||||
const areaOptions = computed(() => {
|
||||
const areas = [...new Set(db.history_report.map(item => item.construction_area).filter(Boolean))] as string[]
|
||||
return [
|
||||
{ value: 'all', text: '全部' },
|
||||
...areas.map(text => ({ value: text, text })),
|
||||
]
|
||||
})
|
||||
|
||||
const projectOptions = [
|
||||
{ value: 'project1', text: '项目1' },
|
||||
{ value: 'project2', text: '项目2' },
|
||||
]
|
||||
const projectOptions = computed(() => [
|
||||
{ value: 'all', text: '全部' },
|
||||
...db.project.map(item => ({ value: String(item.id), text: item.project_name })),
|
||||
])
|
||||
|
||||
const reports = [
|
||||
{
|
||||
title: 'k1+200-k1+800压实作业报告',
|
||||
deviceCode: 'ABC123',
|
||||
const reports = computed(() => {
|
||||
const query = appliedQuery.value
|
||||
return db.history_report
|
||||
.filter(item => matchReport(item, query))
|
||||
.map(mapReportItem)
|
||||
})
|
||||
|
||||
function isAll(value: string) {
|
||||
return !value || value === 'all'
|
||||
}
|
||||
|
||||
function matchReport(
|
||||
item: HistoryReport,
|
||||
query: { datetimerange: string[], reportStatus: string, area: string, project: string },
|
||||
) {
|
||||
if (!isAll(query.project) && String(item.project_id) !== query.project)
|
||||
return false
|
||||
if (!isAll(query.area) && item.construction_area !== query.area)
|
||||
return false
|
||||
if (query.reportStatus === 'pending')
|
||||
return false
|
||||
if (!matchDateRange(item.start_time, query.datetimerange))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
function parseDate(value?: string) {
|
||||
if (!value)
|
||||
return null
|
||||
const date = new Date(value.replace(/-/g, '/'))
|
||||
return Number.isNaN(date.getTime()) ? null : date
|
||||
}
|
||||
|
||||
function matchDateRange(startTime: string | undefined, range: string[]) {
|
||||
if (!range || range.length < 2)
|
||||
return true
|
||||
const start = parseDate(startTime)
|
||||
const from = parseDate(range[0])
|
||||
const to = parseDate(range[1])
|
||||
if (!start || !from || !to)
|
||||
return false
|
||||
return start.getTime() >= from.getTime() && start.getTime() <= to.getTime()
|
||||
}
|
||||
|
||||
function pad(value: number) {
|
||||
return String(value).padStart(2, '0')
|
||||
}
|
||||
|
||||
function formatDateTimeRange(start?: string, end?: string) {
|
||||
const startDate = parseDate(start)
|
||||
const endDate = parseDate(end)
|
||||
if (!startDate)
|
||||
return '-'
|
||||
|
||||
const datePart = `${startDate.getFullYear()}年${pad(startDate.getMonth() + 1)}月${pad(startDate.getDate())}日`
|
||||
const startHm = `${pad(startDate.getHours())}:${pad(startDate.getMinutes())}`
|
||||
if (!endDate)
|
||||
return `${datePart}${startHm}`
|
||||
|
||||
const endHm = `${pad(endDate.getHours())}:${pad(endDate.getMinutes())}`
|
||||
if (startDate.toDateString() === endDate.toDateString())
|
||||
return `${datePart}${startHm}-${endHm}`
|
||||
|
||||
return `${datePart}${startHm}-${endDate.getFullYear()}年${pad(endDate.getMonth() + 1)}月${pad(endDate.getDate())}日${endHm}`
|
||||
}
|
||||
|
||||
function formatDuration(value?: number) {
|
||||
const hours = value ?? 0
|
||||
const text = Number.isInteger(hours) ? String(hours) : hours.toFixed(1)
|
||||
return `${text}H`
|
||||
}
|
||||
|
||||
function formatArea(value?: number) {
|
||||
return `${value ?? 0}m²`
|
||||
}
|
||||
|
||||
function formatRate(value?: number) {
|
||||
const rate = value ?? 0
|
||||
const text = Number.isInteger(rate) ? String(rate) : rate.toFixed(1)
|
||||
return `${text}%`
|
||||
}
|
||||
|
||||
function mapReportItem(item: HistoryReport) {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.report_name,
|
||||
deviceCode: item.device_id || '-',
|
||||
status: '已完成',
|
||||
time: '2025年12月15日08:30-14:30',
|
||||
area: 'G6高速-3标段 基层',
|
||||
duration: '6H',
|
||||
areaCount: '2580m²',
|
||||
passRate: '96.8%',
|
||||
},
|
||||
{
|
||||
title: 'k1+200-k1+800压实作业报告',
|
||||
deviceCode: 'ABC123',
|
||||
status: '已完成',
|
||||
time: '2025年12月15日08:30-14:30',
|
||||
area: 'G6高速-3标段 基层',
|
||||
duration: '6H',
|
||||
areaCount: '2580m²',
|
||||
passRate: '96.8%',
|
||||
},
|
||||
]
|
||||
time: formatDateTimeRange(item.start_time, item.end_time),
|
||||
area: item.construction_area || '-',
|
||||
duration: formatDuration(item.duration),
|
||||
areaCount: formatArea(item.compaction_area),
|
||||
passRate: formatRate(item.qualified_rate),
|
||||
}
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
console.log('查询')
|
||||
appliedQuery.value = {
|
||||
datetimerange: [...(datetimerange.value || [])],
|
||||
reportStatus: reportStatus.value,
|
||||
area: area.value,
|
||||
project: project.value,
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (!db.history_report.length)
|
||||
await db.loadAll()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -122,9 +221,13 @@ function handleQuery() {
|
||||
</view>
|
||||
|
||||
<view class="report-list">
|
||||
<view v-if="!reports.length" class="empty-tip">
|
||||
暂无历史报告
|
||||
</view>
|
||||
<report-item
|
||||
v-for="(item, index) in reports"
|
||||
:key="index"
|
||||
v-for="item in reports"
|
||||
:id="item.id"
|
||||
:key="item.id"
|
||||
:title="item.title"
|
||||
:device-code="item.deviceCode"
|
||||
:status="item.status"
|
||||
@@ -242,4 +345,11 @@ function handleQuery() {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user