|
@@ -16,10 +16,13 @@ const props = defineProps({
|
|
|
required: true,
|
|
|
},
|
|
|
});
|
|
|
+
|
|
|
const chartRef = ref(null);
|
|
|
+const chartData = ref([]);
|
|
|
let chartInstance = null;
|
|
|
let timer = null;
|
|
|
const currentIndex = ref(0);
|
|
|
+const isHovering = ref(false);
|
|
|
|
|
|
// 初始化图表
|
|
|
const initChart = () => {
|
|
@@ -28,38 +31,62 @@ const initChart = () => {
|
|
|
chartInstance = echarts.init(chartRef.value);
|
|
|
updateChart();
|
|
|
window.addEventListener("resize", handleResize);
|
|
|
+
|
|
|
+ // 获取图表DOM元素
|
|
|
+ const chartDom = chartRef.value;
|
|
|
+
|
|
|
+ // 直接在DOM元素上添加事件监听
|
|
|
+ chartDom.addEventListener("mouseenter", () => {
|
|
|
+ isHovering.value = true;
|
|
|
+ pauseAutoPlay();
|
|
|
+ });
|
|
|
+
|
|
|
+ chartDom.addEventListener("mouseleave", () => {
|
|
|
+ isHovering.value = false;
|
|
|
+ startAutoPlay();
|
|
|
+ });
|
|
|
+
|
|
|
+ // 初始定时器
|
|
|
+ startAutoPlay();
|
|
|
+};
|
|
|
+
|
|
|
+// 暂停自动播放
|
|
|
+const pauseAutoPlay = () => {
|
|
|
+ if (timer) {
|
|
|
+ clearInterval(timer);
|
|
|
+ timer = null;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 开始自动播放
|
|
|
+const startAutoPlay = () => {
|
|
|
+ if (!isHovering.value && !timer && chartData.value.length > 1) {
|
|
|
+ timer = setInterval(nextChart, 5000);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 数据转换函数
|
|
|
const transformData = (rawData) => {
|
|
|
return rawData.map((item) => {
|
|
|
- // 处理工序名称列表
|
|
|
const operationNames = item.operationNameList.filter(
|
|
|
(name) => name !== "成品率"
|
|
|
);
|
|
|
-
|
|
|
- // 处理工序数值列表 - 每3个一组:[目标值, 实际值, 差值]
|
|
|
const operationNumbers = item.operationNumberList;
|
|
|
const targetValues = [];
|
|
|
const actualValues = [];
|
|
|
|
|
|
for (let i = 0; i < operationNumbers.length; i += 3) {
|
|
|
- // 跳过成品率数据(通常是最后3个)
|
|
|
if (i / 3 >= operationNames.length) break;
|
|
|
-
|
|
|
targetValues.push(parseFloat(operationNumbers[i]));
|
|
|
actualValues.push(parseFloat(operationNumbers[i + 1]));
|
|
|
}
|
|
|
|
|
|
- // 获取成品率数据(最后3个值)
|
|
|
const yieldIndex = operationNumbers.length - 3;
|
|
|
const productTarget = parseFloat(operationNumbers[yieldIndex]);
|
|
|
const productActual = parseFloat(operationNumbers[yieldIndex + 1]);
|
|
|
|
|
|
return {
|
|
|
- title:
|
|
|
- `${item.materialModel}工序成品率对比` +
|
|
|
- (item.materialCategory ? `(${item.materialCategory})` : ""),
|
|
|
+ title: `${item.materialModel}工序成品率对比${item.materialCategory ? `(${item.materialCategory})` : ""}`,
|
|
|
xAxis: operationNames,
|
|
|
productTarget: productTarget,
|
|
|
productActual: productActual,
|
|
@@ -90,8 +117,6 @@ const updateChart = () => {
|
|
|
if (!chartInstance || !chartData.value.length) return;
|
|
|
|
|
|
const currentData = chartData.value[currentIndex.value];
|
|
|
-
|
|
|
- // 计算工序差值
|
|
|
const processDiff = currentData.series[0].data.map((target, index) => {
|
|
|
const diff = currentData.series[1].data[index] - target;
|
|
|
return parseFloat(diff.toFixed(1));
|
|
@@ -127,7 +152,6 @@ const updateChart = () => {
|
|
|
|
|
|
let result = `<div style="font-weight:bold;margin-bottom:5px">${params[0].axisValue}</div>`;
|
|
|
|
|
|
- // 工序数据
|
|
|
result += `
|
|
|
<div style="display:flex;align-items:center;margin:3px 0">
|
|
|
<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#5470C6;margin-right:5px"></span>
|
|
@@ -145,7 +169,6 @@ const updateChart = () => {
|
|
|
<span style="font-weight:bold;color:${diffColor}">${diffSymbol}${diffValue}%</span>
|
|
|
</div>`;
|
|
|
|
|
|
- // 产品数据
|
|
|
result += `
|
|
|
<div style="border-top:1px solid rgba(255,255,255,0.2);margin:5px 0"></div>
|
|
|
<div style="display:flex;align-items:center;margin:3px 0">
|
|
@@ -176,7 +199,7 @@ const updateChart = () => {
|
|
|
grid: {
|
|
|
top: "10%",
|
|
|
right: "12%",
|
|
|
- bottom: "15%", // 增加底部空间
|
|
|
+ bottom: "15%",
|
|
|
left: "8%",
|
|
|
},
|
|
|
xAxis: {
|
|
@@ -219,7 +242,6 @@ const updateChart = () => {
|
|
|
},
|
|
|
},
|
|
|
series: [
|
|
|
- // 工序目标值(实线)
|
|
|
{
|
|
|
...currentData.series[0],
|
|
|
lineStyle: {
|
|
@@ -241,15 +263,8 @@ const updateChart = () => {
|
|
|
return `${params.value}% (${diffSymbol}${diff}%)`;
|
|
|
},
|
|
|
color: "#fff",
|
|
|
- rich: {
|
|
|
- diff: {
|
|
|
- color: "#EE6666",
|
|
|
- padding: [0, 0, 0, 5],
|
|
|
- },
|
|
|
- },
|
|
|
},
|
|
|
},
|
|
|
- // 工序实际值(实线)
|
|
|
{
|
|
|
...currentData.series[1],
|
|
|
lineStyle: {
|
|
@@ -262,10 +277,9 @@ const updateChart = () => {
|
|
|
borderWidth: 1,
|
|
|
},
|
|
|
label: {
|
|
|
- show: false, // 只在目标值上显示标签
|
|
|
+ show: false,
|
|
|
},
|
|
|
},
|
|
|
- // 产品目标值横线(虚线)
|
|
|
{
|
|
|
name: "产品目标值",
|
|
|
type: "line",
|
|
@@ -297,7 +311,6 @@ const updateChart = () => {
|
|
|
],
|
|
|
},
|
|
|
},
|
|
|
- // 产品实际值横线(虚线)
|
|
|
{
|
|
|
name: "产品实际值",
|
|
|
type: "line",
|
|
@@ -337,48 +350,51 @@ const updateChart = () => {
|
|
|
};
|
|
|
|
|
|
const nextChart = () => {
|
|
|
- currentIndex.value = (currentIndex.value + 1) % chartData.value.length;
|
|
|
- updateChart();
|
|
|
- resetTimer();
|
|
|
-};
|
|
|
-
|
|
|
-const resetTimer = () => {
|
|
|
- if (timer) clearInterval(timer);
|
|
|
- startTimer();
|
|
|
-};
|
|
|
-
|
|
|
-const startTimer = () => {
|
|
|
- timer = setInterval(nextChart, 5000);
|
|
|
+ if (chartData.value.length > 0) {
|
|
|
+ currentIndex.value = (currentIndex.value + 1) % chartData.value.length;
|
|
|
+ updateChart();
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const handleResize = () => {
|
|
|
chartInstance?.resize();
|
|
|
};
|
|
|
|
|
|
-const chartData = ref([]);
|
|
|
-
|
|
|
const loadData = async () => {
|
|
|
- const rowData = await qualityReport();
|
|
|
- chartData.value = transformData(rowData.data);
|
|
|
+ try {
|
|
|
+ const rowData = await qualityReport();
|
|
|
+ chartData.value = transformData(rowData.data);
|
|
|
+ if (chartData.value.length > 0) {
|
|
|
+ updateChart();
|
|
|
+ startAutoPlay();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("加载数据失败:", error);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
|
- loadData();
|
|
|
initChart();
|
|
|
- startTimer();
|
|
|
+ loadData();
|
|
|
});
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
if (chartInstance) {
|
|
|
+ // 移除DOM事件监听
|
|
|
+ const chartDom = chartRef.value;
|
|
|
+ if (chartDom) {
|
|
|
+ chartDom.removeEventListener("mouseenter");
|
|
|
+ chartDom.removeEventListener("mouseleave");
|
|
|
+ }
|
|
|
+
|
|
|
chartInstance.dispose();
|
|
|
window.removeEventListener("resize", handleResize);
|
|
|
}
|
|
|
- if (timer) clearInterval(timer);
|
|
|
+ pauseAutoPlay();
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-/* 样式保持不变 */
|
|
|
.sliding-chart-container {
|
|
|
width: 100%;
|
|
|
height: 100%;
|