From d3d2f9861c3d4bccfb9594b7efd76e62d3b44b65 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期三, 03 六月 2026 16:41:31 +0800
Subject: [PATCH] feat: 添加合格率计算及显示功能
---
src/views/reportAnalysis/reportManagement/index.vue | 1077 +++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 647 insertions(+), 430 deletions(-)
diff --git a/src/views/reportAnalysis/reportManagement/index.vue b/src/views/reportAnalysis/reportManagement/index.vue
index 4c73f7f..221ef86 100644
--- a/src/views/reportAnalysis/reportManagement/index.vue
+++ b/src/views/reportAnalysis/reportManagement/index.vue
@@ -1,341 +1,379 @@
<template>
- <div class="report-management">
- <!-- 鍥捐〃鍖哄煙 -->
- <div class="charts-container">
- <el-row :gutter="20">
- <!-- 鍚勭被鍨嬪畬鎴愭暟閲� -->
- <el-col :span="9">
- <el-card class="chart-card"
- shadow="hover">
- <template #header>
- <div class="card-header">
- <div class="chart-title-line"></div>
- <span>鍚勭被鍨嬪畬鎴愭暟閲�</span>
- </div>
- </template>
- <div class="top-container">
- <div class="typeNum">
- <div class="typeNum-left">
- <img src="~@/assets/images/chartCard.svg"
- alt="鍥捐〃"
- style="width: 40px; height: 40px; object-fit: contain;">
- <div class="typeNum-left-text">鍘熸潗鏂�</div>
- </div>
- <div class="typeNum-center">
- <div class="typeNum-leftLine">-</div>
- <div class="typeNum-rightLine"></div>
- </div>
- <div class="typeNum-right">
- <div class="typeNum-right-top">
- <div class="typeNum-right-top-name">鎬绘暟閲�</div>
- <div class="typeNum-right-top-text">2099 <span class="unit">涓�</span></div>
+ <div class="scale-container">
+ <div class="report-management-container"
+ :style="{ transform: `scale(${scaleRatio})` }">
+ <div class="report-management">
+ <!-- 鍥捐〃鍖哄煙 -->
+ <div class="charts-container">
+ <el-row :gutter="20">
+ <!-- 鍚勭被鍨嬪畬鎴愭暟閲� -->
+ <el-col :span="9">
+ <el-card class="chart-card"
+ shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <div class="chart-title-line"></div>
+ <span>鍚勭被鍨嬪畬鎴愭暟閲�</span>
</div>
- <div class="typeNum-right-bottom">
- <div class="typeNum-right-top-name">宸插畬鎴愭暟</div>
- <div class="typeNum-right-top-text">2099 <span class="unit">涓�</span></div>
- </div>
- </div>
- </div>
- <div class="typeNum">
- <div class="typeNum-left">
- <img src="~@/assets/images/chartCard2.svg"
- alt="鍥捐〃"
- style="width: 40px; height: 40px; object-fit: contain;">
- <div class="typeNum-left-text"
- style="color: #5EB334;">鍗婃垚鍝�</div>
- </div>
- <div class="typeNum-center">
- <div class="typeNum-leftLine2">-</div>
- <div class="typeNum-rightLine2"></div>
- </div>
- <div class="typeNum-right">
- <div class="typeNum-right-top">
- <div class="typeNum-right-top-name">鎬绘暟閲�</div>
- <div class="typeNum-right-top-text">2099 <span class="unit">涓�</span></div>
- </div>
- <div class="typeNum-right-bottom">
- <div class="typeNum-right-top-name">宸插畬鎴愭暟</div>
- <div class="typeNum-right-top-text">2099 <span class="unit">涓�</span></div>
- </div>
- </div>
- </div>
- <div class="typeNum">
- <div class="typeNum-left">
- <img src="~@/assets/images/chartCard3.svg"
- alt="鍥捐〃"
- style="width: 40px; height: 40px; object-fit: contain;">
- <div class="typeNum-left-text"
- style="color: #8000FF;">鎴愬搧</div>
- </div>
- <div class="typeNum-center">
- <div class="typeNum-leftLine3">-</div>
- <div class="typeNum-rightLine3"></div>
- </div>
- <div class="typeNum-right">
- <div class="typeNum-right-top">
- <div class="typeNum-right-top-name">鎬绘暟閲�</div>
- <div class="typeNum-right-top-text">2099 <span class="unit">涓�</span></div>
- </div>
- <div class="typeNum-right-bottom">
- <div class="typeNum-right-top-name">宸插畬鎴愭暟</div>
- <div class="typeNum-right-top-text">2099 <span class="unit">涓�</span></div>
- </div>
- </div>
- </div>
- </div>
- </el-card>
- </el-col>
- <!-- 璐ㄦ鍚堟牸鐜� -->
- <el-col :span="15">
- <el-card class="chart-card"
- shadow="hover">
- <template #header>
- <div class="card-header">
- <div class="chart-title-line"></div>
- <span>璐ㄦ鍚堟牸鐜�</span>
- </div>
- </template>
- <div class="top-container flex-center">
- <div class="quality-card blue-card">
- <div class="quality-card-title">
- <img src="~@/assets/images/chartCard.svg"
- alt="鍘熸潗鏂�"
- style="width: 24px; height: 24px; margin-right: 8px;">
- 鍘熸潗鏂欏悎鏍肩巼
- </div>
- <div class="quality-card-content">
- <div class="quality-item">
- <div>
- <div class="quality-item-label blue-label">瀹屾垚鐜�</div>
- <div class="quality-item-tip">鍗犳瘮</div>
- <div class="quality-item-value">80%</div>
+ </template>
+ <div class="top-container">
+ <div class="typeNum">
+ <div class="typeNum-left">
+ <img src="~@/assets/images/chartCard.svg"
+ alt="鍥捐〃"
+ style="width: 40px; height: 40px; object-fit: contain;">
+ <div class="typeNum-left-text">鍘熸潗鏂�</div>
</div>
- <div class="quality-item-chart"
- ref="materialCompletionChart"></div>
- </div>
- <div class="quality-item">
- <div>
- <div class="quality-item-label green-label">鍚堟牸鐜�</div>
- <div class="quality-item-tip">鍗犳瘮</div>
- <div class="quality-item-value">80%</div>
+ <div class="typeNum-center">
+ <div class="typeNum-leftLine">-</div>
+ <div class="typeNum-rightLine"></div>
</div>
- <div class="quality-item-chart"
- ref="materialQualityChart"></div>
- </div>
- </div>
- </div>
- <div class="quality-card green-card">
- <div class="quality-card-title">
- <img src="~@/assets/images/chartCard2.svg"
- alt="鍗婃垚鍝�"
- style="width: 24px; height: 24px; margin-right: 8px;">
- 鍗婃垚鍝佸悎鏍肩巼
- </div>
- <div class="quality-card-content">
- <div class="quality-item">
- <div>
- <div class="quality-item-label blue-label">瀹屾垚鐜�</div>
- <div class="quality-item-tip">鍗犳瘮</div>
- <div class="quality-item-value">80%</div>
+ <div class="typeNum-right">
+ <div class="typeNum-right-top">
+ <div class="typeNum-right-top-name">鎬绘暟閲�</div>
+ <div class="typeNum-right-top-text">{{ getInspectStatValue(0, 'totalCount') }} <span class="unit">涓�</span></div>
+ </div>
+ <div class="typeNum-right-bottom">
+ <div class="typeNum-right-top-name">宸插畬鎴愭暟</div>
+ <div class="typeNum-right-top-text">{{ getInspectStatValue(0, 'completedCount') }} <span class="unit">涓�</span>
+ </div>
+ </div>
</div>
- <div class="quality-item-chart"
- ref="semiCompletionChart"></div>
</div>
- <div class="quality-item">
- <div>
- <div class="quality-item-label green-label">鍚堟牸鐜�</div>
- <div class="quality-item-tip">鍗犳瘮</div>
- <div class="quality-item-value">80%</div>
+ <div class="typeNum">
+ <div class="typeNum-left">
+ <img src="~@/assets/images/chartCard2.svg"
+ alt="鍥捐〃"
+ style="width: 40px; height: 40px; object-fit: contain;">
+ <div class="typeNum-left-text"
+ style="color: #5EB334;">鍗婃垚鍝�</div>
</div>
- <div class="quality-item-chart"
- ref="semiQualityChart"></div>
- </div>
- </div>
- </div>
- <div class="quality-card purple-card">
- <div class="quality-card-title">
- <img src="~@/assets/images/chartCard3.svg"
- alt="鎴愬搧"
- style="width: 24px; height: 24px; margin-right: 8px;">
- 鎴愬搧鍚堟牸鐜�
- </div>
- <div class="quality-card-content">
- <div class="quality-item">
- <div>
- <div class="quality-item-label blue-label">瀹屾垚鐜�</div>
- <div class="quality-item-tip">鍗犳瘮</div>
- <div class="quality-item-value">80%</div>
+ <div class="typeNum-center">
+ <div class="typeNum-leftLine2">-</div>
+ <div class="typeNum-rightLine2"></div>
</div>
- <div class="quality-item-chart"
- ref="finalCompletionChart"></div>
- </div>
- <div class="quality-item">
- <div>
- <div class="quality-item-label green-label">鍚堟牸鐜�</div>
- <div class="quality-item-tip">鍗犳瘮</div>
- <div class="quality-item-value">80%</div>
+ <div class="typeNum-right">
+ <div class="typeNum-right-top">
+ <div class="typeNum-right-top-name">鎬绘暟閲�</div>
+ <div class="typeNum-right-top-text">{{ getInspectStatValue(1, 'totalCount') }} <span class="unit">涓�</span></div>
+ </div>
+ <div class="typeNum-right-bottom">
+ <div class="typeNum-right-top-name">宸插畬鎴愭暟</div>
+ <div class="typeNum-right-top-text">{{ getInspectStatValue(1, 'completedCount') }} <span class="unit">涓�</span>
+ </div>
+ </div>
</div>
- <div class="quality-item-chart"
- ref="finalQualityChart"></div>
+ </div>
+ <div class="typeNum">
+ <div class="typeNum-left">
+ <img src="~@/assets/images/chartCard3.svg"
+ alt="鍥捐〃"
+ style="width: 40px; height: 40px; object-fit: contain;">
+ <div class="typeNum-left-text"
+ style="color: #8000FF;">鎴愬搧</div>
+ </div>
+ <div class="typeNum-center">
+ <div class="typeNum-leftLine3">-</div>
+ <div class="typeNum-rightLine3"></div>
+ </div>
+ <div class="typeNum-right">
+ <div class="typeNum-right-top">
+ <div class="typeNum-right-top-name">鎬绘暟閲�</div>
+ <div class="typeNum-right-top-text">{{ getInspectStatValue(2, 'totalCount') }} <span class="unit">涓�</span></div>
+ </div>
+ <div class="typeNum-right-bottom">
+ <div class="typeNum-right-top-name">宸插畬鎴愭暟</div>
+ <div class="typeNum-right-top-text">{{ getInspectStatValue(2, 'completedCount') }} <span class="unit">涓�</span>
+ </div>
+ </div>
+ </div>
</div>
</div>
- </div>
- </div>
- </el-card>
- </el-col>
- </el-row>
- </div>
- <div class="charts-container">
- <el-row :gutter="20">
- <!-- 璐ㄦ鍚堟牸鐜� -->
- <el-col :span="24">
- <el-card class="chart-card"
- shadow="hover">
- <template #header>
- <div class="card-header">
- <div class="chart-title-line"></div>
- <span>璐ㄦ鍚堟牸鐜�</span>
- </div>
- </template>
- <div class="chart-container-line">
- <div class="container-line-left">
- <div style="height: 100%; width: 100%;"
- ref="usageChartRef">
- </div>
- </div>
- <div class="container-line-right">
- <div style="height: 80%; width: 100%;"
- ref="inspectionChartRef">
- </div>
- <div class="container-line-right-bottom">
- <div class="inspection-chart-box">
- <div class="chart-box-title">鍘熸潗鏂欐娊妫�鏁�</div>
- <div class="chart-box-num">600</div>
+ </el-card>
+ </el-col>
+ <!-- 璐ㄦ鍚堟牸鐜� -->
+ <el-col :span="15">
+ <el-card class="chart-card"
+ shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <div class="chart-title-line"></div>
+ <span>璐ㄦ鍚堟牸鐜�</span>
</div>
- <div class="inspection-chart-box">
- <div class="chart-box-title">鍗婃垚鍝佹娊妫�鏁�</div>
- <div class="chart-box-num">200</div>
+ </template>
+ <div class="top-container flex-center">
+ <div class="quality-card blue-card">
+ <div class="quality-card-title">
+ <img src="~@/assets/images/chartCard.svg"
+ alt="鍘熸潗鏂�"
+ style="width: 24px; height: 24px; margin-right: 8px;">
+ 鍘熸潗鏂欏悎鏍肩巼
+ </div>
+ <div class="quality-card-content">
+ <div class="quality-item">
+ <div>
+ <div class="quality-item-label blue-label">瀹屾垚鐜�</div>
+ <div class="quality-item-tip">鍗犳瘮</div>
+ <div class="quality-item-value">{{ getPassRateStatValue(0, 'completionRate') }}</div>
+ </div>
+ <div class="quality-item-chart"
+ ref="materialCompletionChart"></div>
+ </div>
+ <div class="quality-item">
+ <div>
+ <div class="quality-item-label green-label">鍚堟牸鐜�</div>
+ <div class="quality-item-tip">鍗犳瘮</div>
+ <div class="quality-item-value">{{ getPassRateStatValue(0, 'passRate') }}</div>
+ </div>
+ <div class="quality-item-chart"
+ ref="materialQualityChart"></div>
+ </div>
+ </div>
</div>
- <div class="inspection-chart-box">
- <div class="chart-box-title">鎴愬搧鎶芥鏁�</div>
- <div class="chart-box-num">200</div>
+ <div class="quality-card green-card">
+ <div class="quality-card-title">
+ <img src="~@/assets/images/chartCard2.svg"
+ alt="鍗婃垚鍝�"
+ style="width: 24px; height: 24px; margin-right: 8px;">
+ 鍗婃垚鍝佸悎鏍肩巼
+ </div>
+ <div class="quality-card-content">
+ <div class="quality-item">
+ <div>
+ <div class="quality-item-label blue-label">瀹屾垚鐜�</div>
+ <div class="quality-item-tip">鍗犳瘮</div>
+ <div class="quality-item-value">{{ getPassRateStatValue(1, 'completionRate') }}</div>
+ </div>
+ <div class="quality-item-chart"
+ ref="semiCompletionChart"></div>
+ </div>
+ <div class="quality-item">
+ <div>
+ <div class="quality-item-label green-label">鍚堟牸鐜�</div>
+ <div class="quality-item-tip">鍗犳瘮</div>
+ <div class="quality-item-value">{{ getPassRateStatValue(1, 'passRate') }}</div>
+ </div>
+ <div class="quality-item-chart"
+ ref="semiQualityChart"></div>
+ </div>
+ </div>
+ </div>
+ <div class="quality-card purple-card">
+ <div class="quality-card-title">
+ <img src="~@/assets/images/chartCard3.svg"
+ alt="鎴愬搧"
+ style="width: 24px; height: 24px; margin-right: 8px;">
+ 鎴愬搧鍚堟牸鐜�
+ </div>
+ <div class="quality-card-content">
+ <div class="quality-item">
+ <div>
+ <div class="quality-item-label blue-label">瀹屾垚鐜�</div>
+ <div class="quality-item-tip">鍗犳瘮</div>
+ <div class="quality-item-value">{{ getPassRateStatValue(2, 'completionRate') }}</div>
+ </div>
+ <div class="quality-item-chart"
+ ref="finalCompletionChart"></div>
+ </div>
+ <div class="quality-item">
+ <div>
+ <div class="quality-item-label green-label">鍚堟牸鐜�</div>
+ <div class="quality-item-tip">鍗犳瘮</div>
+ <div class="quality-item-value">{{ getPassRateStatValue(2, 'passRate') }}</div>
+ </div>
+ <div class="quality-item-chart"
+ ref="finalQualityChart"></div>
+ </div>
+ </div>
</div>
</div>
- </div>
- </div>
- <!-- </div> -->
- <!-- <div ref="sampleChartRef"
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+ <div class="charts-container">
+ <el-row :gutter="20">
+ <!-- 璐ㄦ鍚堟牸鐜� -->
+ <el-col :span="24">
+ <el-card class="chart-card"
+ shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <div class="chart-title-line"></div>
+ <span>璐ㄦ鍚堟牸鐜�</span>
+ </div>
+ </template>
+ <div class="chart-container-line">
+ <div class="container-line-left">
+ <div style="height: 100%; width: 100%;"
+ ref="usageChartRef">
+ </div>
+ </div>
+ <div class="container-line-right">
+ <div style="height: 80%; width: 100%;"
+ ref="inspectionChartRef">
+ </div>
+ <div class="container-line-right-bottom">
+ <div class="inspection-chart-box">
+ <div class="chart-box-title">鍘熸潗鏂欐�绘暟</div>
+ <div class="chart-box-num">{{ getYearlyStatValue(0, 'totalCount') }}</div>
+ </div>
+ <div class="inspection-chart-box">
+ <div class="chart-box-title">鍗婃垚鍝佹�绘暟</div>
+ <div class="chart-box-num">{{ getYearlyStatValue(1, 'totalCount') }}</div>
+ </div>
+ <div class="inspection-chart-box">
+ <div class="chart-box-title">鎴愬搧鎬绘暟</div>
+ <div class="chart-box-num">{{ getYearlyStatValue(2, 'totalCount') }}</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- </div> -->
+ <!-- <div ref="sampleChartRef"
class="chart-container"></div> -->
- <div class="yearchange">
- <div style="margin-right: 8px;font-size: 14px;">骞翠唤:</div>
- <el-date-picker v-model="value3"
- size="mini"
- :clearable="false"
- style="width: 60px;"
- type="year"
- :disabled-date="disabledDate"
- placeholder="">
- </el-date-picker>
- </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">
- <div class="chart-title-line"></div>
- <span>璐ㄩ噺瀹屾垚鏄庣粏</span>
- </div>
- </template>
- <div ref="equipmentChartRef"
- 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">
- <div class="chart-title-line"></div>
- <span>妫�娴嬮」鐩垎绫�</span>
- </div>
- </template>
- <div class="chart-container-line">
- <div class="container-line2-left">
- <div class="info-box">
- <div class="info-box-header">椤圭洰鍒嗗竷</div>
- <div class="info-line">
- <div class="info-icon"
- style="background-color: #165DFF"></div>
- <div class="info-line-title">鐗╃悊鎬ц兘</div>
- <div class="info-line-value1">30%</div>
- <div class="info-line-value2">300</div>
- </div>
- <div class="info-line">
- <div class="info-icon"
- style="background-color: #14C9C9;"></div>
- <div class="info-line-title">鐗╃悊鎬ц兘</div>
- <div class="info-line-value1">30%</div>
- <div class="info-line-value2">300</div>
- </div>
- <div class="info-line">
- <div class="info-icon"
- style="background-color: #F7BA1E;"></div>
- <div class="info-line-title">鐗╃悊鎬ц兘</div>
- <div class="info-line-value1">30%</div>
- <div class="info-line-value2">300</div>
- </div>
- <div class="info-line">
- <div class="info-icon"
- style="background-color: #722ED1;"></div>
- <div class="info-line-title">鐗╃悊鎬ц兘</div>
- <div class="info-line-value1">30%</div>
- <div class="info-line-value2">300</div>
- </div>
- <div class="info-line">
- <div class="info-icon"
- style="background-color: #3491FA;"></div>
- <div class="info-line-title">鐗╃悊鎬ц兘</div>
- <div class="info-line-value1">30%</div>
- <div class="info-line-value2">300</div>
- </div>
+ <div class="yearchange">
+ <div style="margin-right: 8px;font-size: 14px;">骞翠唤:</div>
+ <el-date-picker v-model="value3"
+ size="mini"
+ :clearable="false"
+ style="width: 60px;"
+ type="year"
+ :disabled-date="disabledDate"
+ placeholder="">
+ </el-date-picker>
</div>
- </div>
- <div ref="sampleChartRef"
- style="height: 100%; width: 50%;"
- class="chart-container"></div>
- </div>
- <!-- Tab 閫夋嫨鍣� -->
- <div class="tab-selector">
- <div class="tab-item"
- :class="{ active: activeTab === 'raw' }"
- @click="activeTab = 'raw'">鍘熸潗鏂�</div>
- <div class="tab-item"
- :class="{ active: activeTab === 'semi' }"
- @click="activeTab = 'semi'">鍗婃垚鍝�</div>
- <div class="tab-item"
- :class="{ active: activeTab === 'final' }"
- @click="activeTab = 'final'">鎴愬搧</div>
- </div>
- </el-card>
- </el-col>
- </el-row>
+ </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">
+ <div class="chart-title-line"></div>
+ <span>璐ㄩ噺瀹屾垚鏄庣粏</span>
+ </div>
+ </template>
+ <div ref="equipmentChartRef"
+ 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">
+ <div class="chart-title-line"></div>
+ <span>妫�娴嬮」鐩垎绫�</span>
+ </div>
+ </template>
+ <div class="chart-container-line">
+ <div class="container-line2-left">
+ <div class="info-box">
+ <div class="info-box-header">椤圭洰鍒嗗竷</div>
+ <div class="info-line"
+ v-for="(item, index) in topParametersData.list"
+ :key="index">
+ <div class="info-icon"
+ :style="{ backgroundColor: getParameterColor(index) }"></div>
+ <div class="info-line-title">{{ item.name }}</div>
+ <div class="info-line-value1">{{ item.percentage }}%</div>
+ <div class="info-line-value2">{{ item.count }}</div>
+ </div>
+ </div>
+ </div>
+ <div ref="sampleChartRef"
+ style="height: 100%; width: 50%;"
+ class="chart-container"></div>
+ </div>
+ <!-- Tab 閫夋嫨鍣� -->
+ <div class="tab-selector">
+ <div class="tab-item"
+ :class="{ active: activeTab === 'raw' }"
+ @click="activeTab = 'raw'">鍘熸潗鏂�</div>
+ <div class="tab-item"
+ :class="{ active: activeTab === 'semi' }"
+ @click="activeTab = 'semi'">鍗婃垚鍝�</div>
+ <div class="tab-item"
+ :class="{ active: activeTab === 'final' }"
+ @click="activeTab = 'final'">鎴愬搧</div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+ </div>
</div>
</div>
</template>
<script setup>
- import { ref, reactive, onMounted, nextTick } from "vue";
- import { ElMessage, ElMessageBox } from "element-plus";
+ import {
+ ref,
+ reactive,
+ onMounted,
+ nextTick,
+ onBeforeUnmount,
+ watch,
+ } from "vue";
+ import { ElMessage } from "element-plus";
import * as echarts from "echarts";
- import { Box, Tools, Document, ShoppingCart } from "@element-plus/icons-vue";
+ import {
+ getInspectStatistics,
+ getPassRateStatistics,
+ getMonthlyPassRateStatistics,
+ getYearlyPassRateStatistics,
+ getMonthlyCompletionDetails,
+ getTopParameters,
+ } from "@/api/reportAnalysis/qualityReport";
+
+ // 缂╂斁姣斾緥
+ const scaleRatio = ref(1);
+ // 璁捐灏哄锛堝熀鍑嗗昂瀵革級
+ const designWidth = 1920;
+ const designHeight = 1080;
+
+ // 璁$畻缂╂斁姣斾緥
+ const calculateScale = () => {
+ const container = document.querySelector(".scale-container");
+ if (!container) return;
+
+ // 鑾峰彇瀹瑰櫒鐨勫疄闄呭昂瀵�
+ const containerWidth = container.clientWidth;
+ const containerHeight = container.clientHeight;
+
+ if (containerWidth === 0) {
+ // 濡傛灉杩樻病娓叉煋鍑烘潵锛屽欢杩熶竴涓嬪啀璁$畻
+ setTimeout(calculateScale, 100);
+ return;
+ }
+
+ // 璁$畻瀹藉害缂╂斁姣斾緥锛屼娇鍏跺缁堝崰婊″搴�
+ const scaleX = containerWidth / designWidth;
+ scaleRatio.value = scaleX;
+ };
+
+ // 绐楀彛澶у皬鍙樺寲澶勭悊
+ const handleResize = () => {
+ calculateScale();
+ // 鍚屾椂璋冩暣鍥捐〃
+ sampleChart?.resize();
+ equipmentChart?.resize();
+ inspectionChart?.resize();
+ usageChart?.resize();
+ materialCompletionChartInstance?.resize();
+ materialQualityChartInstance?.resize();
+ semiCompletionChartInstance?.resize();
+ semiQualityChartInstance?.resize();
+ finalCompletionChartInstance?.resize();
+ finalQualityChartInstance?.resize();
+ };
// 鍝嶅簲寮忔暟鎹�
const filterForm = reactive({
@@ -343,12 +381,127 @@
reportType: "sample",
});
- const statistics = reactive({
- totalSamples: 1250,
- activeEquipment: 45,
- completedInspections: 890,
- totalUsage: 2340,
- });
+ const inspectStatisticsData = ref([]);
+ const passRateStatisticsData = ref([]);
+ const monthlyPassRateData = ref([]);
+ const yearlyPassRateData = ref([]);
+ const monthlyCompletionDetailsData = ref([]);
+ const topParametersData = ref({ totalCount: 0, list: [] });
+ const activeTab = ref("raw");
+
+ const getParameterColor = index => {
+ const colors = [
+ "#165DFF",
+ "#14C9C9",
+ "#F7BA1E",
+ "#722ED1",
+ "#3491FA",
+ "#FF7D00",
+ "#F53F3F",
+ ];
+ return colors[index % colors.length];
+ };
+
+ const getYearlyStatValue = (type, field) => {
+ const stat = yearlyPassRateData.value.find(item => item.modelType === type);
+ return stat ? stat[field] : 0;
+ };
+
+ const getInspectStatValue = (type, field) => {
+ const stat = inspectStatisticsData.value.find(
+ item => item.modelType === type
+ );
+ return stat ? stat[field] : 0;
+ };
+
+ const getPassRateStatValue = (type, field) => {
+ const stat = passRateStatisticsData.value.find(
+ item => item.modelType === type
+ );
+ if (stat) {
+ if (field === "completionRate" || field === "passRate") {
+ return stat[field] ? parseFloat(stat[field]) + "%" : "0%";
+ }
+ return stat[field];
+ }
+ return field === "completionRate" || field === "passRate" ? "0%" : 0;
+ };
+
+ const fetchInspectStatisticsData = async () => {
+ try {
+ const res = await getInspectStatistics();
+ if (res.code === 200) {
+ inspectStatisticsData.value = res.data;
+ }
+ } catch (error) {
+ console.error("Failed to fetch inspect statistics:", error);
+ }
+ };
+
+ const fetchPassRateStatisticsData = async () => {
+ try {
+ const res = await getPassRateStatistics();
+ if (res.code === 200) {
+ passRateStatisticsData.value = res.data;
+ // 鏁版嵁鑾峰彇鍚庨噸鏂板垵濮嬪寲鍥捐〃
+ initAllQualityCharts();
+ }
+ } catch (error) {
+ console.error("Failed to fetch pass rate statistics:", error);
+ }
+ };
+
+ const fetchMonthlyPassRateData = async () => {
+ try {
+ const year = value3.value.getFullYear().toString();
+ const res = await getMonthlyPassRateStatistics(year);
+ if (res.code === 200) {
+ monthlyPassRateData.value = res.data;
+ initUsageChart();
+ }
+ } catch (error) {
+ console.error("Failed to fetch monthly pass rate statistics:", error);
+ }
+ };
+
+ const fetchYearlyPassRateData = async () => {
+ try {
+ const year = value3.value.getFullYear().toString();
+ const res = await getYearlyPassRateStatistics(year);
+ if (res.code === 200) {
+ yearlyPassRateData.value = res.data;
+ initInspectionChart();
+ }
+ } catch (error) {
+ console.error("Failed to fetch yearly pass rate statistics:", error);
+ }
+ };
+
+ const fetchMonthlyCompletionDetailsData = async () => {
+ try {
+ const year = value3.value.getFullYear().toString();
+ const res = await getMonthlyCompletionDetails(year);
+ if (res.code === 200) {
+ monthlyCompletionDetailsData.value = res.data;
+ initEquipmentChart();
+ }
+ } catch (error) {
+ console.error("Failed to fetch monthly completion details:", error);
+ }
+ };
+
+ const fetchTopParametersData = async () => {
+ try {
+ const typeMap = { raw: 1, semi: 2, final: 3 };
+ const res = await getTopParameters(typeMap[activeTab.value]);
+ if (res.code === 200) {
+ topParametersData.value = res.data;
+ initSampleChart();
+ }
+ } catch (error) {
+ console.error("Failed to fetch top parameters:", error);
+ }
+ };
const tableData = ref([]);
const tableLoading = ref(false);
@@ -368,8 +521,16 @@
return time.getFullYear() > currentYear;
};
- // Tab 閫夋嫨鍣ㄥ綋鍓嶆縺娲婚」
- const activeTab = ref("raw");
+ // 鐩戝惉骞翠唤鍙樺寲
+ watch(value3, () => {
+ fetchMonthlyPassRateData();
+ fetchYearlyPassRateData();
+ fetchMonthlyCompletionDetailsData();
+ });
+
+ watch(activeTab, () => {
+ fetchTopParametersData();
+ });
// 鍥捐〃寮曠敤
const sampleChartRef = ref(null);
@@ -399,60 +560,6 @@
let finalCompletionChartInstance = null;
let finalQualityChartInstance = null;
- // 鍒濆鍖栨暟鎹�
- const initData = () => {
- // 妯℃嫙琛ㄦ牸鏁版嵁
- tableData.value = [
- {
- id: "SP001",
- name: "鏍峰搧A-001",
- type: "閲戝睘鏉愭枡",
- status: "妫�娴嬩腑",
- progress: 75,
- createTime: "2025-01-15 09:30:00",
- updateTime: "2025-01-20 14:20:00",
- },
- {
- id: "SP002",
- name: "鏍峰搧B-002",
- type: "濉戞枡鍒跺搧",
- status: "宸插畬鎴�",
- progress: 100,
- createTime: "2025-01-10 10:15:00",
- updateTime: "2025-01-18 16:45:00",
- },
- {
- id: "SP003",
- name: "鏍峰搧C-003",
- type: "鐢靛瓙鍏冧欢",
- status: "寰呮娴�",
- progress: 0,
- createTime: "2025-01-22 08:45:00",
- updateTime: "2025-01-22 08:45:00",
- },
- {
- id: "EQ001",
- name: "妫�娴嬭澶嘇",
- type: "鍘熸潗鏂�",
- status: "浣跨敤涓�",
- progress: 60,
- createTime: "2025-01-05 14:20:00",
- updateTime: "2025-01-20 11:30:00",
- },
- {
- id: "EQ002",
- name: "妫�娴嬭澶嘊",
- type: "鍗婃垚鍝�",
- status: "绌洪棽",
- progress: 0,
- createTime: "2025-01-08 16:10:00",
- updateTime: "2025-01-19 09:15:00",
- },
- ];
-
- pagination.total = tableData.value.length;
- };
-
// 鍒濆鍖栨牱鍝佽繘搴﹀浘琛�
const initSampleChart = () => {
if (sampleChartRef.value) {
@@ -471,7 +578,7 @@
// },
series: [
{
- name: "鏍峰搧鐘舵��",
+ name: "妫�娴嬮」鐩�",
type: "pie",
radius: ["40%", "80%"],
avoidLabelOverlap: false,
@@ -489,12 +596,11 @@
labelLine: {
show: false,
},
- data: [
- { value: 450, name: "宸插畬鎴�" },
- { value: 320, name: "妫�娴嬩腑" },
- { value: 280, name: "寰呮娴�" },
- { value: 200, name: "宸叉殏鍋�" },
- ],
+ data: topParametersData.value.list.map((item, index) => ({
+ value: item.count,
+ name: item.name,
+ itemStyle: { color: getParameterColor(index) },
+ })),
},
],
};
@@ -556,7 +662,9 @@
name: "鍘熸潗鏂�",
type: "bar",
barWidth: "15%",
- data: [85, 75, 80, 85, 90, 88, 92, 87, 89, 91, 93, 95],
+ data: monthlyCompletionDetailsData.value.map(
+ item => item.rawMaterialCount
+ ),
itemStyle: {
color: "#409EFF",
},
@@ -566,7 +674,9 @@
type: "bar",
barWidth: "15%",
- data: [60, 65, 70, 68, 72, 75, 78, 80, 79, 82, 84, 85],
+ data: monthlyCompletionDetailsData.value.map(
+ item => item.processCount
+ ),
itemStyle: {
color: "#67C23A",
},
@@ -576,7 +686,9 @@
type: "bar",
barWidth: "15%",
- data: [75, 78, 80, 82, 85, 83, 86, 88, 87, 89, 90, 92],
+ data: monthlyCompletionDetailsData.value.map(
+ item => item.outgoingCount
+ ),
itemStyle: {
color: "#E6A23C",
},
@@ -601,12 +713,28 @@
series: [
{
type: "pie",
- radius: "80%",
+ radius: "70%",
data: [
- { value: 335, name: "鍘熸潗鏂�", itemStyle: { color: "#1890FF" } },
- { value: 310, name: "鍗婃垚鍝�", itemStyle: { color: "#F7BA1E" } },
- { value: 234, name: "鎴愬搧", itemStyle: { color: "#14C9C9" } },
+ {
+ value: getYearlyStatValue(0, "totalCount"),
+ name: "鍘熸潗鏂�",
+ itemStyle: { color: "#1890FF" },
+ },
+ {
+ value: getYearlyStatValue(1, "totalCount"),
+ name: "鍗婃垚鍝�",
+ itemStyle: { color: "#F7BA1E" },
+ },
+ {
+ value: getYearlyStatValue(2, "totalCount"),
+ name: "鎴愬搧",
+ itemStyle: { color: "#14C9C9" },
+ },
],
+ label: {
+ show: true,
+ formatter: "{b}: {c}",
+ },
emphasis: {
itemStyle: {
shadowBlur: 10,
@@ -683,32 +811,34 @@
{
name: "鍘熸潗鏂�", // 绯诲垪鍚嶇О
type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
- stack: "Total", // 鍫嗗彔鍚嶇О
- symbol: "none",
+ // stack: "Total", // 鍫嗗彔鍚嶇О
+ symbol: "circle",
itemStyle: {
color: "#1890FF", // 璁剧疆杩欐潯绾跨殑棰滆壊
},
- data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330], // 棰嗙敤娆℃暟鏁版嵁
+ data: monthlyPassRateData.value.map(
+ item => item.rawMaterial.passRate
+ ),
},
{
name: "鍗婃垚鍝�", // 绯诲垪鍚嶇О
type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
- stack: "Total", // 鍫嗗彔鍚嶇О
- symbol: "none",
+ // stack: "Total", // 鍫嗗彔鍚嶇О
+ symbol: "circle",
itemStyle: {
color: "#F7BA1E", // 璁剧疆杩欐潯绾跨殑棰滆壊
},
- data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320], // 褰掕繕娆℃暟鏁版嵁
+ data: monthlyPassRateData.value.map(item => item.process.passRate),
},
{
name: "鎴愬搧", // 绯诲垪鍚嶇О
type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
- stack: "Total", // 鍫嗗彔鍚嶇О
- symbol: "none",
+ // stack: "Total", // 鍫嗗彔鍚嶇О
+ symbol: "circle",
itemStyle: {
color: "#14C9C9", // 璁剧疆杩欐潯绾跨殑棰滆壊
},
- data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320], // 褰掕繕娆℃暟鏁版嵁
+ data: monthlyPassRateData.value.map(item => item.outgoing.passRate),
},
],
};
@@ -718,9 +848,14 @@
};
// 鍒濆鍖栬川妫�鍚堟牸鐜囧浘琛�
- const initQualityChart = (chartRef, color) => {
+ const initQualityChart = (chartRef, color, value = 0.8) => {
if (chartRef.value) {
- const chart = echarts.init(chartRef.value);
+ let chart = echarts.getInstanceByDom(chartRef.value);
+ if (!chart) {
+ chart = echarts.init(chartRef.value);
+ }
+ const numericValue =
+ typeof value === "string" ? parseFloat(value) / 100 : value / 100;
const option = {
series: [
{
@@ -734,8 +869,8 @@
show: false,
},
data: [
- { value: 0.8, itemStyle: { color: color } },
- { value: 0.2, itemStyle: { color: "#f5f5f5" } },
+ { value: numericValue, itemStyle: { color: color } },
+ { value: 1 - numericValue, itemStyle: { color: "#f5f5f5" } },
],
},
],
@@ -750,22 +885,34 @@
const initAllQualityCharts = () => {
materialCompletionChartInstance = initQualityChart(
materialCompletionChart,
- "#1890ff"
+ "#1890ff",
+ getPassRateStatValue(0, "completionRate")
);
materialQualityChartInstance = initQualityChart(
materialQualityChart,
- "#52c41a"
+ "#52c41a",
+ getPassRateStatValue(0, "passRate")
);
semiCompletionChartInstance = initQualityChart(
semiCompletionChart,
- "#1890ff"
+ "#1890ff",
+ getPassRateStatValue(1, "completionRate")
);
- semiQualityChartInstance = initQualityChart(semiQualityChart, "#52c41a");
+ semiQualityChartInstance = initQualityChart(
+ semiQualityChart,
+ "#52c41a",
+ getPassRateStatValue(1, "passRate")
+ );
finalCompletionChartInstance = initQualityChart(
finalCompletionChart,
- "#1890ff"
+ "#1890ff",
+ getPassRateStatValue(2, "completionRate")
);
- finalQualityChartInstance = initQualityChart(finalQualityChart, "#722ed1");
+ finalQualityChartInstance = initQualityChart(
+ finalQualityChart,
+ "#722ed1",
+ getPassRateStatValue(2, "passRate")
+ );
};
// 浜嬩欢澶勭悊鍑芥暟
@@ -854,8 +1001,19 @@
};
// 鐢熷懡鍛ㄦ湡
+ let resizeObserver = null;
onMounted(() => {
- initData();
+ // 璁$畻鍒濆缂╂斁姣斾緥
+ nextTick(() => {
+ calculateScale();
+ });
+
+ fetchInspectStatisticsData();
+ fetchPassRateStatisticsData();
+ fetchMonthlyPassRateData();
+ fetchYearlyPassRateData();
+ fetchMonthlyCompletionDetailsData();
+ fetchTopParametersData();
nextTick(() => {
initSampleChart();
initEquipmentChart();
@@ -864,30 +1022,48 @@
initAllQualityCharts();
});
// 鐩戝惉绐楀彛澶у皬鍙樺寲锛岄噸鏂拌皟鏁村浘琛ㄥぇ灏�
- window.addEventListener("resize", () => {
- sampleChart?.resize();
- equipmentChart?.resize();
- inspectionChart?.resize();
- usageChart?.resize();
+ window.addEventListener("resize", handleResize);
- // 璋冩暣璐ㄦ鍚堟牸鐜囧浘琛ㄥぇ灏�
- materialCompletionChartInstance?.resize();
- materialQualityChartInstance?.resize();
- semiCompletionChartInstance?.resize();
- semiQualityChartInstance?.resize();
- finalCompletionChartInstance?.resize();
- finalQualityChartInstance?.resize();
- });
+ // 浣跨敤 ResizeObserver 鐩戝惉瀹瑰櫒灏哄鍙樺寲锛堣В鍐充晶杈规爮鍒囨崲闂锛�
+ const container = document.querySelector(".scale-container");
+ if (container && window.ResizeObserver) {
+ resizeObserver = new ResizeObserver(() => {
+ handleResize();
+ });
+ resizeObserver.observe(container);
+ }
+ });
+
+ onBeforeUnmount(() => {
+ window.removeEventListener("resize", handleResize);
+ if (resizeObserver) {
+ resizeObserver.disconnect();
+ }
});
</script>
<style scoped>
+ .scale-container {
+ position: relative;
+ width: 100%;
+ height: calc(100vh - 84px);
+ background-color: #f0f2f5;
+ overflow-x: hidden;
+ overflow-y: auto;
+ }
+
+ .report-management-container {
+ position: relative;
+ width: 1920px;
+ height: 1080px;
+ transform-origin: left top;
+ background-color: #f0f2f5;
+ transition: transform 0.3s;
+ }
+
.report-management {
padding: 20px;
- background-color: #f5f5f5;
- min-height: 100vh;
- /* height: 87vh;
- overflow: hidden; */
+ height: 100%;
}
.page-header {
@@ -978,6 +1154,7 @@
.chart-card {
margin-bottom: 20px;
}
+
.container-line-right-bottom {
height: 20%;
width: 100%;
@@ -986,6 +1163,7 @@
align-items: center;
/* background-color: #5b3f3f; */
}
+
.card-header {
display: flex;
justify-content: flex-start;
@@ -999,6 +1177,7 @@
font-style: normal;
text-transform: none;
}
+
.chart-title-line {
width: 6px;
height: 22px;
@@ -1011,6 +1190,7 @@
height: 250px;
width: 100%;
}
+
.chart-container-line {
height: 250px;
width: 100%;
@@ -1051,18 +1231,22 @@
color: #fff;
background-color: #409eff;
}
+
.container-line-left {
height: 100%;
width: 66%;
}
+
.container-line-right {
height: 100%;
width: 34%;
}
+
.container-line2-left {
height: 100%;
width: 50%;
}
+
.info-box {
width: 92%;
margin-left: 4%;
@@ -1073,6 +1257,7 @@
align-items: center;
justify-content: space-around;
}
+
.info-box-header {
width: 100%;
margin-left: 20px;
@@ -1087,17 +1272,20 @@
padding-left: 20px;
align-items: center;
}
+
.info-icon {
width: 7px;
height: 7px;
border-radius: 50%;
margin-right: 8px;
}
+
.info-line-title {
font-size: 12px;
color: #4e5969;
flex: 1;
}
+
.info-line-value1 {
font-size: 12px;
color: #3d3d3d;
@@ -1105,6 +1293,7 @@
font-weight: 500;
margin-right: 15%;
}
+
.info-line-value2 {
font-size: 12px;
color: #3d3d3d;
@@ -1112,11 +1301,13 @@
font-weight: 500;
margin-right: 10%;
}
+
.top-container {
height: 130px;
width: 100%;
display: flex;
}
+
.typeNum {
height: 100%;
width: 33.33%;
@@ -1124,6 +1315,7 @@
align-items: center;
justify-content: center;
}
+
.typeNum-left {
font-size: 12px;
color: #909399;
@@ -1132,25 +1324,30 @@
align-items: center;
justify-content: center;
}
+
.typeNum-left-text {
font-size: 12px;
color: #3491fa;
font-weight: 500;
margin-top: 5px;
}
+
.table-card {
margin-bottom: 20px;
}
+
.typeNum-center {
display: flex;
align-items: center;
justify-content: center;
margin-left: 10px;
}
+
.typeNum-leftLine {
color: #3491fa;
font-size: 12px;
}
+
.typeNum-rightLine {
border-top: 1px solid #3491fa;
border-left: 1px solid #3491fa;
@@ -1158,10 +1355,12 @@
height: 80px;
width: 8px;
}
+
.typeNum-leftLine2 {
color: #5eb334;
font-size: 12px;
}
+
.typeNum-rightLine2 {
border-top: 1px solid #3491fa;
border-left: 1px solid #5eb334;
@@ -1169,10 +1368,12 @@
height: 80px;
width: 8px;
}
+
.typeNum-leftLine3 {
color: #8000ff;
font-size: 12px;
}
+
.typeNum-rightLine3 {
border-top: 1px solid #8000ff;
border-left: 1px solid #8000ff;
@@ -1180,6 +1381,7 @@
height: 80px;
width: 8px;
}
+
.typeNum-right {
margin-left: 10px;
display: flex;
@@ -1187,21 +1389,25 @@
height: 90%;
justify-content: space-between;
}
+
.typeNum-right-top-name {
font-weight: 400;
font-size: 12px;
color: #3d3d3d;
}
+
.typeNum-right-top-text {
font-weight: 400;
font-size: 16px;
color: rgba(0, 0, 0, 0.85);
margin-top: 5px;
}
+
.unit {
font-size: 12px;
color: #3d3d3d;
}
+
.inspection-chart-box {
height: 50px;
width: 30%;
@@ -1209,21 +1415,25 @@
border-radius: 8px;
padding-left: 15px;
}
+
.chart-box-title {
font-size: 12px;
color: #4e5969;
margin-top: 5px;
}
+
.unit {
font-size: 12px;
color: #3d3d3d;
}
+
.chart-box-num {
font-size: 18px;
color: #000;
margin-top: 5px;
font-weight: 500;
}
+
/* 璐ㄦ鍚堟牸鐜囧崱鐗囨牱寮� */
.top-container鍚堟牸鐜� {
height: 130px;
@@ -1233,9 +1443,11 @@
align-items: center;
justify-content: space-between;
}
+
.flex-center {
justify-content: space-evenly;
}
+
.quality-card {
/* flex: 1; */
width: 32%;
@@ -1272,9 +1484,11 @@
color: #666666;
margin-bottom: 3px;
}
+
.blue-label {
color: #1890ff;
}
+
.green-label {
color: #52c41a;
}
@@ -1317,9 +1531,10 @@
height: 60px;
margin-left: 10px;
}
+
/* .flex-center {
- justify-content: space-evenly;
- } */
+ justify-content: space-evenly;
+ } */
.blue-chart {
/* background-color: rgba(24, 144, 255, 0.1); */
@@ -1366,6 +1581,7 @@
margin-top: 20px;
text-align: right;
}
+
.yearchange {
position: absolute;
right: 40px;
@@ -1396,6 +1612,7 @@
:deep(.el-tag) {
margin: 0;
}
+
:deep(.el-input__prefix) {
display: none !important;
}
--
Gitblit v1.9.3