|
|
|
@ -1,5 +1,17 @@ |
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div class="audio-detection-container"> |
|
|
|
<div class="audio-detection-container"> |
|
|
|
|
|
|
|
<!-- 加载动画 --> |
|
|
|
|
|
|
|
<div v-if="isLoading" class="loading-overlay"> |
|
|
|
|
|
|
|
<div class="loading-spinner"></div> |
|
|
|
|
|
|
|
<span class="loading-text">加载中...</span> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 切换加载 --> |
|
|
|
|
|
|
|
<div v-if="isSwitching" class="switch-loading-overlay"> |
|
|
|
|
|
|
|
<div class="loading-spinner"></div> |
|
|
|
|
|
|
|
<span class="loading-text">数据加载中...</span> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 顶部 Header --> |
|
|
|
<!-- 顶部 Header --> |
|
|
|
<div class="header-bar"> |
|
|
|
<div class="header-bar"> |
|
|
|
<div class="header-left"> |
|
|
|
<div class="header-left"> |
|
|
|
@ -196,6 +208,12 @@ const splChartContainer = ref<HTMLElement | null>(null) |
|
|
|
let waveform: WaveSurfer | null = null |
|
|
|
let waveform: WaveSurfer | null = null |
|
|
|
let splChart: echarts.ECharts | null = null |
|
|
|
let splChart: echarts.ECharts | null = null |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 页面加载状态 |
|
|
|
|
|
|
|
const isLoading = ref(true) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 切换条码加载状态 |
|
|
|
|
|
|
|
const isSwitching = ref(false) |
|
|
|
|
|
|
|
|
|
|
|
// 定时器 |
|
|
|
// 定时器 |
|
|
|
let updateTimer: number | null = null |
|
|
|
let updateTimer: number | null = null |
|
|
|
let splUpdateTimer: number | null = null |
|
|
|
let splUpdateTimer: number | null = null |
|
|
|
@ -212,15 +230,23 @@ const resourceStatus = ref([ |
|
|
|
const stats = ref({ |
|
|
|
const stats = ref({ |
|
|
|
duration: '00:00:00', |
|
|
|
duration: '00:00:00', |
|
|
|
dba: 0, |
|
|
|
dba: 0, |
|
|
|
batchTotal: 100, |
|
|
|
batchTotal: 82, |
|
|
|
failCount: 3 |
|
|
|
failCount: 3 |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
// 检测结果状态:'pass' | 'fail' |
|
|
|
// 检测结果状态:'pass' | 'fail' |
|
|
|
const resultStatus = ref<'pass' | 'fail'>('pass') |
|
|
|
const resultStatus = ref<'pass' | 'fail'>('pass') |
|
|
|
|
|
|
|
|
|
|
|
// 条码号 |
|
|
|
// 条码号 - 使用当前日期 |
|
|
|
const barcode = ref('2026042400001') |
|
|
|
function generateBarcode(): string { |
|
|
|
|
|
|
|
const now = new Date() |
|
|
|
|
|
|
|
const year = now.getFullYear() |
|
|
|
|
|
|
|
const month = String(now.getMonth() + 1).padStart(2, '0') |
|
|
|
|
|
|
|
const day = String(now.getDate()).padStart(2, '0') |
|
|
|
|
|
|
|
return `${year}${month}${day}02102` |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const barcode = ref(generateBarcode()) |
|
|
|
|
|
|
|
|
|
|
|
// 当前条码是否已锁定(已点击合格或不合格) |
|
|
|
// 当前条码是否已锁定(已点击合格或不合格) |
|
|
|
const isLocked = ref(false) |
|
|
|
const isLocked = ref(false) |
|
|
|
@ -544,19 +570,27 @@ const handleFail = () => { |
|
|
|
|
|
|
|
|
|
|
|
// 导航按钮处理 |
|
|
|
// 导航按钮处理 |
|
|
|
const handlePrevious = () => { |
|
|
|
const handlePrevious = () => { |
|
|
|
|
|
|
|
if (isSwitching.value) return |
|
|
|
isLocked.value = false |
|
|
|
isLocked.value = false |
|
|
|
|
|
|
|
isSwitching.value = true |
|
|
|
const num = parseInt(barcode.value) - 1 |
|
|
|
const num = parseInt(barcode.value) - 1 |
|
|
|
barcode.value = num.toString().padStart(barcode.value.length, '0') |
|
|
|
barcode.value = num.toString().padStart(barcode.value.length, '0') |
|
|
|
if (isPaused.value) isPaused.value = false |
|
|
|
|
|
|
|
resultStatus.value = 'pass' |
|
|
|
resultStatus.value = 'pass' |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
isSwitching.value = false |
|
|
|
|
|
|
|
}, 1000) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleNext = () => { |
|
|
|
const handleNext = () => { |
|
|
|
|
|
|
|
if (isSwitching.value) return |
|
|
|
isLocked.value = false |
|
|
|
isLocked.value = false |
|
|
|
|
|
|
|
isSwitching.value = true |
|
|
|
const num = parseInt(barcode.value) + 1 |
|
|
|
const num = parseInt(barcode.value) + 1 |
|
|
|
barcode.value = num.toString().padStart(barcode.value.length, '0') |
|
|
|
barcode.value = num.toString().padStart(barcode.value.length, '0') |
|
|
|
if (isPaused.value) isPaused.value = false |
|
|
|
|
|
|
|
resultStatus.value = 'pass' |
|
|
|
resultStatus.value = 'pass' |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
isSwitching.value = false |
|
|
|
|
|
|
|
}, 1000) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const togglePause = () => { |
|
|
|
const togglePause = () => { |
|
|
|
@ -568,6 +602,7 @@ onMounted(() => { |
|
|
|
setTimeout(() => { |
|
|
|
setTimeout(() => { |
|
|
|
initWaveform() |
|
|
|
initWaveform() |
|
|
|
initSPLChart() |
|
|
|
initSPLChart() |
|
|
|
|
|
|
|
isLoading.value = false |
|
|
|
}, 100) |
|
|
|
}, 100) |
|
|
|
|
|
|
|
|
|
|
|
// 每 100ms 更新一次统计数据(时长、dBA、不合格数) |
|
|
|
// 每 100ms 更新一次统计数据(时长、dBA、不合格数) |
|
|
|
@ -615,6 +650,53 @@ const handleResize = () => { |
|
|
|
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 50%, #dbeafe 100%); |
|
|
|
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 50%, #dbeafe 100%); |
|
|
|
padding: 20px; |
|
|
|
padding: 20px; |
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; |
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; |
|
|
|
|
|
|
|
position: relative; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 加载动画 */ |
|
|
|
|
|
|
|
.loading-overlay { |
|
|
|
|
|
|
|
position: fixed; |
|
|
|
|
|
|
|
inset: 0; |
|
|
|
|
|
|
|
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 50%, #dbeafe 100%); |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
flex-direction: column; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
justify-content: center; |
|
|
|
|
|
|
|
gap: 20px; |
|
|
|
|
|
|
|
z-index: 9999; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.loading-spinner { |
|
|
|
|
|
|
|
width: 48px; |
|
|
|
|
|
|
|
height: 48px; |
|
|
|
|
|
|
|
border: 4px solid #e0e7ff; |
|
|
|
|
|
|
|
border-top-color: #3b82f6; |
|
|
|
|
|
|
|
border-radius: 50%; |
|
|
|
|
|
|
|
animation: spin 0.8s linear infinite; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes spin { |
|
|
|
|
|
|
|
to { transform: rotate(360deg); } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.loading-text { |
|
|
|
|
|
|
|
font-size: 16px; |
|
|
|
|
|
|
|
color: #6b7280; |
|
|
|
|
|
|
|
font-weight: 500; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 切换加载蒙版 */ |
|
|
|
|
|
|
|
.switch-loading-overlay { |
|
|
|
|
|
|
|
position: fixed; |
|
|
|
|
|
|
|
inset: 0; |
|
|
|
|
|
|
|
background: rgba(240, 249, 255, 0.85); |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
flex-direction: column; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
justify-content: center; |
|
|
|
|
|
|
|
gap: 20px; |
|
|
|
|
|
|
|
z-index: 9998; |
|
|
|
|
|
|
|
backdrop-filter: blur(2px); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 顶部 Header */ |
|
|
|
/* 顶部 Header */ |
|
|
|
|