| | |
| | | <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> |
| | |
| | | </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> |
| | |
| | | </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> |
| | |
| | | <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> |
| | |
| | | </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> |
| | |
| | | </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> |
| | |
| | | <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年MM月" |
| | | value-format="YYYY-MM" |
| | | :clearable="false" |
| | | :disabled-date="disabledMonthDate" |
| | | style="width: 150px;" |
| | | /> |
| | | </div> |
| | | |
| | | <!-- 主Tab:类别切换 --> |
| | | <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> |
| | | |
| | | <!-- 子Tab:指标切换 --> |
| | | <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"> |
| | |
| | | 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'); // 主Tab: raw, semi, final |
| | | const momSubTab = ref('current'); // 子Tab: 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 { |
| | | // 从选中的月份中解析年份和月份 |
| | | 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([]); |
| | |
| | | fetchMonthlyPassRateData(); |
| | | fetchYearlyPassRateData(); |
| | | fetchMonthlyCompletionDetailsData(); |
| | | fetchMomData(); |
| | | }); |
| | | |
| | | watch(activeTab, () => { |
| | | fetchTopParametersData(); |
| | | }); |
| | | |
| | | // 监听月份选择器变化 |
| | | watch(momSelectedMonth, () => { |
| | | fetchMomData(); |
| | | }); |
| | | |
| | | |
| | |
| | | fetchYearlyPassRateData(); |
| | | fetchMonthlyCompletionDetailsData(); |
| | | fetchTopParametersData(); |
| | | fetchMomData(); |
| | | nextTick(() => { |
| | | initSampleChart(); |
| | | initEquipmentChart(); |
| | |
| | | :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; |
| | | } |
| | | |
| | | /* 主Tab样式 */ |
| | | .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; |
| | | } |
| | | |
| | | /* 子Tab样式 */ |
| | | .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> |