From 9d94bacb1e7decb49a4a6d3de171355867f7fde7 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期一, 01 六月 2026 14:15:23 +0800
Subject: [PATCH] fix:质检合格率 添加同比环比
---
src/views/reportAnalysis/reportManagement/index.vue | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/api/reportAnalysis/qualityReport.js | 9 +
2 files changed, 467 insertions(+), 7 deletions(-)
diff --git a/src/api/reportAnalysis/qualityReport.js b/src/api/reportAnalysis/qualityReport.js
index 66a7540..214425d 100644
--- a/src/api/reportAnalysis/qualityReport.js
+++ b/src/api/reportAnalysis/qualityReport.js
@@ -50,3 +50,12 @@
params: { modelType }
})
}
+
+// 鑾峰彇鏈堝害鍚堟牸鐜囩幆姣旂粺璁℃暟鎹�
+export function getMonthlyPassRateWithComparison(year, month) {
+ return request({
+ url: '/qualityReport/getMonthlyPassRateWithComparison',
+ method: 'post',
+ params: { year, month }
+ })
+}
diff --git a/src/views/reportAnalysis/reportManagement/index.vue b/src/views/reportAnalysis/reportManagement/index.vue
index dc9d486..6bcc5cd 100644
--- a/src/views/reportAnalysis/reportManagement/index.vue
+++ b/src/views/reportAnalysis/reportManagement/index.vue
@@ -15,7 +15,7 @@
<div class="top-container">
<div class="typeNum">
<div class="typeNum-left">
- <img src="~@/assets/images/chartCard.svg" alt="鍥捐〃"
+ <img :src="chartCardIcon" alt="鍥捐〃"
style="width: 40px; height: 40px; object-fit: contain;">
<div class="typeNum-left-text">鍘熸潗鏂�</div>
</div>
@@ -39,7 +39,7 @@
</div>
<div class="typeNum">
<div class="typeNum-left">
- <img src="~@/assets/images/chartCard2.svg" alt="鍥捐〃"
+ <img :src="chartCard2Icon" alt="鍥捐〃"
style="width: 40px; height: 40px; object-fit: contain;">
<div class="typeNum-left-text" style="color: #5EB334;">鍗婃垚鍝�</div>
</div>
@@ -63,7 +63,7 @@
</div>
<div class="typeNum">
<div class="typeNum-left">
- <img src="~@/assets/images/chartCard3.svg" alt="鍥捐〃"
+ <img :src="chartCard3Icon" alt="鍥捐〃"
style="width: 40px; height: 40px; object-fit: contain;">
<div class="typeNum-left-text" style="color: #8000FF;">鎴愬搧</div>
</div>
@@ -100,7 +100,7 @@
<div class="top-container flex-center">
<div class="quality-card blue-card">
<div class="quality-card-title">
- <img src="~@/assets/images/chartCard.svg" alt="鍘熸潗鏂�"
+ <img :src="chartCardIcon" alt="鍘熸潗鏂�"
style="width: 24px; height: 24px; margin-right: 8px;">
鍘熸潗鏂欏悎鏍肩巼
</div>
@@ -125,7 +125,7 @@
</div>
<div class="quality-card green-card">
<div class="quality-card-title">
- <img src="~@/assets/images/chartCard2.svg" alt="鍗婃垚鍝�"
+ <img :src="chartCard2Icon" alt="鍗婃垚鍝�"
style="width: 24px; height: 24px; margin-right: 8px;">
鍗婃垚鍝佸悎鏍肩巼
</div>
@@ -150,7 +150,7 @@
</div>
<div class="quality-card purple-card">
<div class="quality-card-title">
- <img src="~@/assets/images/chartCard3.svg" alt="鎴愬搧"
+ <img :src="chartCard3Icon" alt="鎴愬搧"
style="width: 24px; height: 24px; margin-right: 8px;">
鎴愬搧鍚堟牸鐜�
</div>
@@ -189,6 +189,120 @@
<span>璐ㄦ鍚堟牸鐜�</span>
</div>
</template>
+ <!-- 鐜瘮鎸囨爣鍗$墖 -->
+ <div class="mom-cards">
+ <!-- 鏈堜唤閫夋嫨鍣� -->
+ <div class="mom-month-selector">
+ <span class="mom-month-label">閫夋嫨鏈堜唤锛�</span>
+ <el-date-picker
+ v-model="momSelectedMonth"
+ type="month"
+ placeholder="閫夋嫨鏈堜唤"
+ format="YYYY骞碝M鏈�"
+ value-format="YYYY-MM"
+ :clearable="false"
+ :disabled-date="disabledMonthDate"
+ style="width: 150px;"
+ />
+ </div>
+
+ <!-- 涓籘ab锛氱被鍒垏鎹� -->
+ <div class="mom-main-tabs">
+ <div class="mom-tab-item" :class="{ active: momMainTab === 'raw' }" @click="momMainTab = 'raw'">
+ <img :src="chartCardIcon" alt="" style="width: 16px; height: 16px; margin-right: 6px;">
+ 鍘熸潗鏂�
+ </div>
+ <div class="mom-tab-item" :class="{ active: momMainTab === 'semi' }" @click="momMainTab = 'semi'">
+ <img :src="chartCard2Icon" alt="" style="width: 16px; height: 16px; margin-right: 6px;">
+ 鍗婃垚鍝�
+ </div>
+ <div class="mom-tab-item" :class="{ active: momMainTab === 'final' }" @click="momMainTab = 'final'">
+ <img :src="chartCard3Icon" alt="" style="width: 16px; height: 16px; margin-right: 6px;">
+ 鎴愬搧
+ </div>
+ </div>
+
+ <!-- 瀛怲ab锛氭寚鏍囧垏鎹� -->
+ <div class="mom-sub-tabs">
+ <div class="mom-sub-tab-item" :class="{ active: momSubTab === 'current' }" @click="momSubTab = 'current'">
+ 褰撴湀鍚堟牸鐜�
+ </div>
+ <div class="mom-sub-tab-item" :class="{ active: momSubTab === 'mom' }" @click="momSubTab = 'mom'">
+ 鐜瘮鍙樺寲
+ </div>
+ <div class="mom-sub-tab-item" :class="{ active: momSubTab === 'yoy' }" @click="momSubTab = 'yoy'">
+ 鍚屾瘮鍙樺寲
+ </div>
+ </div>
+
+ <!-- 鏁版嵁灞曠ず鍖哄煙 -->
+ <div class="mom-data-panel">
+ <!-- 褰撴湀鍚堟牸鐜� -->
+ <div v-if="momSubTab === 'current'" class="mom-data-content">
+ <div class="mom-data-value">{{ getCurrentMomData().passRate }}%</div>
+ <div class="mom-data-detail">
+ <div class="mom-detail-item">
+ <span class="mom-detail-label">鎬绘暟閲�</span>
+ <span class="mom-detail-value">{{ getCurrentMomData().totalCount }}</span>
+ </div>
+ <div class="mom-detail-item">
+ <span class="mom-detail-label">宸插畬鎴�</span>
+ <span class="mom-detail-value">{{ getCurrentMomData().completedCount }}</span>
+ </div>
+ <div class="mom-detail-item">
+ <span class="mom-detail-label">鍚堟牸鏁�</span>
+ <span class="mom-detail-value">{{ getCurrentMomData().qualifiedCount }}</span>
+ </div>
+ </div>
+ </div>
+
+ <!-- 鐜瘮鍙樺寲 -->
+ <div v-if="momSubTab === 'mom'" class="mom-data-content">
+ <div class="mom-data-header">
+ <div class="mom-compare-item">
+ <span class="mom-compare-label">褰撴湀鍚堟牸鐜�</span>
+ <span class="mom-compare-value primary">{{ getCurrentMomData().passRate }}%</span>
+ </div>
+ <div class="mom-compare-arrow" :class="getTrendClass(getCurrentMomData().momTrend)">
+ {{ getTrendIcon(getCurrentMomData().momTrend) }}
+ </div>
+ <div class="mom-compare-item">
+ <span class="mom-compare-label">涓婃湀鍚堟牸鐜�</span>
+ <span class="mom-compare-value">{{ getCurrentMomData().lastMonthPassRate || 0 }}%</span>
+ </div>
+ </div>
+ <div class="mom-data-change" :class="getTrendClass(getCurrentMomData().momTrend)">
+ 鐜瘮鍙樺寲: {{ formatChange(getCurrentMomData().momChange) }}
+ </div>
+ <div class="mom-data-desc">
+ 涓庝笂鏈堢浉姣旓紝鍚堟牸鐜噞{ getCurrentMomData().momTrend > 0 ? '涓婂崌' : getCurrentMomData().momTrend < 0 ? '涓嬮檷' : '鎸佸钩' }}
+ </div>
+ </div>
+
+ <!-- 鍚屾瘮鍙樺寲 -->
+ <div v-if="momSubTab === 'yoy'" class="mom-data-content">
+ <div class="mom-data-header">
+ <div class="mom-compare-item">
+ <span class="mom-compare-label">褰撴湀鍚堟牸鐜�</span>
+ <span class="mom-compare-value primary">{{ getCurrentMomData().passRate }}%</span>
+ </div>
+ <div class="mom-compare-arrow" :class="getTrendClass(getCurrentMomData().yoyTrend)">
+ {{ getTrendIcon(getCurrentMomData().yoyTrend) }}
+ </div>
+ <div class="mom-compare-item">
+ <span class="mom-compare-label">鍘诲勾鍚屾湀</span>
+ <span class="mom-compare-value">{{ getCurrentMomData().lastYearPassRate || 0 }}%</span>
+ </div>
+ </div>
+ <div class="mom-data-change" :class="getTrendClass(getCurrentMomData().yoyTrend)">
+ 鍚屾瘮鍙樺寲: {{ formatChange(getCurrentMomData().yoyChange) }}
+ </div>
+ <div class="mom-data-desc">
+ 涓庡幓骞村悓鏈堢浉姣旓紝鍚堟牸鐜噞{ getCurrentMomData().yoyTrend > 0 ? '涓婂崌' : getCurrentMomData().yoyTrend < 0 ? '涓嬮檷' : '鎸佸钩' }}
+ </div>
+ </div>
+ </div>
+ </div>
<div class="chart-container-line">
<div class="container-line-left">
<div style="height: 100%; width: 100%;" ref="usageChartRef">
@@ -280,13 +394,99 @@
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";
+import { getInspectStatistics, getPassRateStatistics, getMonthlyPassRateStatistics, getYearlyPassRateStatistics, getMonthlyCompletionDetails, getTopParameters, getMonthlyPassRateWithComparison } from "@/api/reportAnalysis/qualityReport";
+
+// 瀵煎叆鍥炬爣
+import chartCardIcon from '@/assets/images/chartCard.svg';
+import chartCard2Icon from '@/assets/images/chartCard2.svg';
+import chartCard3Icon from '@/assets/images/chartCard3.svg';
// 鍝嶅簲寮忔暟鎹�
const filterForm = reactive({
dateRange: [],
reportType: "sample",
});
+
+// 鐜瘮鏁版嵁
+const momData = ref([
+ { label: '鍘熸潗鏂�', passRate: 0, momChange: 0, yoyChange: 0, momTrend: 0, yoyTrend: 0, totalCount: 0, completedCount: 0, qualifiedCount: 0, lastMonthPassRate: 0, lastYearPassRate: 0 },
+ { label: '鍗婃垚鍝�', passRate: 0, momChange: 0, yoyChange: 0, momTrend: 0, yoyTrend: 0, totalCount: 0, completedCount: 0, qualifiedCount: 0, lastMonthPassRate: 0, lastYearPassRate: 0 },
+ { label: '鎴愬搧', passRate: 0, momChange: 0, yoyChange: 0, momTrend: 0, yoyTrend: 0, totalCount: 0, completedCount: 0, qualifiedCount: 0, lastMonthPassRate: 0, lastYearPassRate: 0 }
+]);
+
+// 鐜瘮Tab鐘舵��
+const momMainTab = ref('raw'); // 涓籘ab: raw, semi, final
+const momSubTab = ref('current'); // 瀛怲ab: current, mom, yoy
+
+// 鏈堜唤閫夋嫨鍣� - 榛樿褰撳墠鏈堜唤
+const momSelectedMonth = ref(new Date().toISOString().slice(0, 7)); // 鏍煎紡: YYYY-MM
+
+// 闄愬埗鏈堜唤閫夋嫨锛屼笉鍏佽閫夋嫨鏈潵鏈堜唤
+const disabledMonthDate = (time) => {
+ return time.getTime() > new Date().getTime();
+};
+
+// 鑾峰彇褰撳墠閫変腑绫诲埆鐨勬暟鎹�
+const getCurrentMomData = () => {
+ const index = momMainTab.value === 'raw' ? 0 : momMainTab.value === 'semi' ? 1 : 2;
+ return momData.value[index] || {};
+};
+
+// 鐜瘮鐩稿叧鏂规硶
+const getMomIcon = (index) => {
+ const icons = [chartCardIcon, chartCard2Icon, chartCard3Icon];
+ return icons[index];
+};
+
+const getMomIconColor = (index) => {
+ const colors = ['#165DFF', '#5EB334', '#722ED1'];
+ return colors[index];
+};
+
+const getTrendClass = (trend) => {
+ if (trend > 0) return 'trend-up';
+ if (trend < 0) return 'trend-down';
+ return 'trend-flat';
+};
+
+const getTrendIcon = (trend) => {
+ if (trend > 0) return '鈫�';
+ if (trend < 0) return '鈫�';
+ return '-';
+};
+
+const formatChange = (change) => {
+ if (!change) return '0%';
+ const value = Number(change).toFixed(1);
+ return value > 0 ? `+${value}%` : `${value}%`;
+};
+
+const fetchMomData = async () => {
+ try {
+ // 浠庨�変腑鐨勬湀浠戒腑瑙f瀽骞翠唤鍜屾湀浠�
+ const [year, monthStr] = momSelectedMonth.value.split('-');
+ const month = parseInt(monthStr, 10);
+ const res = await getMonthlyPassRateWithComparison(year, month);
+ if (res.code === 200) {
+ const data = res.data || [];
+ momData.value = data.map(item => ({
+ label: item.modelType === 0 ? '鍘熸潗鏂�' : item.modelType === 1 ? '鍗婃垚鍝�' : '鎴愬搧',
+ passRate: item.passRate ? Number(item.passRate).toFixed(1) : 0,
+ momChange: item.momChange || 0,
+ yoyChange: item.yoyChange || 0,
+ momTrend: item.momTrend || 0,
+ yoyTrend: item.yoyTrend || 0,
+ totalCount: item.totalCount || 0,
+ completedCount: item.completedCount || 0,
+ qualifiedCount: item.qualifiedCount || 0,
+ lastMonthPassRate: item.lastMonthPassRate ? Number(item.lastMonthPassRate).toFixed(1) : 0,
+ lastYearPassRate: item.lastYearPassRate ? Number(item.lastYearPassRate).toFixed(1) : 0
+ }));
+ }
+ } catch (error) {
+ console.error("Failed to fetch mom data:", error);
+ }
+};
const inspectStatisticsData = ref([]);
const passRateStatisticsData = ref([]);
@@ -422,10 +622,16 @@
fetchMonthlyPassRateData();
fetchYearlyPassRateData();
fetchMonthlyCompletionDetailsData();
+ fetchMomData();
});
watch(activeTab, () => {
fetchTopParametersData();
+});
+
+// 鐩戝惉鏈堜唤閫夋嫨鍣ㄥ彉鍖�
+watch(momSelectedMonth, () => {
+ fetchMomData();
});
@@ -884,6 +1090,7 @@
fetchYearlyPassRateData();
fetchMonthlyCompletionDetailsData();
fetchTopParametersData();
+ fetchMomData();
nextTick(() => {
initSampleChart();
initEquipmentChart();
@@ -1468,4 +1675,248 @@
:deep(.el-input__prefix) {
display: none !important;
}
+
+/* 鐜瘮鎸囨爣鍗$墖鏍峰紡 */
+.mom-cards {
+ margin-bottom: 20px;
+ padding: 0 10px;
+}
+
+/* 鏈堜唤閫夋嫨鍣ㄦ牱寮� */
+.mom-month-selector {
+ display: flex;
+ align-items: center;
+ margin-bottom: 16px;
+ padding: 12px 16px;
+ background: #f5f7fa;
+ border-radius: 8px;
+}
+
+.mom-month-label {
+ font-size: 14px;
+ color: #606266;
+ margin-right: 12px;
+ font-weight: 500;
+}
+
+/* 涓籘ab鏍峰紡 */
+.mom-main-tabs {
+ display: flex;
+ gap: 12px;
+ margin-bottom: 16px;
+}
+
+.mom-tab-item {
+ display: flex;
+ align-items: center;
+ padding: 10px 20px;
+ background: #f5f7fa;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 14px;
+ color: #606266;
+ transition: all 0.3s;
+}
+
+.mom-tab-item:hover {
+ background: #e6f0ff;
+}
+
+.mom-tab-item.active {
+ background: linear-gradient(135deg, #165DFF 0%, #409EFF 100%);
+ color: #fff;
+}
+
+/* 瀛怲ab鏍峰紡 */
+.mom-sub-tabs {
+ display: flex;
+ gap: 8px;
+ margin-bottom: 20px;
+ border-bottom: 1px solid #e8e8e8;
+ padding-bottom: 12px;
+}
+
+.mom-sub-tab-item {
+ padding: 8px 16px;
+ font-size: 13px;
+ color: #909399;
+ cursor: pointer;
+ border-radius: 4px;
+ transition: all 0.3s;
+}
+
+.mom-sub-tab-item:hover {
+ color: #165DFF;
+ background: #f0f5ff;
+}
+
+.mom-sub-tab-item.active {
+ color: #165DFF;
+ font-weight: 500;
+ background: #e6f0ff;
+}
+
+/* 鏁版嵁闈㈡澘鏍峰紡 */
+.mom-data-panel {
+ background: #fafbfc;
+ border-radius: 12px;
+ padding: 24px;
+ min-height: 120px;
+}
+
+.mom-data-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.mom-data-value {
+ font-size: 48px;
+ font-weight: 600;
+ color: #165DFF;
+ margin-bottom: 20px;
+}
+
+.mom-data-detail {
+ display: flex;
+ gap: 40px;
+}
+
+.mom-detail-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.mom-detail-label {
+ font-size: 12px;
+ color: #909399;
+ margin-bottom: 4px;
+}
+
+.mom-detail-value {
+ font-size: 18px;
+ font-weight: 500;
+ color: #303133;
+}
+
+/* 瀵规瘮鏁版嵁鏍峰紡 */
+.mom-data-header {
+ display: flex;
+ align-items: center;
+ gap: 30px;
+ margin-bottom: 20px;
+}
+
+.mom-compare-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.mom-compare-label {
+ font-size: 12px;
+ color: #909399;
+ margin-bottom: 8px;
+}
+
+.mom-compare-value {
+ font-size: 28px;
+ font-weight: 500;
+ color: #606266;
+}
+
+.mom-compare-value.primary {
+ color: #165DFF;
+}
+
+.mom-compare-arrow {
+ font-size: 32px;
+ font-weight: 600;
+}
+
+.mom-data-change {
+ font-size: 24px;
+ font-weight: 500;
+ margin-bottom: 12px;
+}
+
+.mom-data-desc {
+ font-size: 14px;
+ color: #909399;
+}
+
+.mom-card {
+ background: #fff;
+ border-radius: 8px;
+ padding: 16px;
+ border: 1px solid #e8e8e8;
+}
+
+.mom-card-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 12px;
+}
+
+.mom-card-icon {
+ width: 32px;
+ height: 32px;
+ border-radius: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 10px;
+}
+
+.mom-card-icon img {
+ width: 20px;
+ height: 20px;
+}
+
+.mom-card-title {
+ font-size: 14px;
+ color: #333;
+ font-weight: 500;
+}
+
+.mom-card-rate {
+ font-size: 32px;
+ font-weight: 600;
+ color: #165DFF;
+ margin-bottom: 12px;
+}
+
+.mom-card-changes {
+ display: flex;
+ gap: 20px;
+}
+
+.mom-change-item {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.mom-change-label {
+ font-size: 12px;
+ color: #909399;
+}
+
+.mom-change-value {
+ font-size: 13px;
+ font-weight: 500;
+}
+
+.trend-up {
+ color: #52c41a;
+}
+
+.trend-down {
+ color: #f5222d;
+}
+
+.trend-flat {
+ color: #909399;
+}
</style>
--
Gitblit v1.9.3