From d5d3f57f11d829909bd2b55bc1bab331b69a1607 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 18 八月 2025 15:28:24 +0800
Subject: [PATCH] 中强恒兴质量管理页面添加
---
src/views/reportAnalysis/reportManagement/index.vue | 716 +++++++++++++++++++++++
src/views/qualityManagement/visualization/qualityDashboard.vue | 307 ++++++++++
src/views/qualityManagement/nonconformingManagement/index.vue | 7
src/views/reportAnalysis/reportManagement.vue | 733 ++++++++++++++++++++++++
4 files changed, 1,760 insertions(+), 3 deletions(-)
diff --git a/src/views/qualityManagement/nonconformingManagement/index.vue b/src/views/qualityManagement/nonconformingManagement/index.vue
index d3ac667..169a2f3 100644
--- a/src/views/qualityManagement/nonconformingManagement/index.vue
+++ b/src/views/qualityManagement/nonconformingManagement/index.vue
@@ -4,7 +4,7 @@
<div style="display: flex;flex-direction: row;align-items: center;">
<div>
<span class="search_title">绫诲瀷锛�</span>
- <el-select v-model="searchForm.inspectType" clearable style="width: 240px" @change="handleQuery">
+ <el-select v-model="searchForm.inspectType" clearable style="width: 200px" @change="handleQuery">
<el-option label="鍘熸潗鏂欐楠�" :value="0" />
<el-option label="杩囩▼妫�楠�" :value="1" />
<el-option label="鍑哄巶妫�楠�" :value="2" />
@@ -12,7 +12,7 @@
</div>
<div style="margin-left: 10px">
<span class="search_title">鐘舵�侊細</span>
- <el-select v-model="searchForm.inspectState" clearable style="width: 240px" @change="handleQuery">
+ <el-select v-model="searchForm.inspectState" clearable style="width: 200px" @change="handleQuery">
<el-option label="寰呭鐞�" :value="0" />
<el-option label="宸插鐞�" :value="1" />
</el-select>
@@ -21,7 +21,7 @@
<span class="search_title">浜у搧鍚嶇О锛�</span>
<el-input
v-model="searchForm.productName"
- style="width: 240px"
+ style="width: 200px"
placeholder="璇疯緭鍏ヤ骇鍝佸悕绉版悳绱�"
@change="handleQuery"
clearable
@@ -30,6 +30,7 @@
</div>
<span style="margin-left: 10px" class="search_title">妫�娴嬫棩鏈燂細</span>
<el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
+ style="width: 300px"
placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
<el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
</div>
diff --git a/src/views/qualityManagement/visualization/qualityDashboard.vue b/src/views/qualityManagement/visualization/qualityDashboard.vue
new file mode 100644
index 0000000..57462b7
--- /dev/null
+++ b/src/views/qualityManagement/visualization/qualityDashboard.vue
@@ -0,0 +1,307 @@
+<template>
+ <div class="quality-dashboard">
+ <el-row :gutter="16">
+ <el-col :xs="24" :sm="12">
+ <el-card shadow="hover" class="panel">
+ <template #header>
+ <div class="panel-title">
+ 妫�娴嬫牱鍝佸姩鎬佺姸鎬�
+ <div class="actions">
+ <el-switch v-model="voiceEnabled" active-text="璇煶棰勮" inactive-text="闈欓煶" />
+ </div>
+ </div>
+ </template>
+ <div class="status-list">
+ <div v-for="item in sampleStatus" :key="item.id" class="status-item" :class="item.status">
+ <div class="left">
+ <span class="dot" :class="item.status"></span>
+ <span class="name">{{ item.name }}</span>
+ </div>
+ <div class="right">
+ <el-tag :type="statusTagType(item.status)" size="small">{{ statusLabel(item.status) }}</el-tag>
+ <span class="time">{{ item.time }}</span>
+ </div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :xs="24" :sm="12">
+ <el-card shadow="hover" class="panel">
+ <template #header>
+ <div class="panel-title">浠诲姟鎺掕锛圱op 10锛�</div>
+ </template>
+ <EChart :xAxis="tasksXAxis" :yAxis="[{ type: 'value' }]" :series="tasksSeries" :grid="{ left: 40, right: 20, top: 20, bottom: 40 }" :tooltip="{ trigger: 'axis' }" :barColors="['#3b82f6']" :chartStyle="{ height: '320px', width: '100%' }" />
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="16" style="margin-top: 16px;">
+ <el-col :xs="24" :sm="14">
+ <el-card shadow="hover" class="panel">
+ <template #header>
+ <div class="panel-title">鍘嗗彶瓒嬪娍</div>
+ </template>
+ <EChart :xAxis="[{ type: 'category', data: trendXAxis }]" :yAxis="[{ type: 'value', name: '鏁伴噺' }]" :series="trendSeries" :tooltip="{ trigger: 'axis' }" :legend="{ top: 0 }" :lineColors="['#10b981', '#f59e0b']" :chartStyle="{ height: '340px', width: '100%' }" />
+ </el-card>
+ </el-col>
+ <el-col :xs="24" :sm="10">
+ <el-card shadow="hover" class="panel">
+ <template #header>
+ <div class="panel-title">鍚堟牸鐜囧垎鏋�</div>
+ </template>
+ <EChart :series="passRateSeries" :legend="{ show: false }" :chartStyle="{ height: '340px', width: '100%' }" />
+ <div class="passrate-text">
+ 褰撳墠鍚堟牸鐜囷細<b>{{ (passRate * 100).toFixed(1) }}%</b>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="16" style="margin-top: 16px;">
+ <el-col :xs="24">
+ <el-card shadow="hover" class="panel">
+ <template #header>
+ <div class="panel-title">SPC 鎺у埗鍥撅紙Xbar锛�</div>
+ </template>
+ <EChart :xAxis="[{ type: 'category', data: spcXAxis }]" :yAxis="[{ type: 'value', name: '娴嬮噺鍊�' }]" :series="spcSeries" :legend="{ top: 0 }" :tooltip="{ trigger: 'axis' }" :lineColors="['#2563eb', '#ef4444', '#f97316', '#22c55e']" :chartStyle="{ height: '380px', width: '100%' }" />
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+</template>
+
+<script setup>
+import { onMounted, onBeforeUnmount, reactive, ref } from 'vue'
+import EChart from '@/components/Echarts/echarts.vue'
+
+const voiceEnabled = ref(true)
+let dataTimer = null
+
+// 1) 鏍峰搧鍔ㄦ�佺姸鎬侊紙婊氬姩鏇存柊锛�
+const sampleStatus = ref([])
+const statusPool = ['processing', 'warning', 'error', 'success']
+function statusLabel(s) {
+ return s === 'processing' ? '妫�娴嬩腑' : s === 'warning' ? '棰勮' : s === 'error' ? '涓嶅悎鏍�' : '鍚堟牸'
+}
+function statusTagType(s) {
+ return s === 'processing' ? 'info' : s === 'warning' ? 'warning' : s === 'error' ? 'danger' : 'success'
+}
+function randomSample() {
+ const id = Math.random().toString(36).slice(2, 8)
+ const status = statusPool[Math.floor(Math.random() * statusPool.length)]
+ const name = `鏍峰搧-${Math.floor(Math.random() * 900 + 100)}`
+ const time = new Date().toLocaleTimeString('zh-CN', { hour12: false })
+ return { id, name, status, time }
+}
+
+// 2) 浠诲姟鎺掕锛堟煴鐘跺浘锛�
+const tasksXAxis = reactive([{ type: 'category', data: [] }])
+const tasksSeries = ref([
+ {
+ type: 'bar',
+ data: [],
+ label: { show: true, position: 'inside', align: 'center', verticalAlign: 'middle', color: '#fff' },
+ encode: undefined,
+ },
+])
+
+// 3) 鍘嗗彶瓒嬪娍锛堟姌绾匡級
+const trendXAxis = ref([])
+const trendSeries = ref([
+ { name: '鏉ユ牱鏁�', type: 'line', smooth: true, data: [] },
+ { name: '瀹屾垚鏁�', type: 'line', smooth: true, data: [] },
+])
+
+// 4) 鍚堟牸鐜囧垎鏋愶紙浠〃鐩橈級
+const passRate = ref(0.92)
+const passRateSeries = ref([
+ {
+ type: 'gauge',
+ progress: { show: true, width: 12 },
+ axisLine: { lineStyle: { width: 12 } },
+ pointer: { show: true },
+ detail: { valueAnimation: true, formatter: (v) => `${(v * 100).toFixed(1)}%` },
+ data: [{ value: passRate.value }],
+ },
+])
+
+// 5) SPC 鎺у埗鍥�
+const spcXAxis = ref([])
+const spcData = ref([]) // 瀹為檯娴嬮噺鍊�
+const CL = ref(50)
+const UCL = ref(55)
+const LCL = ref(45)
+const spcSeries = ref([
+ {
+ name: '娴嬮噺鍧囧��',
+ type: 'line',
+ smooth: false,
+ symbol: 'circle',
+ data: [],
+ markLine: {
+ symbol: 'none',
+ lineStyle: { type: 'dashed', color: '#999' },
+ data: [
+ { yAxis: () => UCL.value, name: 'UCL' },
+ { yAxis: () => CL.value, name: 'CL' },
+ { yAxis: () => LCL.value, name: 'LCL' },
+ ],
+ label: { formatter: ({ name }) => name },
+ },
+ },
+ { name: 'UCL', type: 'line', data: [], symbol: 'none', lineStyle: { type: 'dashed', color: '#ef4444' } },
+ { name: 'CL', type: 'line', data: [], symbol: 'none', lineStyle: { type: 'dashed', color: '#f97316' } },
+ { name: 'LCL', type: 'line', data: [], symbol: 'none', lineStyle: { type: 'dashed', color: '#22c55e' } },
+])
+
+// 璇煶鎾姤
+function speak(text) {
+ if (!voiceEnabled.value) return
+ if (!('speechSynthesis' in window)) return
+ const utter = new SpeechSynthesisUtterance(text)
+ utter.lang = 'zh-CN'
+ try {
+ window.speechSynthesis.cancel()
+ window.speechSynthesis.speak(utter)
+ } catch (e) {
+ // ignore
+ }
+}
+
+function refreshFakeData() {
+ // 鏍峰搧鐘舵�佹粴鍔�
+ const next = randomSample()
+ sampleStatus.value = [next, ...sampleStatus.value].slice(0, 8)
+
+ // 浠诲姟鎺掕
+ const tasks = Array.from({ length: 10 }).map((_, i) => ({ name: `浠诲姟-${i + 1}`, count: Math.floor(Math.random() * 100 + 20) }))
+ tasks.sort((a, b) => a.count - b.count)
+ tasksXAxis.data = tasks.map(t => t.name)
+ tasksSeries.value[0].data = tasks.map(t => t.count)
+
+ // 鍘嗗彶瓒嬪娍锛堣拷鍔犵偣锛�
+ const nowLabel = new Date().toLocaleTimeString('zh-CN', { minute: '2-digit', second: '2-digit' })
+ if (trendXAxis.value.length > 15) {
+ trendXAxis.value.shift()
+ trendSeries.value[0].data.shift()
+ trendSeries.value[1].data.shift()
+ }
+ trendXAxis.value.push(nowLabel)
+ const incoming = Math.floor(Math.random() * 30 + 20)
+ const finished = Math.max(0, incoming - Math.floor(Math.random() * 10))
+ trendSeries.value[0].data.push(incoming)
+ trendSeries.value[1].data.push(finished)
+
+ // 鍚堟牸鐜囷紙杞诲井娉㈠姩锛�
+ const delta = (Math.random() - 0.5) * 0.02
+ passRate.value = Math.min(0.99, Math.max(0.6, passRate.value + delta))
+ passRateSeries.value[0].data[0].value = passRate.value
+
+ // SPC 鏁版嵁锛堢獥鍙gЩ鍔級
+ const nextVal = CL.value + (Math.random() - 0.5) * 8 // 娉㈠姩
+ if (spcXAxis.value.length > 30) {
+ spcXAxis.value.shift()
+ spcData.value.shift()
+ }
+ spcXAxis.value.push(`${spcXAxis.value.length + 1}`)
+ spcData.value.push(parseFloat(nextVal.toFixed(2)))
+ spcSeries.value[0].data = [...spcData.value]
+ spcSeries.value[1].data = new Array(spcData.value.length).fill(UCL.value)
+ spcSeries.value[2].data = new Array(spcData.value.length).fill(CL.value)
+ spcSeries.value[3].data = new Array(spcData.value.length).fill(LCL.value)
+
+ // 瑙﹀彂鎾姤锛氬悎鏍肩巼杩囦綆鎴� SPC 瓒呴檺
+ if (passRate.value < 0.8) {
+ speak(`棰勮锛屽綋鍓嶅悎鏍肩巼涓� ${(passRate.value * 100).toFixed(0)}%锛屼綆浜� 80% 闃堝�糮)
+ }
+ const last = spcData.value[spcData.value.length - 1]
+ if (last > UCL.value) {
+ speak(`棰勮锛屾渶鏂版祴閲忓�� ${last.toFixed(2)} 瓒呰繃涓婇檺`)
+ }
+ if (last < LCL.value) {
+ speak(`棰勮锛屾渶鏂版祴閲忓�� ${last.toFixed(2)} 浣庝簬涓嬮檺`)
+ }
+}
+
+onMounted(() => {
+ // 鍒濆鍖栧嚑鏉″亣鏁版嵁
+ sampleStatus.value = Array.from({ length: 5 }).map(() => randomSample())
+ for (let i = 0; i < 10; i++) {
+ trendXAxis.value.push(`T-${i}`)
+ trendSeries.value[0].data.push(Math.floor(Math.random() * 30 + 20))
+ trendSeries.value[1].data.push(Math.floor(Math.random() * 25 + 15))
+ }
+ for (let i = 0; i < 20; i++) {
+ spcXAxis.value.push(`${i + 1}`)
+ const v = CL.value + (Math.random() - 0.5) * 6
+ spcData.value.push(parseFloat(v.toFixed(2)))
+ }
+ spcSeries.value[0].data = [...spcData.value]
+ spcSeries.value[1].data = new Array(spcData.value.length).fill(UCL.value)
+ spcSeries.value[2].data = new Array(spcData.value.length).fill(CL.value)
+ spcSeries.value[3].data = new Array(spcData.value.length).fill(LCL.value)
+
+ dataTimer = setInterval(refreshFakeData, 10000)
+})
+
+onBeforeUnmount(() => {
+ if (dataTimer) clearInterval(dataTimer)
+ try { window.speechSynthesis && window.speechSynthesis.cancel() } catch (e) {}
+})
+</script>
+
+<style scoped>
+.quality-dashboard {
+ padding: 8px;
+}
+.panel-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-weight: 600;
+}
+.status-list {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ max-height: 320px;
+ overflow: auto;
+}
+.status-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 10px;
+ border-radius: 6px;
+ background: var(--el-fill-color-light);
+}
+.status-item .left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+.status-item .right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+.status-item .name { font-weight: 500; }
+.status-item .time { color: var(--el-text-color-secondary); font-size: 12px; }
+.dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ display: inline-block;
+}
+.dot.processing { background: #60a5fa; }
+.dot.warning { background: #f59e0b; }
+.dot.error { background: #ef4444; }
+.dot.success { background: #10b981; }
+.passrate-text {
+ text-align: center;
+ margin-top: 8px;
+}
+</style>
+
+
diff --git a/src/views/reportAnalysis/reportManagement.vue b/src/views/reportAnalysis/reportManagement.vue
new file mode 100644
index 0000000..02babb5
--- /dev/null
+++ b/src/views/reportAnalysis/reportManagement.vue
@@ -0,0 +1,733 @@
+<template>
+ <div class="report-management">
+ <!-- 椤甸潰鏍囬 -->
+ <div class="page-header">
+ <h2>鎶ヨ〃绠$悊</h2>
+ <p>鎻愪緵鏍峰搧杩涘害銆佽澶囦娇鐢ㄣ�佹娴嬮」鐩�侀鐢ㄨ褰曠瓑鍚勭被鑷姩缁熻鎶ヨ〃</p>
+ </div>
+
+ <!-- 绛涢�夋潯浠� -->
+ <el-card class="filter-card" shadow="never">
+ <el-form :model="filterForm" inline>
+ <el-form-item label="鏃堕棿鑼冨洿">
+ <el-date-picker
+ v-model="filterForm.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ @change="handleFilterChange"
+ />
+ </el-form-item>
+ <el-form-item label="鎶ヨ〃绫诲瀷">
+ <el-select v-model="filterForm.reportType" placeholder="璇烽�夋嫨鎶ヨ〃绫诲瀷" @change="handleFilterChange">
+ <el-option label="鏍峰搧杩涘害鎶ヨ〃" value="sample" />
+ <el-option label="璁惧浣跨敤鎶ヨ〃" value="equipment" />
+ <el-option label="妫�娴嬮」鐩姤琛�" value="inspection" />
+ <el-option label="棰嗙敤璁板綍鎶ヨ〃" value="usage" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleFilterChange">鏌ヨ</el-button>
+ <el-button @click="resetFilter">閲嶇疆</el-button>
+ <el-button type="success" @click="exportReport">瀵煎嚭鎶ヨ〃</el-button>
+ </el-form-item>
+ </el-form>
+ </el-card>
+
+ <!-- 缁熻鍗$墖 -->
+ <div class="statistics-cards">
+ <el-row :gutter="20">
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><Box /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.totalSamples }}</div>
+ <div class="stat-label">鎬绘牱鍝佹暟</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><Tools /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.activeEquipment }}</div>
+ <div class="stat-label">鍦ㄧ敤璁惧</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><Document /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.completedInspections }}</div>
+ <div class="stat-label">宸插畬鎴愭娴�</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><ShoppingCart /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.totalUsage }}</div>
+ <div class="stat-label">鎬婚鐢ㄦ鏁�</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 鍥捐〃鍖哄煙 -->
+ <div class="charts-container">
+ <el-row :gutter="20">
+ <!-- 鏍峰搧杩涘害鍥捐〃 -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>鏍峰搧杩涘害缁熻</span>
+ <el-button type="text" @click="refreshSampleChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="sampleChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+
+ <!-- 璁惧浣跨敤鍥捐〃 -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>璁惧浣跨敤鐜囩粺璁�</span>
+ <el-button type="text" @click="refreshEquipmentChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="equipmentChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20" style="margin-top: 20px;">
+ <!-- 妫�娴嬮」鐩粺璁� -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>妫�娴嬮」鐩垎甯�</span>
+ <el-button type="text" @click="refreshInspectionChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="inspectionChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+
+ <!-- 棰嗙敤璁板綍瓒嬪娍 -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>棰嗙敤璁板綍瓒嬪娍</span>
+ <el-button type="text" @click="refreshUsageChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="usageChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 璇︾粏鏁版嵁琛ㄦ牸 -->
+ <el-card class="table-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>璇︾粏鏁版嵁</span>
+ <div>
+ <el-button type="primary" size="small" @click="refreshTable">鍒锋柊</el-button>
+ <el-button type="success" size="small" @click="exportTable">瀵煎嚭</el-button>
+ </div>
+ </div>
+ </template>
+
+ <el-table
+ :data="tableData"
+ style="width: 100%"
+ v-loading="tableLoading"
+ stripe
+ border
+ >
+ <el-table-column prop="id" label="缂栧彿" width="80" />
+ <el-table-column prop="name" label="鍚嶇О" />
+ <el-table-column prop="type" label="绫诲瀷" width="120" />
+ <el-table-column prop="status" label="鐘舵��" width="100">
+ <template #default="scope">
+ <el-tag :type="getStatusType(scope.row.status)">
+ {{ scope.row.status }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="progress" label="杩涘害" width="120">
+ <template #default="scope">
+ <el-progress :percentage="scope.row.progress" :status="getProgressStatus(scope.row.progress)" />
+ </template>
+ </el-table-column>
+ <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" width="180" />
+ <el-table-column prop="updateTime" label="鏇存柊鏃堕棿" width="180" />
+ <el-table-column label="鎿嶄綔" width="150" fixed="right">
+ <template #default="scope">
+ <el-button type="text" size="small" @click="viewDetail(scope.row)">鏌ョ湅</el-button>
+ <el-button type="text" size="small" @click="editItem(scope.row)">缂栬緫</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <div class="pagination-container">
+ <el-pagination
+ v-model:current-page="pagination.currentPage"
+ v-model:page-size="pagination.pageSize"
+ :page-sizes="[10, 20, 50, 100]"
+ :total="pagination.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+ </el-card>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, nextTick } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import * as echarts from 'echarts'
+import { Box, Tools, Document, ShoppingCart } from '@element-plus/icons-vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const filterForm = reactive({
+ dateRange: [],
+ reportType: 'sample'
+})
+
+const statistics = reactive({
+ totalSamples: 1250,
+ activeEquipment: 45,
+ completedInspections: 890,
+ totalUsage: 2340
+})
+
+const tableData = ref([])
+const tableLoading = ref(false)
+const pagination = reactive({
+ currentPage: 1,
+ pageSize: 20,
+ total: 0
+})
+
+// 鍥捐〃寮曠敤
+const sampleChartRef = ref(null)
+const equipmentChartRef = ref(null)
+const inspectionChartRef = ref(null)
+const usageChartRef = ref(null)
+
+// 鍥捐〃瀹炰緥
+let sampleChart = null
+let equipmentChart = null
+let inspectionChart = null
+let usageChart = null
+
+// 鍒濆鍖栨暟鎹�
+const initData = () => {
+ // 妯℃嫙琛ㄦ牸鏁版嵁
+ tableData.value = [
+ {
+ id: 'SP001',
+ name: '鏍峰搧A-001',
+ type: '閲戝睘鏉愭枡',
+ status: '妫�娴嬩腑',
+ progress: 75,
+ createTime: '2024-01-15 09:30:00',
+ updateTime: '2024-01-20 14:20:00'
+ },
+ {
+ id: 'SP002',
+ name: '鏍峰搧B-002',
+ type: '濉戞枡鍒跺搧',
+ status: '宸插畬鎴�',
+ progress: 100,
+ createTime: '2024-01-10 10:15:00',
+ updateTime: '2024-01-18 16:45:00'
+ },
+ {
+ id: 'SP003',
+ name: '鏍峰搧C-003',
+ type: '鐢靛瓙鍏冧欢',
+ status: '寰呮娴�',
+ progress: 0,
+ createTime: '2024-01-22 08:45:00',
+ updateTime: '2024-01-22 08:45:00'
+ },
+ {
+ id: 'EQ001',
+ name: '妫�娴嬭澶嘇',
+ type: '鍏夎氨浠�',
+ status: '浣跨敤涓�',
+ progress: 60,
+ createTime: '2024-01-05 14:20:00',
+ updateTime: '2024-01-20 11:30:00'
+ },
+ {
+ id: 'EQ002',
+ name: '妫�娴嬭澶嘊',
+ type: '鏄惧井闀�',
+ status: '绌洪棽',
+ progress: 0,
+ createTime: '2024-01-08 16:10:00',
+ updateTime: '2024-01-19 09:15:00'
+ }
+ ]
+
+ pagination.total = tableData.value.length
+}
+
+// 鍒濆鍖栨牱鍝佽繘搴﹀浘琛�
+const initSampleChart = () => {
+ if (sampleChartRef.value) {
+ sampleChart = echarts.init(sampleChartRef.value)
+ const option = {
+ title: {
+ text: '鏍峰搧杩涘害鍒嗗竷',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left'
+ },
+ series: [
+ {
+ name: '鏍峰搧鐘舵��',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: false,
+ position: 'center'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '18',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: [
+ { value: 450, name: '宸插畬鎴�' },
+ { value: 320, name: '妫�娴嬩腑' },
+ { value: 280, name: '寰呮娴�' },
+ { value: 200, name: '宸叉殏鍋�' }
+ ]
+ }
+ ]
+ }
+ sampleChart.setOption(option)
+ }
+}
+
+// 鍒濆鍖栬澶囦娇鐢ㄥ浘琛�
+const initEquipmentChart = () => {
+ if (equipmentChartRef.value) {
+ equipmentChart = echarts.init(equipmentChartRef.value)
+ const option = {
+ title: {
+ text: '璁惧浣跨敤鐜�',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow'
+ }
+ },
+ xAxis: {
+ type: 'category',
+ data: ['鍏夎氨浠�', '鏄惧井闀�', '纭害璁�', '鎷夊姏鏈�', '鍐插嚮鏈�', '閲戠浉浠�']
+ },
+ yAxis: {
+ type: 'value',
+ name: '浣跨敤鐜�(%)'
+ },
+ series: [
+ {
+ name: '浣跨敤鐜�',
+ type: 'bar',
+ data: [85, 60, 75, 90, 45, 70],
+ label: {
+ show: true,
+ position: 'inside',
+ align: 'center',
+ verticalAlign: 'middle',
+ formatter: '{c}%',
+ color: '#fff'
+ },
+ itemStyle: {
+ color: function(params) {
+ const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#9C27B0']
+ return colors[params.dataIndex]
+ }
+ }
+ }
+ ]
+ }
+ equipmentChart.setOption(option)
+ }
+}
+
+// 鍒濆鍖栨娴嬮」鐩浘琛�
+const initInspectionChart = () => {
+ if (inspectionChartRef.value) {
+ inspectionChart = echarts.init(inspectionChartRef.value)
+ const option = {
+ title: {
+ text: '妫�娴嬮」鐩垎甯�',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'item'
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left'
+ },
+ series: [
+ {
+ name: '妫�娴嬮」鐩�',
+ type: 'pie',
+ radius: '50%',
+ data: [
+ { value: 335, name: '鐗╃悊鎬ц兘' },
+ { value: 310, name: '鍖栧鍒嗘瀽' },
+ { value: 234, name: '灏哄娴嬮噺' },
+ { value: 135, name: '澶栬妫�鏌�' },
+ { value: 148, name: '鍏朵粬妫�娴�' }
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ }
+ }
+ ]
+ }
+ inspectionChart.setOption(option)
+ }
+}
+
+// 鍒濆鍖栭鐢ㄨ褰曞浘琛�
+const initUsageChart = () => {
+ if (usageChartRef.value) {
+ usageChart = echarts.init(usageChartRef.value)
+ const option = {
+ title: {
+ text: '棰嗙敤璁板綍瓒嬪娍',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'axis'
+ },
+ legend: {
+ data: ['棰嗙敤娆℃暟', '褰掕繕娆℃暟']
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ data: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�', '8鏈�', '9鏈�', '10鏈�', '11鏈�', '12鏈�']
+ },
+ yAxis: {
+ type: 'value'
+ },
+ series: [
+ {
+ name: '棰嗙敤娆℃暟',
+ type: 'line',
+ stack: 'Total',
+ data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330]
+ },
+ {
+ name: '褰掕繕娆℃暟',
+ type: 'line',
+ stack: 'Total',
+ data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320]
+ }
+ ]
+ }
+ usageChart.setOption(option)
+ }
+}
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleFilterChange = () => {
+ ElMessage.success('绛涢�夋潯浠跺凡鏇存柊')
+ // 杩欓噷鍙互鏍规嵁绛涢�夋潯浠堕噸鏂板姞杞芥暟鎹�
+}
+
+const resetFilter = () => {
+ filterForm.dateRange = []
+ filterForm.reportType = 'sample'
+ ElMessage.info('绛涢�夋潯浠跺凡閲嶇疆')
+}
+
+const exportReport = () => {
+ ElMessage.success('鎶ヨ〃瀵煎嚭鍔熻兘寮�鍙戜腑...')
+}
+
+const refreshSampleChart = () => {
+ initSampleChart()
+ ElMessage.success('鏍峰搧杩涘害鍥捐〃宸插埛鏂�')
+}
+
+const refreshEquipmentChart = () => {
+ initEquipmentChart()
+ ElMessage.success('璁惧浣跨敤鍥捐〃宸插埛鏂�')
+}
+
+const refreshInspectionChart = () => {
+ initInspectionChart()
+ ElMessage.success('妫�娴嬮」鐩浘琛ㄥ凡鍒锋柊')
+}
+
+const refreshUsageChart = () => {
+ initUsageChart()
+ ElMessage.success('棰嗙敤璁板綍鍥捐〃宸插埛鏂�')
+}
+
+const refreshTable = () => {
+ tableLoading.value = true
+ setTimeout(() => {
+ tableLoading.value = false
+ ElMessage.success('琛ㄦ牸鏁版嵁宸插埛鏂�')
+ }, 1000)
+}
+
+const exportTable = () => {
+ ElMessage.success('琛ㄦ牸瀵煎嚭鍔熻兘寮�鍙戜腑...')
+}
+
+const handleSizeChange = (val) => {
+ pagination.pageSize = val
+ // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const handleCurrentChange = (val) => {
+ pagination.currentPage = val
+ // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const getStatusType = (status) => {
+ const statusMap = {
+ '宸插畬鎴�': 'success',
+ '妫�娴嬩腑': 'warning',
+ '寰呮娴�': 'info',
+ '宸叉殏鍋�': 'danger',
+ '浣跨敤涓�': 'primary',
+ '绌洪棽': 'info'
+ }
+ return statusMap[status] || 'info'
+}
+
+const getProgressStatus = (progress) => {
+ if (progress === 100) return 'success'
+ if (progress >= 80) return 'warning'
+ if (progress >= 50) return ''
+ return 'exception'
+}
+
+const viewDetail = (row) => {
+ ElMessage.info(`鏌ョ湅璇︽儏: ${row.name}`)
+}
+
+const editItem = (row) => {
+ ElMessage.info(`缂栬緫椤圭洰: ${row.name}`)
+}
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+ initData()
+ nextTick(() => {
+ initSampleChart()
+ initEquipmentChart()
+ initInspectionChart()
+ initUsageChart()
+ })
+
+ // 鐩戝惉绐楀彛澶у皬鍙樺寲锛岄噸鏂拌皟鏁村浘琛ㄥぇ灏�
+ window.addEventListener('resize', () => {
+ sampleChart?.resize()
+ equipmentChart?.resize()
+ inspectionChart?.resize()
+ usageChart?.resize()
+ })
+})
+</script>
+
+<style scoped>
+.report-management {
+ padding: 20px;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+}
+
+.page-header {
+ margin-bottom: 20px;
+ text-align: center;
+}
+
+.page-header h2 {
+ color: #303133;
+ margin-bottom: 8px;
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.page-header p {
+ color: #909399;
+ font-size: 14px;
+ margin: 0;
+}
+
+.filter-card {
+ margin-bottom: 20px;
+}
+
+.statistics-cards {
+ margin-bottom: 20px;
+}
+
+.stat-card {
+ height: 120px;
+}
+
+.stat-content {
+ display: flex;
+ align-items: center;
+ height: 100%;
+}
+
+.stat-icon {
+ width: 60px;
+ height: 60px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 20px;
+ font-size: 24px;
+ color: white;
+}
+
+.stat-card:nth-child(1) .stat-icon {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+}
+
+.stat-card:nth-child(2) .stat-icon {
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+}
+
+.stat-card:nth-child(3) .stat-icon {
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+}
+
+.stat-card:nth-child(4) .stat-icon {
+ background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
+}
+
+.stat-info {
+ flex: 1;
+}
+
+.stat-number {
+ font-size: 28px;
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 8px;
+}
+
+.stat-label {
+ font-size: 14px;
+ color: #909399;
+}
+
+.charts-container {
+ margin-bottom: 20px;
+}
+
+.chart-card {
+ margin-bottom: 20px;
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.chart-container {
+ height: 300px;
+ width: 100%;
+}
+
+.table-card {
+ margin-bottom: 20px;
+}
+
+.pagination-container {
+ margin-top: 20px;
+ text-align: right;
+}
+
+:deep(.el-card__header) {
+ padding: 15px 20px;
+ border-bottom: 1px solid #ebeef5;
+ background-color: #fafafa;
+}
+
+:deep(.el-card__body) {
+ padding: 20px;
+}
+
+:deep(.el-table) {
+ margin-bottom: 20px;
+}
+
+:deep(.el-progress) {
+ margin: 0;
+}
+
+:deep(.el-tag) {
+ margin: 0;
+}
+</style>
diff --git a/src/views/reportAnalysis/reportManagement/index.vue b/src/views/reportAnalysis/reportManagement/index.vue
new file mode 100644
index 0000000..b25619c
--- /dev/null
+++ b/src/views/reportAnalysis/reportManagement/index.vue
@@ -0,0 +1,716 @@
+<template>
+ <div class="report-management">
+ <!-- 绛涢�夋潯浠� -->
+ <el-card class="filter-card" shadow="never">
+ <el-form :model="filterForm" inline>
+ <el-form-item label="鏃堕棿鑼冨洿">
+ <el-date-picker
+ style="width: 300px"
+ v-model="filterForm.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ @change="handleFilterChange"
+ />
+ </el-form-item>
+ <el-form-item label="鎶ヨ〃绫诲瀷">
+ <el-select v-model="filterForm.reportType" placeholder="璇烽�夋嫨鎶ヨ〃绫诲瀷" @change="handleFilterChange" style="width: 300px">
+ <el-option label="鏍峰搧杩涘害鎶ヨ〃" value="sample" />
+ <el-option label="璁惧浣跨敤鎶ヨ〃" value="equipment" />
+ <el-option label="妫�娴嬮」鐩姤琛�" value="inspection" />
+ <el-option label="棰嗙敤璁板綍鎶ヨ〃" value="usage" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleFilterChange">鏌ヨ</el-button>
+ <el-button @click="resetFilter">閲嶇疆</el-button>
+ <el-button type="success" @click="exportReport">瀵煎嚭鎶ヨ〃</el-button>
+ </el-form-item>
+ </el-form>
+ </el-card>
+
+ <!-- 缁熻鍗$墖 -->
+ <div class="statistics-cards">
+ <el-row :gutter="20">
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><Box /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.totalSamples }}</div>
+ <div class="stat-label">鎬绘牱鍝佹暟</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><Tools /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.activeEquipment }}</div>
+ <div class="stat-label">鍦ㄧ敤璁惧</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><Document /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.completedInspections }}</div>
+ <div class="stat-label">宸插畬鎴愭娴�</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="stat-card" shadow="hover">
+ <div class="stat-content">
+ <div class="stat-icon">
+ <el-icon><ShoppingCart /></el-icon>
+ </div>
+ <div class="stat-info">
+ <div class="stat-number">{{ statistics.totalUsage }}</div>
+ <div class="stat-label">鎬婚鐢ㄦ鏁�</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 鍥捐〃鍖哄煙 -->
+ <div class="charts-container">
+ <el-row :gutter="20">
+ <!-- 鏍峰搧杩涘害鍥捐〃 -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>鏍峰搧杩涘害缁熻</span>
+ <el-button link @click="refreshSampleChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="sampleChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+
+ <!-- 璁惧浣跨敤鍥捐〃 -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>璁惧浣跨敤鐜囩粺璁�</span>
+ <el-button link @click="refreshEquipmentChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="equipmentChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20" style="margin-top: 20px;">
+ <!-- 妫�娴嬮」鐩粺璁� -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>妫�娴嬮」鐩垎甯�</span>
+ <el-button link @click="refreshInspectionChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="inspectionChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+
+ <!-- 棰嗙敤璁板綍瓒嬪娍 -->
+ <el-col :span="12">
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>棰嗙敤璁板綍瓒嬪娍</span>
+ <el-button link @click="refreshUsageChart">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div ref="usageChartRef" class="chart-container"></div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 璇︾粏鏁版嵁琛ㄦ牸 -->
+ <el-card class="table-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span>璇︾粏鏁版嵁</span>
+ <div>
+ <el-button type="primary" size="small" @click="refreshTable">鍒锋柊</el-button>
+ <el-button type="success" size="small" @click="exportTable">瀵煎嚭</el-button>
+ </div>
+ </div>
+ </template>
+
+ <el-table
+ :data="tableData"
+ style="width: 100%"
+ v-loading="tableLoading"
+ stripe
+ border
+ >
+ <el-table-column prop="id" label="缂栧彿" width="80" />
+ <el-table-column prop="name" label="鍚嶇О" />
+ <el-table-column prop="type" label="绫诲瀷" width="120" />
+ <el-table-column prop="status" label="鐘舵��" width="100">
+ <template #default="scope">
+ <el-tag :type="getStatusType(scope.row.status)">
+ {{ scope.row.status }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="progress" label="杩涘害" width="120">
+ <template #default="scope">
+ <el-progress :percentage="scope.row.progress" :status="getProgressStatus(scope.row.progress)" />
+ </template>
+ </el-table-column>
+ <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" width="180" />
+ <el-table-column prop="updateTime" label="鏇存柊鏃堕棿" width="180" />
+ <el-table-column label="鎿嶄綔" width="150" fixed="right">
+ <template #default="scope">
+ <el-button link size="small" @click="viewDetail(scope.row)">鏌ョ湅</el-button>
+ <el-button link size="small" @click="editItem(scope.row)">缂栬緫</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <div class="pagination-container">
+ <el-pagination
+ v-model:current-page="pagination.currentPage"
+ v-model:page-size="pagination.pageSize"
+ :page-sizes="[10, 20, 50, 100]"
+ :total="pagination.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+ </el-card>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, nextTick } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import * as echarts from 'echarts'
+import { Box, Tools, Document, ShoppingCart } from '@element-plus/icons-vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const filterForm = reactive({
+ dateRange: [],
+ reportType: 'sample'
+})
+
+const statistics = reactive({
+ totalSamples: 1250,
+ activeEquipment: 45,
+ completedInspections: 890,
+ totalUsage: 2340
+})
+
+const tableData = ref([])
+const tableLoading = ref(false)
+const pagination = reactive({
+ currentPage: 1,
+ pageSize: 20,
+ total: 0
+})
+
+// 鍥捐〃寮曠敤
+const sampleChartRef = ref(null)
+const equipmentChartRef = ref(null)
+const inspectionChartRef = ref(null)
+const usageChartRef = ref(null)
+
+// 鍥捐〃瀹炰緥
+let sampleChart = null
+let equipmentChart = null
+let inspectionChart = null
+let usageChart = null
+
+// 鍒濆鍖栨暟鎹�
+const initData = () => {
+ // 妯℃嫙琛ㄦ牸鏁版嵁
+ tableData.value = [
+ {
+ id: 'SP001',
+ name: '鏍峰搧A-001',
+ type: '閲戝睘鏉愭枡',
+ status: '妫�娴嬩腑',
+ progress: 75,
+ createTime: '2024-01-15 09:30:00',
+ updateTime: '2024-01-20 14:20:00'
+ },
+ {
+ id: 'SP002',
+ name: '鏍峰搧B-002',
+ type: '濉戞枡鍒跺搧',
+ status: '宸插畬鎴�',
+ progress: 100,
+ createTime: '2024-01-10 10:15:00',
+ updateTime: '2024-01-18 16:45:00'
+ },
+ {
+ id: 'SP003',
+ name: '鏍峰搧C-003',
+ type: '鐢靛瓙鍏冧欢',
+ status: '寰呮娴�',
+ progress: 0,
+ createTime: '2024-01-22 08:45:00',
+ updateTime: '2024-01-22 08:45:00'
+ },
+ {
+ id: 'EQ001',
+ name: '妫�娴嬭澶嘇',
+ type: '鍏夎氨浠�',
+ status: '浣跨敤涓�',
+ progress: 60,
+ createTime: '2024-01-05 14:20:00',
+ updateTime: '2024-01-20 11:30:00'
+ },
+ {
+ id: 'EQ002',
+ name: '妫�娴嬭澶嘊',
+ type: '鏄惧井闀�',
+ status: '绌洪棽',
+ progress: 0,
+ createTime: '2024-01-08 16:10:00',
+ updateTime: '2024-01-19 09:15:00'
+ }
+ ]
+
+ pagination.total = tableData.value.length
+}
+
+// 鍒濆鍖栨牱鍝佽繘搴﹀浘琛�
+const initSampleChart = () => {
+ if (sampleChartRef.value) {
+ sampleChart = echarts.init(sampleChartRef.value)
+ const option = {
+ title: {
+ show: false
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left'
+ },
+ series: [
+ {
+ name: '鏍峰搧鐘舵��',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ avoidLabelOverlap: false,
+ label: {
+ show: false,
+ position: 'center'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '18',
+ fontWeight: 'bold'
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: [
+ { value: 450, name: '宸插畬鎴�' },
+ { value: 320, name: '妫�娴嬩腑' },
+ { value: 280, name: '寰呮娴�' },
+ { value: 200, name: '宸叉殏鍋�' }
+ ]
+ }
+ ]
+ }
+ sampleChart.setOption(option)
+ }
+}
+
+// 鍒濆鍖栬澶囦娇鐢ㄥ浘琛�
+const initEquipmentChart = () => {
+ if (equipmentChartRef.value) {
+ equipmentChart = echarts.init(equipmentChartRef.value)
+ const option = {
+ title: {
+ show: false
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow'
+ }
+ },
+ xAxis: {
+ type: 'category',
+ data: ['鍏夎氨浠�', '鏄惧井闀�', '纭害璁�', '鎷夊姏鏈�', '鍐插嚮鏈�', '閲戠浉浠�']
+ },
+ yAxis: {
+ type: 'value',
+ name: '浣跨敤鐜�(%)'
+ },
+ series: [
+ {
+ name: '浣跨敤鐜�',
+ type: 'bar',
+ data: [85, 60, 75, 90, 45, 70],
+ itemStyle: {
+ color: function(params) {
+ const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#9C27B0']
+ return colors[params.dataIndex]
+ }
+ }
+ }
+ ]
+ }
+ equipmentChart.setOption(option)
+ }
+}
+
+// 鍒濆鍖栨娴嬮」鐩浘琛�
+const initInspectionChart = () => {
+ if (inspectionChartRef.value) {
+ inspectionChart = echarts.init(inspectionChartRef.value)
+ const option = {
+ title: {
+ show: false
+ },
+ tooltip: {
+ trigger: 'item'
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left'
+ },
+ series: [
+ {
+ name: '妫�娴嬮」鐩�',
+ type: 'pie',
+ radius: '50%',
+ data: [
+ { value: 335, name: '鐗╃悊鎬ц兘' },
+ { value: 310, name: '鍖栧鍒嗘瀽' },
+ { value: 234, name: '灏哄娴嬮噺' },
+ { value: 135, name: '澶栬妫�鏌�' },
+ { value: 148, name: '鍏朵粬妫�娴�' }
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ }
+ }
+ ]
+ }
+ inspectionChart.setOption(option)
+ }
+}
+
+// 鍒濆鍖栭鐢ㄨ褰曞浘琛�
+const initUsageChart = () => {
+ if (usageChartRef.value) {
+ usageChart = echarts.init(usageChartRef.value)
+ const option = {
+ title: {
+ show: false
+ },
+ tooltip: {
+ trigger: 'axis'
+ },
+ legend: {
+ data: ['棰嗙敤娆℃暟', '褰掕繕娆℃暟']
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ data: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�', '8鏈�', '9鏈�', '10鏈�', '11鏈�', '12鏈�']
+ },
+ yAxis: {
+ type: 'value'
+ },
+ series: [
+ {
+ name: '棰嗙敤娆℃暟',
+ type: 'line',
+ stack: 'Total',
+ data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330]
+ },
+ {
+ name: '褰掕繕娆℃暟',
+ type: 'line',
+ stack: 'Total',
+ data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320]
+ }
+ ]
+ }
+ usageChart.setOption(option)
+ }
+}
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleFilterChange = () => {
+ ElMessage.success('绛涢�夋潯浠跺凡鏇存柊')
+ // 杩欓噷鍙互鏍规嵁绛涢�夋潯浠堕噸鏂板姞杞芥暟鎹�
+}
+
+const resetFilter = () => {
+ filterForm.dateRange = []
+ filterForm.reportType = 'sample'
+ ElMessage.info('绛涢�夋潯浠跺凡閲嶇疆')
+}
+
+const exportReport = () => {
+ ElMessage.success('鎶ヨ〃瀵煎嚭鍔熻兘寮�鍙戜腑...')
+}
+
+const refreshSampleChart = () => {
+ initSampleChart()
+ ElMessage.success('鏍峰搧杩涘害鍥捐〃宸插埛鏂�')
+}
+
+const refreshEquipmentChart = () => {
+ initEquipmentChart()
+ ElMessage.success('璁惧浣跨敤鍥捐〃宸插埛鏂�')
+}
+
+const refreshInspectionChart = () => {
+ initInspectionChart()
+ ElMessage.success('妫�娴嬮」鐩浘琛ㄥ凡鍒锋柊')
+}
+
+const refreshUsageChart = () => {
+ initUsageChart()
+ ElMessage.success('棰嗙敤璁板綍鍥捐〃宸插埛鏂�')
+}
+
+const refreshTable = () => {
+ tableLoading.value = true
+ setTimeout(() => {
+ tableLoading.value = false
+ ElMessage.success('琛ㄦ牸鏁版嵁宸插埛鏂�')
+ }, 1000)
+}
+
+const exportTable = () => {
+ ElMessage.success('琛ㄦ牸瀵煎嚭鍔熻兘寮�鍙戜腑...')
+}
+
+const handleSizeChange = (val) => {
+ pagination.pageSize = val
+ // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const handleCurrentChange = (val) => {
+ pagination.currentPage = val
+ // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const getStatusType = (status) => {
+ const statusMap = {
+ '宸插畬鎴�': 'success',
+ '妫�娴嬩腑': 'warning',
+ '寰呮娴�': 'info',
+ '宸叉殏鍋�': 'danger',
+ '浣跨敤涓�': 'primary',
+ '绌洪棽': 'info'
+ }
+ return statusMap[status] || 'info'
+}
+
+const getProgressStatus = (progress) => {
+ if (progress === 100) return 'success'
+ if (progress >= 80) return 'warning'
+ if (progress >= 50) return ''
+ return 'exception'
+}
+
+const viewDetail = (row) => {
+ ElMessage.info(`鏌ョ湅璇︽儏: ${row.name}`)
+}
+
+const editItem = (row) => {
+ ElMessage.info(`缂栬緫椤圭洰: ${row.name}`)
+}
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+ initData()
+ nextTick(() => {
+ initSampleChart()
+ initEquipmentChart()
+ initInspectionChart()
+ initUsageChart()
+ })
+
+ // 鐩戝惉绐楀彛澶у皬鍙樺寲锛岄噸鏂拌皟鏁村浘琛ㄥぇ灏�
+ window.addEventListener('resize', () => {
+ sampleChart?.resize()
+ equipmentChart?.resize()
+ inspectionChart?.resize()
+ usageChart?.resize()
+ })
+})
+</script>
+
+<style scoped>
+.report-management {
+ padding: 20px;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+}
+
+.page-header {
+ margin-bottom: 20px;
+ text-align: center;
+}
+
+.page-header h2 {
+ color: #303133;
+ margin-bottom: 8px;
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.page-header p {
+ color: #909399;
+ font-size: 14px;
+ margin: 0;
+}
+
+.filter-card {
+ margin-bottom: 20px;
+}
+
+.statistics-cards {
+ margin-bottom: 20px;
+}
+
+.stat-card {
+ height: 120px;
+}
+
+.stat-content {
+ display: flex;
+ align-items: center;
+ height: 100%;
+}
+
+.stat-icon {
+ width: 60px;
+ height: 60px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 20px;
+ font-size: 24px;
+ color: white;
+}
+
+.stat-card:nth-child(1) .stat-icon {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+}
+
+.stat-card:nth-child(2) .stat-icon {
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+}
+
+.stat-card:nth-child(3) .stat-icon {
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+}
+
+.stat-card:nth-child(4) .stat-icon {
+ background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
+}
+
+.stat-info {
+ flex: 1;
+}
+
+.stat-number {
+ font-size: 28px;
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 8px;
+}
+
+.stat-label {
+ font-size: 14px;
+ color: #909399;
+}
+
+.charts-container {
+ margin-bottom: 20px;
+}
+
+.chart-card {
+ margin-bottom: 20px;
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.chart-container {
+ height: 300px;
+ width: 100%;
+}
+
+.table-card {
+ margin-bottom: 20px;
+}
+
+.pagination-container {
+ margin-top: 20px;
+ text-align: right;
+}
+
+:deep(.el-card__header) {
+ padding: 15px 20px;
+ border-bottom: 1px solid #ebeef5;
+ background-color: #fafafa;
+}
+
+:deep(.el-card__body) {
+ padding: 20px;
+}
+
+:deep(.el-table) {
+ margin-bottom: 20px;
+}
+
+:deep(.el-progress) {
+ margin: 0;
+}
+
+:deep(.el-tag) {
+ margin: 0;
+}
+</style>
--
Gitblit v1.9.3