|
|
|
|
@ -0,0 +1,234 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div class="p-4">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<el-form :model="queryParams" :inline="true">
|
|
|
|
|
<el-form-item label="选择周">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="selectedWeek"
|
|
|
|
|
type="week"
|
|
|
|
|
format="YYYY 第 ww 周"
|
|
|
|
|
placeholder="选择周"
|
|
|
|
|
@change="handleDateChange"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
<el-card class="mt-4" shadow="never" v-loading="loading">
|
|
|
|
|
<template #header>
|
|
|
|
|
<div class="text-center text-xl font-bold">每周生产测试不良数据分析图表</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 动态数据表格 -->
|
|
|
|
|
<el-table :data="tableData" border style="width: 100%" :row-style="{ height: '50px' }">
|
|
|
|
|
<el-table-column prop="metric" label="数据" min-width="180" />
|
|
|
|
|
<el-table-column
|
|
|
|
|
v-for="col in dateColumns"
|
|
|
|
|
:key="col.prop"
|
|
|
|
|
:prop="col.prop"
|
|
|
|
|
align="center"
|
|
|
|
|
min-width="100"
|
|
|
|
|
>
|
|
|
|
|
<template #header>
|
|
|
|
|
<div>{{ col.date }}</div>
|
|
|
|
|
<div>{{ col.dayOfWeek }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<span v-if="scope.row.metric.includes('不良率')">{{ formatValue(scope.row[col.prop]) }}%</span>
|
|
|
|
|
<span v-else>{{ formatValue(scope.row[col.prop]) }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="total" label="汇总" align="center" min-width="100">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<span v-if="scope.row.metric.includes('不良率')">{{ formatValue(scope.row.total) }}%</span>
|
|
|
|
|
<span v-else>{{ formatValue(scope.row.total) }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
<!-- ECharts 图表容器 -->
|
|
|
|
|
<div ref="chartRef" style="width: 100%; height: 400px;" class="mt-4"></div>
|
|
|
|
|
</el-card>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
import 'dayjs/locale/zh-cn';
|
|
|
|
|
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
|
|
|
|
import { getDefectAnalysisReport } from '@/api/qms/report';
|
|
|
|
|
|
|
|
|
|
// --- 初始化 dayjs 配置 ---
|
|
|
|
|
dayjs.extend(weekOfYear);
|
|
|
|
|
dayjs.locale('zh-cn');
|
|
|
|
|
|
|
|
|
|
// --- ECharts 实例 ---
|
|
|
|
|
const chartRef = ref<HTMLElement | null>(null);
|
|
|
|
|
let chartInstance: echarts.ECharts | null = null;
|
|
|
|
|
|
|
|
|
|
// --- Vue 响应式状态定义 ---
|
|
|
|
|
const loading = ref(false); // 控制加载状态
|
|
|
|
|
const selectedWeek = ref(new Date()); // 默认选择当前周
|
|
|
|
|
const queryParams = ref({ // API 查询参数
|
|
|
|
|
startTime: '',
|
|
|
|
|
endTime: ''
|
|
|
|
|
});
|
|
|
|
|
const reportData = ref<any>(null); // 存储从API获取的原始报告数据
|
|
|
|
|
const tableData = ref<any[]>([]); // 存储为表格转换后的数据
|
|
|
|
|
const dateColumns = ref<any[]>([]); // 存储动态生成的表格列
|
|
|
|
|
|
|
|
|
|
// --- ECharts 初始化 ---
|
|
|
|
|
const initChart = () => {
|
|
|
|
|
if (chartRef.value) {
|
|
|
|
|
chartInstance = echarts.init(chartRef.value);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- 数据获取与处理 ---
|
|
|
|
|
const handleQuery = async () => {
|
|
|
|
|
// 确保有合法的日期范围
|
|
|
|
|
if (!queryParams.value.startTime || !queryParams.value.endTime) {
|
|
|
|
|
handleDateChange(new Date()); // 如果没有,则使用当前日期初始化
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
try {
|
|
|
|
|
// 调用后端接口获取报告数据
|
|
|
|
|
const res = await getDefectAnalysisReport(queryParams.value);
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
reportData.value = res.data;
|
|
|
|
|
// 将API数据转换为表格和图表需要的格式
|
|
|
|
|
transformDataForTable();
|
|
|
|
|
updateChart();
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("获取报告数据失败:", error);
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- 核心逻辑:数据转换为表格格式 ---
|
|
|
|
|
const transformDataForTable = () => {
|
|
|
|
|
if (!reportData.value) {
|
|
|
|
|
tableData.value = [];
|
|
|
|
|
dateColumns.value = [];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { tableData: apiTableData, dateColumns: apiDateColumns } = reportData.value;
|
|
|
|
|
|
|
|
|
|
tableData.value = apiTableData || [];
|
|
|
|
|
dateColumns.value = apiDateColumns || [];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- 更新 ECharts 图表 ---
|
|
|
|
|
const updateChart = () => {
|
|
|
|
|
if (!chartInstance || !reportData.value || !reportData.value.chartData) return;
|
|
|
|
|
|
|
|
|
|
const { chartData } = reportData.value;
|
|
|
|
|
|
|
|
|
|
// 配置 ECharts 的 option
|
|
|
|
|
const option = {
|
|
|
|
|
tooltip: {
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
axisPointer: {
|
|
|
|
|
type: 'cross',
|
|
|
|
|
crossStyle: { color: '#999' }
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
legend: {
|
|
|
|
|
data: ['检验数量', '不良数量', '不良率']
|
|
|
|
|
},
|
|
|
|
|
xAxis: [
|
|
|
|
|
{
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: chartData.dates,
|
|
|
|
|
axisPointer: { type: 'shadow' }
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
yAxis: [
|
|
|
|
|
{
|
|
|
|
|
type: 'value',
|
|
|
|
|
name: '数量 (个)',
|
|
|
|
|
min: 0,
|
|
|
|
|
axisLabel: { formatter: '{value}' }
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: 'value',
|
|
|
|
|
name: '不良率 (%)',
|
|
|
|
|
min: 0,
|
|
|
|
|
axisLabel: { formatter: '{value} %' }
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: '检验数量',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
tooltip: { valueFormatter: (value: number) => value + ' 个' },
|
|
|
|
|
data: chartData.inspectionData
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '不良数量',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
tooltip: { valueFormatter: (value: number) => value + ' 个' },
|
|
|
|
|
data: chartData.defectData
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '不良率',
|
|
|
|
|
type: 'line',
|
|
|
|
|
yAxisIndex: 1, // 关联到第二个 y 轴
|
|
|
|
|
tooltip: { valueFormatter: (value: number) => value + ' %' },
|
|
|
|
|
data: chartData.defectRateData
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
chartInstance.setOption(option);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- 格式化数值显示 ---
|
|
|
|
|
const formatValue = (value: any) => {
|
|
|
|
|
if (value === null || value === undefined) return '0';
|
|
|
|
|
if (typeof value === 'number') {
|
|
|
|
|
return value.toLocaleString();
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- 事件处理 ---
|
|
|
|
|
const handleDateChange = (date: Date) => {
|
|
|
|
|
// 根据选择的日期计算该周的开始和结束日期
|
|
|
|
|
const startOfWeek = dayjs(date).startOf('week');
|
|
|
|
|
const endOfWeek = dayjs(date).endOf('week');
|
|
|
|
|
queryParams.value.startTime = startOfWeek.format('YYYY-MM-DD');
|
|
|
|
|
queryParams.value.endTime = endOfWeek.format('YYYY-MM-DD');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// --- Vue 生命周期钩子 ---
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
// 1. 初始化图表实例
|
|
|
|
|
initChart();
|
|
|
|
|
// 2. 首次加载时,获取当前周的数据
|
|
|
|
|
handleDateChange(selectedWeek.value);
|
|
|
|
|
handleQuery();
|
|
|
|
|
// 3. 监听窗口大小变化,自适应重绘图表
|
|
|
|
|
window.addEventListener('resize', () => {
|
|
|
|
|
if (chartInstance) {
|
|
|
|
|
chartInstance.resize();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* 您可以在此添加自定义样式 */
|
|
|
|
|
.el-form-item {
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
</style>
|