buhuazhen
2026-06-01 9d94bacb1e7decb49a4a6d3de171355867f7fde7
fix:质检合格率 添加同比环比
已修改2个文件
474 ■■■■■ 文件已修改
src/api/reportAnalysis/qualityReport.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/reportManagement/index.vue 465 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 }
  })
}
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年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">
@@ -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'); // 主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([]);
@@ -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;
}
/* 主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>