From 224248b6ff6baea525c324b2b80db78d00fbcf30 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期三, 21 一月 2026 09:40:51 +0800
Subject: [PATCH] feat: 质量管理-报表管理后端接口数据对接
---
src/views/reportAnalysis/reportManagement/index.vue | 1909 +++++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 1,332 insertions(+), 577 deletions(-)
diff --git a/src/views/reportAnalysis/reportManagement/index.vue b/src/views/reportAnalysis/reportManagement/index.vue
index b25619c..343a2c2 100644
--- a/src/views/reportAnalysis/reportManagement/index.vue
+++ b/src/views/reportAnalysis/reportManagement/index.vue
@@ -1,716 +1,1471 @@
<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>
+ <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">{{ 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>
+ <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">{{ 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>
+ <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>
+ </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">{{ 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="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>
+ </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" 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>
</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'
+import { ref, reactive, onMounted, nextTick } from "vue";
+import { ElMessage } from "element-plus";
+import * as echarts from "echarts";
+import { getInspectStatistics, getPassRateStatistics, getMonthlyPassRateStatistics, getYearlyPassRateStatistics, getMonthlyCompletionDetails, getTopParameters } from "@/api/reportAnalysis/qualityReport";
// 鍝嶅簲寮忔暟鎹�
const filterForm = reactive({
- dateRange: [],
- reportType: 'sample'
-})
+ dateRange: [],
+ 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 tableData = ref([])
-const tableLoading = ref(false)
+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.inspectType === type);
+ return stat ? stat[field] : 0;
+};
+
+const getInspectStatValue = (type, field) => {
+ const stat = inspectStatisticsData.value.find(item => item.inspectType === type);
+ return stat ? stat[field] : 0;
+};
+
+const getPassRateStatValue = (type, field) => {
+ const stat = passRateStatisticsData.value.find(item => item.inspectType === type);
+ if (stat) {
+ if (field === 'completionRate' || field === 'passRate') {
+ return stat[field] ? Number(stat[field]).toFixed(0) + '%' : '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: 0, semi: 1, final: 2 };
+ 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);
const pagination = reactive({
- currentPage: 1,
- pageSize: 20,
- total: 0
-})
+ currentPage: 1,
+ pageSize: 20,
+ total: 0,
+});
+
+// 鍒濆鍖栧勾浠戒负褰撳墠骞翠唤锛堜娇鐢―ate瀵硅薄锛�
+const currentYear = new Date().getFullYear();
+const value3 = ref(new Date(currentYear, 0, 1));
+
+// 闄愬埗鏃ユ湡閫夋嫨锛屼笉鍏佽閫夋嫨浠婂勾涔嬪悗鐨勫勾浠�
+const disabledDate = time => {
+ const currentYear = new Date().getFullYear();
+ return time.getFullYear() > currentYear;
+};
+
+// 鐩戝惉骞翠唤鍙樺寲
+import { watch } from "vue";
+watch(value3, () => {
+ fetchMonthlyPassRateData();
+ fetchYearlyPassRateData();
+ fetchMonthlyCompletionDetailsData();
+});
+
+watch(activeTab, () => {
+ fetchTopParametersData();
+});
+
// 鍥捐〃寮曠敤
-const sampleChartRef = ref(null)
-const equipmentChartRef = ref(null)
-const inspectionChartRef = ref(null)
-const usageChartRef = ref(null)
+const sampleChartRef = ref(null);
+const equipmentChartRef = ref(null);
+const inspectionChartRef = ref(null);
+const usageChartRef = ref(null);
+
+// 璐ㄦ鍚堟牸鐜囧浘琛ㄥ紩鐢�
+const materialCompletionChart = ref(null);
+const materialQualityChart = ref(null);
+const semiCompletionChart = ref(null);
+const semiQualityChart = ref(null);
+const finalCompletionChart = ref(null);
+const finalQualityChart = ref(null);
// 鍥捐〃瀹炰緥
-let sampleChart = null
-let equipmentChart = null
-let inspectionChart = null
-let usageChart = 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
-}
+// 璐ㄦ鍚堟牸鐜囧浘琛ㄥ疄渚�
+let materialCompletionChartInstance = null;
+let materialQualityChartInstance = null;
+let semiCompletionChartInstance = null;
+let semiQualityChartInstance = null;
+let finalCompletionChartInstance = null;
+let finalQualityChartInstance = null;
// 鍒濆鍖栨牱鍝佽繘搴﹀浘琛�
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)
- }
-}
+ 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%", "80%"],
+ avoidLabelOverlap: false,
+ label: {
+ show: false,
+ position: "center",
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: "18",
+ fontWeight: "bold",
+ },
+ },
+ labelLine: {
+ show: false,
+ },
+ data: topParametersData.value.list.map((item, index) => ({
+ value: item.count,
+ name: item.name,
+ itemStyle: { color: getParameterColor(index) }
+ })),
+ },
+ ],
+ };
+ 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)
- }
-}
+ if (equipmentChartRef.value) {
+ equipmentChart = echarts.init(equipmentChartRef.value);
+ const option = {
+ title: {
+ show: false,
+ },
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "shadow",
+ },
+ },
+ grid: {
+ left: "1%",
+ right: "1%",
+ bottom: "1%",
+ containLabel: true,
+ },
+ legend: {
+ data: ["鍘熸潗鏂�", "鍗婃垚鍝�", "鎴愬搧"], // 鍥句緥鏁版嵁
+ icon: ["circle", "circle", "circle"],
+ itemWidth: 10, // 璁剧疆鍥炬爣瀹藉害
+ itemHeight: 10,
+ itemGap: 30,
+ right: 10,
+ },
+ xAxis: {
+ type: "category",
+ data: [
+ value3.value.getFullYear() + "-1",
+ value3.value.getFullYear() + "-2",
+ value3.value.getFullYear() + "-3",
+ value3.value.getFullYear() + "-4",
+ value3.value.getFullYear() + "-5",
+ value3.value.getFullYear() + "-6",
+ value3.value.getFullYear() + "-7",
+ value3.value.getFullYear() + "-8",
+ value3.value.getFullYear() + "-9",
+ value3.value.getFullYear() + "-10",
+ value3.value.getFullYear() + "-11",
+ value3.value.getFullYear() + "-12",
+ ], // 鏀逛负鍗佷簩涓湀
+ },
+ yAxis: {
+ type: "value",
+ name: "鏁�(涓�)",
+ },
+ series: [
+ {
+ name: "鍘熸潗鏂�",
+ type: "bar",
+ barWidth: "15%",
+ data: monthlyCompletionDetailsData.value.map(item => item.rawMaterialCount),
+ itemStyle: {
+ color: "#409EFF",
+ },
+ },
+ {
+ name: "鍗婃垚鍝�",
+ type: "bar",
+ barWidth: "15%",
+
+ data: monthlyCompletionDetailsData.value.map(item => item.processCount),
+ itemStyle: {
+ color: "#67C23A",
+ },
+ },
+ {
+ name: "鎴愬搧",
+ type: "bar",
+ barWidth: "15%",
+
+ data: monthlyCompletionDetailsData.value.map(item => item.outgoingCount),
+ itemStyle: {
+ color: "#E6A23C",
+ },
+ },
+ ],
+ };
+ 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)
- }
-}
+ if (inspectionChartRef.value) {
+ inspectionChart = echarts.init(inspectionChartRef.value);
+ const option = {
+ title: {
+ show: false,
+ },
+ tooltip: {
+ trigger: "item",
+ },
+ series: [
+ {
+ type: "pie",
+ radius: "70%",
+ data: [
+ { 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,
+ 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)
- }
-}
+ // 妫�鏌ュ浘琛ㄥ鍣ㄦ槸鍚﹀瓨鍦�
+ if (usageChartRef.value) {
+ // 鍒濆鍖� ECharts 瀹炰緥
+ usageChart = echarts.init(usageChartRef.value);
+ // 閰嶇疆鍥捐〃閫夐」
+ const option = {
+ // 鏍囬閰嶇疆锛堥殣钘忥級
+ title: {
+ show: false,
+ },
+
+ // 缃戞牸閰嶇疆锛堣皟鏁磋竟璺濓級
+ grid: {
+ left: "1%",
+ right: "4%",
+ bottom: "3%",
+ top: "14%",
+ containLabel: true,
+ },
+ // 鎻愮ず妗嗛厤缃�
+ tooltip: {
+ trigger: "axis", // 瑙﹀彂绫诲瀷涓哄潗鏍囪酱瑙﹀彂
+ },
+ // 鍥句緥閰嶇疆
+ legend: {
+ data: ["鍘熸潗鏂�", "鍗婃垚鍝�", "鎴愬搧"], // 鍥句緥鏁版嵁
+ icon: ["circle", "circle", "circle"],
+ itemWidth: 10, // 璁剧疆鍥炬爣瀹藉害
+ itemHeight: 10,
+ itemGap: 30,
+ },
+ // X杞撮厤缃�
+ xAxis: {
+ type: "category", // 绫诲埆杞�
+ boundaryGap: false, // 鍧愭爣杞翠袱杈圭暀鐧界瓥鐣�
+ data: [
+ value3.value.getFullYear() + "-1",
+ value3.value.getFullYear() + "-2",
+ value3.value.getFullYear() + "-3",
+ value3.value.getFullYear() + "-4",
+ value3.value.getFullYear() + "-5",
+ value3.value.getFullYear() + "-6",
+ value3.value.getFullYear() + "-7",
+ value3.value.getFullYear() + "-8",
+ value3.value.getFullYear() + "-9",
+ value3.value.getFullYear() + "-10",
+ value3.value.getFullYear() + "-11",
+ value3.value.getFullYear() + "-12",
+ ], // X杞存暟鎹�
+ },
+ // Y杞撮厤缃�
+ yAxis: {
+ type: "value", // 鏁板�艰酱
+ name: "鍗曚綅锛�%",
+ },
+ // 绯诲垪鏁版嵁
+ series: [
+ {
+ name: "鍘熸潗鏂�", // 绯诲垪鍚嶇О
+ type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
+ // stack: "Total", // 鍫嗗彔鍚嶇О
+ symbol: "circle",
+ itemStyle: {
+ color: "#1890FF", // 璁剧疆杩欐潯绾跨殑棰滆壊
+ },
+ data: monthlyPassRateData.value.map(item => item.rawMaterial.passRate),
+ },
+ {
+ name: "鍗婃垚鍝�", // 绯诲垪鍚嶇О
+ type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
+ // stack: "Total", // 鍫嗗彔鍚嶇О
+ symbol: "circle",
+ itemStyle: {
+ color: "#F7BA1E", // 璁剧疆杩欐潯绾跨殑棰滆壊
+ },
+ data: monthlyPassRateData.value.map(item => item.process.passRate),
+ },
+ {
+ name: "鎴愬搧", // 绯诲垪鍚嶇О
+ type: "line", // 鍥捐〃绫诲瀷涓烘姌绾垮浘
+ // stack: "Total", // 鍫嗗彔鍚嶇О
+ symbol: "circle",
+ itemStyle: {
+ color: "#14C9C9", // 璁剧疆杩欐潯绾跨殑棰滆壊
+ },
+ data: monthlyPassRateData.value.map(item => item.outgoing.passRate),
+ },
+ ],
+ };
+ // 灏嗛厤缃簲鐢ㄥ埌鍥捐〃
+ usageChart.setOption(option);
+ }
+};
+
+// 鍒濆鍖栬川妫�鍚堟牸鐜囧浘琛�
+const initQualityChart = (chartRef, color, value = 0.8) => {
+ if (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: [
+ {
+ type: "pie",
+ radius: ["45%", "90%"],
+ itemStyle: {
+ borderColor: "#f5f5f5",
+ // borderWidth: 2,
+ },
+ labelLine: {
+ show: false,
+ },
+ data: [
+ { value: numericValue, itemStyle: { color: color } },
+ { value: 1 - numericValue, itemStyle: { color: "#f5f5f5" } },
+ ],
+ },
+ ],
+ };
+ chart.setOption(option);
+ return chart;
+ }
+ return null;
+};
+
+// 鍒濆鍖栨墍鏈夎川妫�鍚堟牸鐜囧浘琛�
+const initAllQualityCharts = () => {
+ materialCompletionChartInstance = initQualityChart(
+ materialCompletionChart,
+ "#1890ff",
+ getPassRateStatValue(0, 'completionRate')
+ );
+ materialQualityChartInstance = initQualityChart(
+ materialQualityChart,
+ "#52c41a",
+ getPassRateStatValue(0, 'passRate')
+ );
+ semiCompletionChartInstance = initQualityChart(
+ semiCompletionChart,
+ "#1890ff",
+ getPassRateStatValue(1, 'completionRate')
+ );
+ semiQualityChartInstance = initQualityChart(
+ semiQualityChart,
+ "#52c41a",
+ getPassRateStatValue(1, 'passRate')
+ );
+ finalCompletionChartInstance = initQualityChart(
+ finalCompletionChart,
+ "#1890ff",
+ getPassRateStatValue(2, 'completionRate')
+ );
+ finalQualityChartInstance = initQualityChart(
+ finalQualityChart,
+ "#722ed1",
+ getPassRateStatValue(2, 'passRate')
+ );
+};
// 浜嬩欢澶勭悊鍑芥暟
const handleFilterChange = () => {
- ElMessage.success('绛涢�夋潯浠跺凡鏇存柊')
- // 杩欓噷鍙互鏍规嵁绛涢�夋潯浠堕噸鏂板姞杞芥暟鎹�
-}
+ ElMessage.success("绛涢�夋潯浠跺凡鏇存柊");
+ // 杩欓噷鍙互鏍规嵁绛涢�夋潯浠堕噸鏂板姞杞芥暟鎹�
+};
const resetFilter = () => {
- filterForm.dateRange = []
- filterForm.reportType = 'sample'
- ElMessage.info('绛涢�夋潯浠跺凡閲嶇疆')
-}
+ filterForm.dateRange = [];
+ filterForm.reportType = "sample";
+ ElMessage.info("绛涢�夋潯浠跺凡閲嶇疆");
+};
const exportReport = () => {
- ElMessage.success('鎶ヨ〃瀵煎嚭鍔熻兘寮�鍙戜腑...')
-}
+ ElMessage.success("鎶ヨ〃瀵煎嚭鍔熻兘寮�鍙戜腑...");
+};
const refreshSampleChart = () => {
- initSampleChart()
- ElMessage.success('鏍峰搧杩涘害鍥捐〃宸插埛鏂�')
-}
+ initSampleChart();
+ ElMessage.success("鏍峰搧杩涘害鍥捐〃宸插埛鏂�");
+};
const refreshEquipmentChart = () => {
- initEquipmentChart()
- ElMessage.success('璁惧浣跨敤鍥捐〃宸插埛鏂�')
-}
+ initEquipmentChart();
+ ElMessage.success("璁惧浣跨敤鍥捐〃宸插埛鏂�");
+};
const refreshInspectionChart = () => {
- initInspectionChart()
- ElMessage.success('妫�娴嬮」鐩浘琛ㄥ凡鍒锋柊')
-}
+ initInspectionChart();
+ ElMessage.success("妫�娴嬮」鐩浘琛ㄥ凡鍒锋柊");
+};
const refreshUsageChart = () => {
- initUsageChart()
- ElMessage.success('棰嗙敤璁板綍鍥捐〃宸插埛鏂�')
-}
+ initUsageChart();
+ ElMessage.success("棰嗙敤璁板綍鍥捐〃宸插埛鏂�");
+};
const refreshTable = () => {
- tableLoading.value = true
- setTimeout(() => {
- tableLoading.value = false
- ElMessage.success('琛ㄦ牸鏁版嵁宸插埛鏂�')
- }, 1000)
-}
+ tableLoading.value = true;
+ setTimeout(() => {
+ tableLoading.value = false;
+ ElMessage.success("琛ㄦ牸鏁版嵁宸插埛鏂�");
+ }, 1000);
+};
const exportTable = () => {
- ElMessage.success('琛ㄦ牸瀵煎嚭鍔熻兘寮�鍙戜腑...')
-}
+ ElMessage.success("琛ㄦ牸瀵煎嚭鍔熻兘寮�鍙戜腑...");
+};
-const handleSizeChange = (val) => {
- pagination.pageSize = val
- // 閲嶆柊鍔犺浇鏁版嵁
-}
+const handleSizeChange = val => {
+ pagination.pageSize = val;
+ // 閲嶆柊鍔犺浇鏁版嵁
+};
-const handleCurrentChange = (val) => {
- pagination.currentPage = val
- // 閲嶆柊鍔犺浇鏁版嵁
-}
+const handleCurrentChange = val => {
+ pagination.currentPage = val;
+ // 閲嶆柊鍔犺浇鏁版嵁
+};
-const getStatusType = (status) => {
- const statusMap = {
- '宸插畬鎴�': 'success',
- '妫�娴嬩腑': 'warning',
- '寰呮娴�': 'info',
- '宸叉殏鍋�': 'danger',
- '浣跨敤涓�': 'primary',
- '绌洪棽': 'info'
- }
- return statusMap[status] || 'info'
-}
+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 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 viewDetail = row => {
+ ElMessage.info(`鏌ョ湅璇︽儏: ${row.name}`);
+};
-const editItem = (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()
- })
-})
+ fetchInspectStatisticsData();
+ fetchPassRateStatisticsData();
+ fetchMonthlyPassRateData();
+ fetchYearlyPassRateData();
+ fetchMonthlyCompletionDetailsData();
+ fetchTopParametersData();
+ nextTick(() => {
+ initSampleChart();
+ initEquipmentChart();
+ initInspectionChart();
+ initUsageChart();
+ initAllQualityCharts();
+ });
+ // 鐩戝惉绐楀彛澶у皬鍙樺寲锛岄噸鏂拌皟鏁村浘琛ㄥぇ灏�
+ window.addEventListener("resize", () => {
+ sampleChart?.resize();
+ equipmentChart?.resize();
+ inspectionChart?.resize();
+ usageChart?.resize();
+
+ // 璋冩暣璐ㄦ鍚堟牸鐜囧浘琛ㄥぇ灏�
+ materialCompletionChartInstance?.resize();
+ materialQualityChartInstance?.resize();
+ semiCompletionChartInstance?.resize();
+ semiQualityChartInstance?.resize();
+ finalCompletionChartInstance?.resize();
+ finalQualityChartInstance?.resize();
+ });
+});
</script>
<style scoped>
.report-management {
- padding: 20px;
- background-color: #f5f5f5;
- min-height: 100vh;
+ padding: 20px;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+ /* height: 87vh;
+ overflow: hidden; */
}
.page-header {
- margin-bottom: 20px;
- text-align: center;
+ margin-bottom: 20px;
+ text-align: center;
}
.page-header h2 {
- color: #303133;
- margin-bottom: 8px;
- font-size: 24px;
- font-weight: 600;
+ color: #303133;
+ margin-bottom: 8px;
+ font-size: 24px;
+ font-weight: 600;
}
.page-header p {
- color: #909399;
- font-size: 14px;
- margin: 0;
+ color: #909399;
+ font-size: 14px;
+ margin: 0;
}
.filter-card {
- margin-bottom: 20px;
+ margin-bottom: 20px;
}
.statistics-cards {
- margin-bottom: 20px;
+ margin-bottom: 20px;
}
.stat-card {
- height: 120px;
+ height: 120px;
}
.stat-content {
- display: flex;
- align-items: center;
- height: 100%;
+ 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;
+ 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%);
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.stat-card:nth-child(2) .stat-icon {
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.stat-card:nth-child(3) .stat-icon {
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.stat-card:nth-child(4) .stat-icon {
- background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
+ background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.stat-info {
- flex: 1;
+ flex: 1;
}
.stat-number {
- font-size: 28px;
- font-weight: bold;
- color: #303133;
- margin-bottom: 8px;
+ font-size: 28px;
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 8px;
}
.stat-label {
- font-size: 14px;
- color: #909399;
+ font-size: 14px;
+ color: #909399;
}
.charts-container {
- margin-bottom: 20px;
+ /* margin-bottom: 20px; */
+ position: relative;
}
.chart-card {
- margin-bottom: 20px;
+ margin-bottom: 20px;
+}
+
+.container-line-right-bottom {
+ height: 20%;
+ width: 100%;
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ /* background-color: #5b3f3f; */
}
.card-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ font-family: Source Han Sans, Source Han Sans;
+ font-weight: 700;
+ font-size: 18px;
+ color: #000000;
+ /* line-height: 27px; */
+ text-align: left;
+ font-style: normal;
+ text-transform: none;
+}
+
+.chart-title-line {
+ width: 6px;
+ height: 22px;
+ background-color: #161a9a;
+ margin-right: 16px;
+ border-radius: 3px;
}
.chart-container {
- height: 300px;
- width: 100%;
+ height: 250px;
+ width: 100%;
+}
+
+.chart-container-line {
+ height: 250px;
+ width: 100%;
+ display: flex;
+ position: relative;
+}
+
+/* Tab 閫夋嫨鍣ㄦ牱寮� */
+.tab-selector {
+ position: absolute;
+ top: 20px;
+ right: 40px;
+ display: flex;
+ border: 1px solid #dcdfe6;
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.tab-item {
+ padding: 4px 12px;
+ cursor: pointer;
+ font-size: 14px;
+ color: #606266;
+ background-color: #fff;
+ border-right: 1px solid #dcdfe6;
+ transition: all 0.3s;
+}
+
+.tab-item:last-child {
+ border-right: none;
+}
+
+.tab-item:hover {
+ color: #409eff;
+}
+
+.tab-item.active {
+ 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%;
+ height: 100%;
+ background-color: #f7f8fa;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.info-box-header {
+ width: 100%;
+ margin-left: 20px;
+ color: #1d2129;
+ font-size: 16px;
+ font-weight: 500;
+}
+
+.info-line {
+ width: 100%;
+ display: flex;
+ 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;
+ color: #1d2129;
+ font-weight: 500;
+ margin-right: 15%;
+}
+
+.info-line-value2 {
+ font-size: 12px;
+ color: #3d3d3d;
+ color: #1d2129;
+ font-weight: 500;
+ margin-right: 10%;
+}
+
+.top-container {
+ height: 130px;
+ width: 100%;
+ display: flex;
+}
+
+.typeNum {
+ height: 100%;
+ width: 33.33%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.typeNum-left {
+ font-size: 12px;
+ color: #909399;
+ display: flex;
+ flex-direction: column;
+ 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;
+ 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;
+ border-bottom: 1px solid #3491fa;
+ height: 80px;
+ width: 8px;
+}
+
+.typeNum-leftLine2 {
+ color: #5eb334;
+ font-size: 12px;
+}
+
+.typeNum-rightLine2 {
+ border-top: 1px solid #3491fa;
+ border-left: 1px solid #5eb334;
+ border-bottom: 1px solid #5eb334;
+ height: 80px;
+ width: 8px;
+}
+
+.typeNum-leftLine3 {
+ color: #8000ff;
+ font-size: 12px;
+}
+
+.typeNum-rightLine3 {
+ border-top: 1px solid #8000ff;
+ border-left: 1px solid #8000ff;
+ border-bottom: 1px solid #8000ff;
+ height: 80px;
+ width: 8px;
+}
+
+.typeNum-right {
+ margin-left: 10px;
+ display: flex;
+ flex-direction: column;
+ 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%;
+ background-color: #f7f8fa;
+ 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;
+ width: 100%;
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.flex-center {
+ justify-content: space-evenly;
+}
+
+.quality-card {
+ /* flex: 1; */
+ width: 32%;
+ /* height: 100px; */
+ border-radius: 8px;
+ padding: 12px;
+ display: flex;
+ flex-direction: column;
+}
+
+.blue-card {
+ background-color: #e6f7ff;
+}
+
+.green-card {
+ background-color: #f6ffed;
+ color: #000000;
+}
+
+.purple-card {
+ background-color: #f9f0ff;
+}
+
+.quality-card-title {
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: 10px;
+ display: flex;
+ align-items: center;
+}
+
+.quality-item-tip {
+ font-size: 12px;
+ color: #666666;
+ margin-bottom: 3px;
+}
+
+.blue-label {
+ color: #1890ff;
+}
+
+.green-label {
+ color: #52c41a;
+}
+
+.quality-card-title {
+ color: #000;
+ font-weight: bold;
+}
+
+.quality-card-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex: 1;
+}
+
+.quality-item {
+ display: flex;
+ /* flex-direction: column; */
+ align-items: center;
+ justify-content: center;
+ margin-top: 5px;
+ flex: 1;
+}
+
+.quality-item-label {
+ font-size: 12px;
+ /* color: #666; */
+ margin-bottom: 4px;
+}
+
+.quality-item-value {
+ font-size: 20px;
+ font-weight: 500;
+ margin-bottom: 4px;
+}
+
+.quality-item-chart {
+ width: 60px;
+ height: 60px;
+ margin-left: 10px;
+}
+
+/* .flex-center {
+justify-content: space-evenly;
+} */
+
+.blue-chart {
+ /* background-color: rgba(24, 144, 255, 0.1); */
+}
+
+.green-chart {
+ /* background-color: rgba(82, 196, 26, 0.1); */
+}
+
+.purple-chart {
+ /* background-color: rgba(114, 46, 209, 0.1); */
+}
+
+.chart-ring {
+ width: 60px;
+ height: 60px;
+ border-radius: 50%;
+ border: 15px solid transparent;
+ position: relative;
+}
+
+.blue-chart .chart-ring {
+ border-top-color: #1890ff;
+ border-right-color: #1890ff;
+ border-bottom-color: #1890ff;
+ transform: rotate(45deg);
+}
+
+.green-chart .chart-ring {
+ border-top-color: #52c41a;
+ border-right-color: #52c41a;
+ border-bottom-color: #52c41a;
+ transform: rotate(45deg);
+}
+
+.purple-chart .chart-ring {
+ border-top-color: #722ed1;
+ border-right-color: #722ed1;
+ border-bottom-color: #722ed1;
+ transform: rotate(45deg);
}
.pagination-container {
- margin-top: 20px;
- text-align: right;
+ margin-top: 20px;
+ text-align: right;
+}
+
+.yearchange {
+ position: absolute;
+ right: 40px;
+ top: 20px;
+ display: flex;
+ align-items: center;
+ /* width: 60px; */
}
:deep(.el-card__header) {
- padding: 15px 20px;
- border-bottom: 1px solid #ebeef5;
- background-color: #fafafa;
+ padding: 15px 20px;
+ border-bottom: 1px solid #ffffff;
+ background-color: #ffffff;
}
:deep(.el-card__body) {
- padding: 20px;
+ padding: 20px;
}
:deep(.el-table) {
- margin-bottom: 20px;
+ margin-bottom: 20px;
}
:deep(.el-progress) {
- margin: 0;
+ margin: 0;
}
:deep(.el-tag) {
- margin: 0;
+ margin: 0;
+}
+
+:deep(.el-input__prefix) {
+ display: none !important;
}
</style>
--
Gitblit v1.9.3