|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="backward2-container">
|
|
|
|
|
|
<el-card class="tree-card" shadow="never" v-loading="loading">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<span class="header-title">追溯结构</span>
|
|
|
|
|
|
<el-button type="primary" link icon="ArrowLeft" @click="goBack">返回列表</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-tree
|
|
|
|
|
|
ref="treeRef"
|
|
|
|
|
|
:data="treeData"
|
|
|
|
|
|
:props="treeProps"
|
|
|
|
|
|
node-key="id"
|
|
|
|
|
|
default-expand-all
|
|
|
|
|
|
:expand-on-click-node="false"
|
|
|
|
|
|
highlight-current
|
|
|
|
|
|
@node-click="handleNodeClick"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #default="{ node, data }">
|
|
|
|
|
|
<span class="custom-tree-node">
|
|
|
|
|
|
<el-icon v-if="!data.children"><Document /></el-icon>
|
|
|
|
|
|
<el-icon v-else><Folder /></el-icon>
|
|
|
|
|
|
<span class="label-text">{{ node.label }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-tree>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="content-area">
|
|
|
|
|
|
<div class="main-area">
|
|
|
|
|
|
<div class="top-section">
|
|
|
|
|
|
<el-card class="production-card" shadow="never" v-loading="loading">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="blue-header">
|
|
|
|
|
|
<span class="header-title">生产信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<el-descriptions v-if="barcodeType === '1'" :column="1" border size="small" class="production-desc">
|
|
|
|
|
|
<el-descriptions-item label="条码">{{ productionInfo.barcode }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="生产日期">{{ productionInfo.productionDate }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="机台">{{ productionInfo.machine }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="班次">{{ productionInfo.shift }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="班组">{{ productionInfo.team }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="物料名称">{{ productionInfo.materialName }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="车次">{{ productionInfo.trainNo }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="重量">{{ productionInfo.weight }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="操作人">{{ productionInfo.operator }}</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
|
|
<el-descriptions v-else-if="barcodeType === '2'" :column="1" border size="small" class="production-desc">
|
|
|
|
|
|
<el-descriptions-item label="流转卡号">{{ productionInfo.cardNo }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="接班编号">{{ productionInfo.shiftNo }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="架子号">{{ productionInfo.shelfNo }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="物料名称">{{ productionInfo.materialName }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="数量">{{ productionInfo.qty }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="单位">{{ productionInfo.unitName }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="宽度">{{ productionInfo.width }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="计划号">{{ productionInfo.orderNumber }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="重量">{{ productionInfo.weight }}</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
|
|
<el-descriptions v-else-if="barcodeType === '3'" :column="1" border size="small" class="production-desc">
|
|
|
|
|
|
<el-descriptions-item label="成型号">{{ productionInfo.greenTyreNo }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="成型时间">{{ productionInfo.beginTime }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="机台">{{ productionInfo.equipId }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="操作人">{{ productionInfo.operator }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="班次">{{ productionInfo.shift }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="班组">{{ productionInfo.team }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="物料名称">{{ productionInfo.materialName }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="重量">{{ productionInfo.weight }}</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
|
|
<el-descriptions v-else :column="1" border size="small" class="production-desc">
|
|
|
|
|
|
<el-descriptions-item label="条码">{{ productionInfo.barcode }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="生产日期">{{ productionInfo.productionDate }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="物料名称">{{ productionInfo.materialName }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="机台">{{ productionInfo.machine }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="班次">{{ productionInfo.shift }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="班组">{{ productionInfo.team }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="车次">{{ productionInfo.trainNo }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="设定重量">{{ productionInfo.setWeight }}</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="实际重量">{{ productionInfo.actualWeight }}</el-descriptions-item>
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<el-card class="quality-card" shadow="never" v-loading="loading">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="blue-header">
|
|
|
|
|
|
<span class="header-title">质检信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<div class="table-scroll">
|
|
|
|
|
|
<el-table :data="qualityData" border stripe size="small" :fit="false" :scrollbar-always-on="true" height="240">
|
|
|
|
|
|
<el-table-column prop="reportNo" label="报告单号" min-width="130" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="times" label="检验次数" min-width="90" align="center" />
|
|
|
|
|
|
<el-table-column prop="item" label="检验项目" min-width="140" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="standard" label="标准" min-width="130" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="value" label="检验值" min-width="100" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="deviation" label="偏差" min-width="90" align="center" />
|
|
|
|
|
|
<el-table-column prop="result" label="结果" min-width="90" align="center" />
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-card v-if="selectedNodeLevel <= 2" class="weighing-card" shadow="never" v-loading="loading">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="blue-header">
|
|
|
|
|
|
<span class="header-title">称量信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<div class="table-scroll">
|
|
|
|
|
|
<el-table :data="weighingData" border stripe size="small" :fit="false" :scrollbar-always-on="true" height="240">
|
|
|
|
|
|
<el-table-column prop="carBarcode" label="车条码" min-width="180" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="order" label="称量次序" min-width="90" align="center" />
|
|
|
|
|
|
<el-table-column label="物料编码" min-width="170" align="center" show-overflow-tooltip>
|
|
|
|
|
|
<template #default="{ row }">{{ row.materialName || row.materialCode || '-' }}</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="machine" label="机台" min-width="100" align="center" />
|
|
|
|
|
|
<el-table-column prop="setWeight" label="设定重量" min-width="100" align="right" />
|
|
|
|
|
|
<el-table-column prop="actualWeight" label="实际重量" min-width="100" align="right" />
|
|
|
|
|
|
<el-table-column prop="tolerance" label="允许误差" min-width="100" align="center" />
|
|
|
|
|
|
<el-table-column prop="actualDeviation" label="实际误差" min-width="100" align="center" />
|
|
|
|
|
|
<el-table-column prop="weighTime" label="称量时间" min-width="170" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="trainNo" label="车次" min-width="90" align="center" />
|
|
|
|
|
|
<el-table-column prop="planDate" label="计划日期" min-width="120" align="center" />
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<el-card v-if="selectedNodeLevel <= 2" class="mixing-card" shadow="never" v-loading="loading">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="blue-header">
|
|
|
|
|
|
<span class="header-title">混炼信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<div class="table-scroll">
|
|
|
|
|
|
<el-table :data="mixingProcessData" border stripe size="small" :fit="false" :scrollbar-always-on="true" height="240">
|
|
|
|
|
|
<el-table-column prop="carBarcode" label="车条码" min-width="180" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="step" label="混炼步骤" min-width="90" align="center" />
|
|
|
|
|
|
<el-table-column prop="condition" label="条件" min-width="120" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="duration" label="时间" min-width="90" align="center" />
|
|
|
|
|
|
<el-table-column prop="temperature" label="温度(℃)" min-width="100" align="right" />
|
|
|
|
|
|
<el-table-column prop="energy" label="能量" min-width="90" align="right" />
|
|
|
|
|
|
<el-table-column prop="power" label="功率" min-width="90" align="right" />
|
|
|
|
|
|
<el-table-column prop="pressure" label="压力" min-width="90" align="right" />
|
|
|
|
|
|
<el-table-column prop="rpm" label="转速" min-width="90" align="right" />
|
|
|
|
|
|
<el-table-column prop="action" label="动作" min-width="120" align="center" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column prop="recordTime" label="保存时间" min-width="180" align="center" show-overflow-tooltip />
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="curve-area" :class="{ collapsed: curveCollapsed }">
|
|
|
|
|
|
<div class="curve-toggle" @click="toggleCurve">
|
|
|
|
|
|
<span class="toggle-text">曲线信息</span>
|
|
|
|
|
|
<el-icon class="toggle-icon" :class="{ rotated: !curveCollapsed }"><ArrowRight /></el-icon>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-card class="curve-card" shadow="never" v-show="!curveCollapsed">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="blue-header">
|
|
|
|
|
|
<span class="header-title">曲线信息</span>
|
|
|
|
|
|
<div class="legend-group">
|
|
|
|
|
|
<span class="legend-item"><i class="legend-dot" style="background: #ff4d4f"></i>温度</span>
|
|
|
|
|
|
<span class="legend-item"><i class="legend-dot" style="background: #40a9ff"></i>功率</span>
|
|
|
|
|
|
<span class="legend-item"><i class="legend-dot" style="background: #36cfc9"></i>能量</span>
|
|
|
|
|
|
<span class="legend-item"><i class="legend-dot" style="background: #95de64"></i>压力</span>
|
|
|
|
|
|
<span class="legend-item"><i class="legend-dot" style="background: #f7d13d"></i>转速</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-button size="small" text type="primary" style="color: #fff" @click="toggleCurve">收起</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<div ref="chartRef" class="chart-container"></div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts" name="MixTraceBackward2">
|
|
|
|
|
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
|
|
import { ArrowRight, Document, Folder } from '@element-plus/icons-vue';
|
|
|
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
|
import backwardData from './data/backward2.json';
|
|
|
|
|
|
import curveDataJson from './data/混炼曲线数据.json';
|
|
|
|
|
|
|
|
|
|
|
|
type BarcodeType = '1' | '2' | '3' | '4';
|
|
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const detailMap = (backwardData as any).detailMap || {};
|
|
|
|
|
|
const detailKeys = Object.keys(detailMap);
|
|
|
|
|
|
|
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
|
const detailId = ref<string>('');
|
|
|
|
|
|
const barcodeType = ref<BarcodeType>('4');
|
|
|
|
|
|
const treeData = ref<any[]>([]);
|
|
|
|
|
|
const qualityData = ref<any[]>([]);
|
|
|
|
|
|
const weighingData = ref<any[]>([]);
|
|
|
|
|
|
const mixingProcessData = ref<any[]>([]);
|
|
|
|
|
|
const curveCollapsed = ref(true);
|
|
|
|
|
|
/** 当前选中节点的树层级,1-2级显示全部,3级+只显示生产和质检 */
|
|
|
|
|
|
const selectedNodeLevel = ref<number>(1);
|
|
|
|
|
|
|
|
|
|
|
|
const treeProps = { children: 'children', label: 'label' };
|
|
|
|
|
|
const treeRef = ref();
|
|
|
|
|
|
const chartRef = ref<HTMLDivElement>();
|
|
|
|
|
|
let chartInstance: echarts.ECharts | null = null;
|
|
|
|
|
|
|
|
|
|
|
|
const goBack = () => {
|
|
|
|
|
|
if (window.history.length > 1) {
|
|
|
|
|
|
router.back();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
router.push('/mes/mixTrace/show/backward1');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const productionInfo = computed(() => {
|
|
|
|
|
|
return detailMap[detailId.value]?.production || {};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 演示模式固定使用假数据条码 QUXIAN_DEMO_001
|
|
|
|
|
|
const curveDataSource = computed(() => (curveDataJson as any)['QUXIAN_DEMO_001'] || {});
|
|
|
|
|
|
|
|
|
|
|
|
const resolveDetailId = (routeId: string, routeType: string): string => {
|
|
|
|
|
|
if (routeId && detailMap[routeId]) return routeId;
|
|
|
|
|
|
if (routeType) {
|
|
|
|
|
|
const match = detailKeys.find((key) => String(detailMap[key]?.barcodeType) === routeType);
|
|
|
|
|
|
if (match) return match;
|
|
|
|
|
|
}
|
|
|
|
|
|
return detailKeys[0] || '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const syncByRoute = () => {
|
|
|
|
|
|
const routeId = String(route.query.id || '');
|
|
|
|
|
|
const routeType = String(route.query.barcodeType || '');
|
|
|
|
|
|
const resolved = resolveDetailId(routeId, routeType);
|
|
|
|
|
|
if (!resolved) return;
|
|
|
|
|
|
|
|
|
|
|
|
detailId.value = resolved;
|
|
|
|
|
|
barcodeType.value = String(detailMap[resolved]?.barcodeType || routeType || '4') as BarcodeType;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const loadData = () => {
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
|
syncByRoute();
|
|
|
|
|
|
|
|
|
|
|
|
const detail = detailMap[detailId.value] || {};
|
|
|
|
|
|
treeData.value = detail.treeData || [];
|
|
|
|
|
|
qualityData.value = detail.qualityData || [];
|
|
|
|
|
|
weighingData.value = detail.weighingData || [];
|
|
|
|
|
|
mixingProcessData.value = detail.mixingProcessData || [];
|
|
|
|
|
|
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
const defaultKey = treeData.value?.[0]?.id;
|
|
|
|
|
|
if (defaultKey && treeRef.value) {
|
|
|
|
|
|
treeRef.value.setCurrentKey(defaultKey);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const initChart = () => {
|
|
|
|
|
|
if (!chartRef.value) return;
|
|
|
|
|
|
const cd = curveDataSource.value;
|
|
|
|
|
|
|
|
|
|
|
|
const toNumberOrNull = (value: any): number | null => {
|
|
|
|
|
|
const num = Number(value);
|
|
|
|
|
|
return Number.isFinite(num) ? num : null;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let xAxisData: Array<string | number> = [];
|
|
|
|
|
|
let temperatureData: Array<number | null> = [];
|
|
|
|
|
|
let powerData: Array<number | null> = [];
|
|
|
|
|
|
let energyData: Array<number | null> = [];
|
|
|
|
|
|
let pressureData: Array<number | null> = [];
|
|
|
|
|
|
let speedData: Array<number | null> = [];
|
|
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(cd.time) && cd.time.length > 0) {
|
|
|
|
|
|
xAxisData = cd.time.map((v: any) => {
|
|
|
|
|
|
const num = Number(v);
|
|
|
|
|
|
return Number.isFinite(num) ? num : 0;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const buildSeriesData = (source: any): Array<number | null> => {
|
|
|
|
|
|
const arr = Array.isArray(source) ? source : [];
|
|
|
|
|
|
return arr.map((v: any) => toNumberOrNull(v));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
temperatureData = buildSeriesData(cd.MixingTemp);
|
|
|
|
|
|
powerData = buildSeriesData(cd.MixingPower);
|
|
|
|
|
|
energyData = buildSeriesData(cd.MixingEnergy);
|
|
|
|
|
|
pressureData = buildSeriesData(cd.MixingPress);
|
|
|
|
|
|
speedData = buildSeriesData(cd.MixingSpeed);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const calcRange = (arr: Array<number | null>) => {
|
|
|
|
|
|
const nums = arr.filter((n): n is number => typeof n === 'number');
|
|
|
|
|
|
if (!nums.length) return {};
|
|
|
|
|
|
const min = Math.min(...nums);
|
|
|
|
|
|
const max = Math.max(...nums);
|
|
|
|
|
|
const pad = min === max ? Math.max(Math.abs(min) * 0.1, 1) : (max - min) * 0.1;
|
|
|
|
|
|
return {
|
|
|
|
|
|
min: Number((min - pad).toFixed(2)),
|
|
|
|
|
|
max: Number((max + pad).toFixed(2))
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const leftAxisRange = calcRange([...temperatureData, ...energyData, ...pressureData, ...speedData]);
|
|
|
|
|
|
const rightAxisRange = calcRange(powerData);
|
|
|
|
|
|
|
|
|
|
|
|
if (chartInstance) {
|
|
|
|
|
|
chartInstance.dispose();
|
|
|
|
|
|
chartInstance = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
chartInstance = echarts.init(chartRef.value);
|
|
|
|
|
|
|
|
|
|
|
|
if (xAxisData.length === 0) {
|
|
|
|
|
|
chartInstance.setOption({
|
|
|
|
|
|
graphic: {
|
|
|
|
|
|
type: 'text',
|
|
|
|
|
|
left: 'center',
|
|
|
|
|
|
top: 'middle',
|
|
|
|
|
|
style: { text: '暂无曲线数据', fill: '#909399', fontSize: 14 }
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
chartInstance.setOption({
|
|
|
|
|
|
animation: false,
|
|
|
|
|
|
grid: { left: '5%', right: '5%', top: '10%', bottom: '10%', containLabel: true },
|
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
data: xAxisData,
|
|
|
|
|
|
boundaryGap: false,
|
|
|
|
|
|
name: '时间(s)'
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: [
|
|
|
|
|
|
{ type: 'value', name: '温度/能量/压力/转速', position: 'left', axisLine: { show: true }, ...leftAxisRange },
|
|
|
|
|
|
{ type: 'value', name: '功率(kW)', position: 'right', axisLine: { show: true }, ...rightAxisRange }
|
|
|
|
|
|
],
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{ name: '温度', type: 'line', yAxisIndex: 0, data: temperatureData, smooth: true, connectNulls: false, showSymbol: false, itemStyle: { color: '#ff4d4f' } },
|
|
|
|
|
|
{ name: '功率', type: 'line', yAxisIndex: 1, data: powerData, smooth: true, connectNulls: false, showSymbol: false, itemStyle: { color: '#40a9ff' } },
|
|
|
|
|
|
{ name: '能量', type: 'line', yAxisIndex: 0, data: energyData, smooth: true, connectNulls: false, showSymbol: false, itemStyle: { color: '#36cfc9' } },
|
|
|
|
|
|
{ name: '压力', type: 'line', yAxisIndex: 0, data: pressureData, smooth: true, connectNulls: false, showSymbol: false, itemStyle: { color: '#95de64' } },
|
|
|
|
|
|
{ name: '转速', type: 'line', yAxisIndex: 0, data: speedData, smooth: true, connectNulls: false, showSymbol: false, itemStyle: { color: '#f7d13d' } }
|
|
|
|
|
|
]
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const resizeChart = () => {
|
|
|
|
|
|
chartInstance?.resize();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const renderChartWithDelay = () => {
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
initChart();
|
|
|
|
|
|
resizeChart();
|
|
|
|
|
|
}, 320);
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toggleCurve = () => {
|
|
|
|
|
|
curveCollapsed.value = !curveCollapsed.value;
|
|
|
|
|
|
if (!curveCollapsed.value) {
|
|
|
|
|
|
renderChartWithDelay();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleNodeClick = (nodeData: any, node: any) => {
|
|
|
|
|
|
selectedNodeLevel.value = node?.level ?? 1;
|
|
|
|
|
|
if (nodeData?.detailId && detailMap[nodeData.detailId]) {
|
|
|
|
|
|
detailId.value = nodeData.detailId;
|
|
|
|
|
|
barcodeType.value = String(detailMap[detailId.value]?.barcodeType || '4') as BarcodeType;
|
|
|
|
|
|
loadData();
|
|
|
|
|
|
if (!curveCollapsed.value) {
|
|
|
|
|
|
renderChartWithDelay();
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
ElMessage.info(`当前节点: ${nodeData?.label || '-'}`);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => [route.query.id, route.query.barcodeType],
|
|
|
|
|
|
() => {
|
|
|
|
|
|
loadData();
|
|
|
|
|
|
if (!curveCollapsed.value) {
|
|
|
|
|
|
renderChartWithDelay();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
watch(detailId, () => {
|
|
|
|
|
|
if (!curveCollapsed.value) {
|
|
|
|
|
|
renderChartWithDelay();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
loadData();
|
|
|
|
|
|
window.addEventListener('resize', resizeChart);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
window.removeEventListener('resize', resizeChart);
|
|
|
|
|
|
if (chartInstance) {
|
|
|
|
|
|
chartInstance.dispose();
|
|
|
|
|
|
chartInstance = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.backward2-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
height: calc(100vh - 90px);
|
|
|
|
|
|
|
|
|
|
|
|
.tree-card {
|
|
|
|
|
|
width: 310px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-card__header) {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
background-color: #2f6ea5;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
padding: 12px 14px;
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-tree-node__content) {
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree-node {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
.label-text {
|
|
|
|
|
|
margin-left: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-area {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.main-area {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
|
|
|
|
|
|
> * {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.top-section {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
|
|
|
|
|
|
.production-card {
|
|
|
|
|
|
flex: 0 0 420px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.quality-card {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.table-scroll {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.blue-header {
|
|
|
|
|
|
background-color: #2f6ea5;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
padding: 10px 14px;
|
|
|
|
|
|
margin: -20px -20px 16px -20px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.production-desc {
|
|
|
|
|
|
:deep(.el-descriptions__label) {
|
|
|
|
|
|
width: 90px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
background: #fafafa;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.weighing-card .el-card__body),
|
|
|
|
|
|
:deep(.mixing-card .el-card__body),
|
|
|
|
|
|
:deep(.quality-card .el-card__body) {
|
|
|
|
|
|
overflow: visible;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.curve-area {
|
|
|
|
|
|
flex: 0 0 50%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
transition: flex-basis 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&.collapsed {
|
|
|
|
|
|
flex-basis: 30px;
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.curve-toggle {
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
background-color: #2f6ea5;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
.toggle-text {
|
|
|
|
|
|
writing-mode: vertical-rl;
|
|
|
|
|
|
letter-spacing: 3px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.toggle-icon {
|
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
|
transition: transform 0.3s ease;
|
|
|
|
|
|
&.rotated {
|
|
|
|
|
|
transform: rotate(180deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.curve-card {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
:deep(.el-card__header) {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
:deep(.el-card__body) {
|
|
|
|
|
|
height: calc(100% - 48px);
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.legend-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
flex-wrap: nowrap;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
.legend-item {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.legend-dot {
|
|
|
|
|
|
width: 8px;
|
|
|
|
|
|
height: 8px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
min-height: 300px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|