|
|
|
|
@ -1,33 +1,59 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div class="p-2">
|
|
|
|
|
<el-tabs v-model="activeTab" type="border-card">
|
|
|
|
|
<!-- ==================== Tab1: 追溯列表(图5) ==================== -->
|
|
|
|
|
<el-tab-pane label="配方追溯" name="trace">
|
|
|
|
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
|
|
|
|
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
|
|
|
<transition
|
|
|
|
|
:enter-active-class="proxy?.animate.searchAnimate.enter"
|
|
|
|
|
:leave-active-class="proxy?.animate.searchAnimate.leave"
|
|
|
|
|
>
|
|
|
|
|
<div v-show="showSearch" class="mb-[10px]">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<el-form ref="traceQueryFormRef" :model="traceQuery" :inline="true">
|
|
|
|
|
<el-form-item label="配方编码" prop="recipeCode">
|
|
|
|
|
<el-input v-model="traceQuery.recipeCode" placeholder="请输入配方编码" clearable
|
|
|
|
|
@keyup.enter="handleTraceQuery" />
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="traceQuery.recipeCode"
|
|
|
|
|
placeholder="请输入配方编码"
|
|
|
|
|
clearable
|
|
|
|
|
@keyup.enter="handleTraceQuery"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="机台" prop="machineId">
|
|
|
|
|
<el-input v-model="traceQuery.machineId" placeholder="请输入机台ID" clearable />
|
|
|
|
|
<el-form-item label="机台" prop="machineName">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="traceQuery.machineName"
|
|
|
|
|
placeholder="请输入机台名称"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="物料名称" prop="materialName">
|
|
|
|
|
<el-input v-model="traceQuery.materialName" placeholder="请输入物料名称" clearable />
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="traceQuery.materialName"
|
|
|
|
|
placeholder="请输入物料名称"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="胶种类型" prop="rubType">
|
|
|
|
|
<el-input v-model="traceQuery.rubType" placeholder="请输入胶种类型" clearable />
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="traceQuery.rubType"
|
|
|
|
|
placeholder="请输入胶种类型"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="操作者" prop="operCode">
|
|
|
|
|
<el-input v-model="traceQuery.operCode" placeholder="请输入操作者" clearable />
|
|
|
|
|
<el-form-item label="操作员" prop="operCode">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="traceQuery.operCode"
|
|
|
|
|
placeholder="请输入操作员"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="创建日期" style="width: 380px;">
|
|
|
|
|
<el-date-picker v-model="traceDateRange" type="daterange" range-separator="-"
|
|
|
|
|
start-placeholder="开始日期" end-placeholder="结束日期"
|
|
|
|
|
value-format="YYYY-MM-DD" />
|
|
|
|
|
<el-form-item label="创建日期" style="width: 380px">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="traceDateRange"
|
|
|
|
|
type="daterange"
|
|
|
|
|
range-separator="-"
|
|
|
|
|
start-placeholder="开始日期"
|
|
|
|
|
end-placeholder="结束日期"
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-button type="primary" icon="Search" @click="handleTraceQuery">搜索</el-button>
|
|
|
|
|
@ -42,78 +68,111 @@
|
|
|
|
|
<template #header>
|
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
|
<el-col :span="1.5">
|
|
|
|
|
<el-button type="warning" plain icon="Download" @click="handleExport"
|
|
|
|
|
v-hasPermi="['mes:mixTrace:export']">导出</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
type="warning"
|
|
|
|
|
plain
|
|
|
|
|
icon="Download"
|
|
|
|
|
@click="handleExport"
|
|
|
|
|
v-hasPermi="['mes:mixTrace:export']"
|
|
|
|
|
>导出</el-button>
|
|
|
|
|
</el-col>
|
|
|
|
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getTraceList" />
|
|
|
|
|
</el-row>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<el-table v-loading="traceLoading" :data="traceList" @row-click="handleTraceRowClick"
|
|
|
|
|
highlight-current-row border stripe>
|
|
|
|
|
<el-table
|
|
|
|
|
v-loading="traceLoading"
|
|
|
|
|
:data="traceList"
|
|
|
|
|
@row-click="handleTraceRowClick"
|
|
|
|
|
highlight-current-row
|
|
|
|
|
border
|
|
|
|
|
stripe
|
|
|
|
|
>
|
|
|
|
|
<el-table-column label="配方编码" prop="recipeCode" min-width="120" />
|
|
|
|
|
<el-table-column label="机台名称" prop="machineName" min-width="100" />
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="120" />
|
|
|
|
|
<el-table-column label="胶种类型" prop="rubType" min-width="100" />
|
|
|
|
|
<el-table-column label="胶种编码" prop="rubTypecode" min-width="100" />
|
|
|
|
|
<el-table-column label="配方重量" prop="totalWeight" min-width="90" align="right" />
|
|
|
|
|
<el-table-column label="版本号" prop="edtCode" min-width="70" align="center" />
|
|
|
|
|
<el-table-column label="操作者" prop="operCode" min-width="80" />
|
|
|
|
|
<el-table-column label="称量步数" prop="weightCount" min-width="80" align="center" />
|
|
|
|
|
<el-table-column label="混炼步数" prop="mixingCount" min-width="80" align="center" />
|
|
|
|
|
<el-table-column label="配方状态" prop="recipeState" min-width="80" align="center">
|
|
|
|
|
<el-table-column label="机台名称" prop="machineName" min-width="120" />
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="140" />
|
|
|
|
|
<el-table-column label="胶种类型" prop="rubType" min-width="110" />
|
|
|
|
|
<el-table-column label="配方重量" prop="totalWeight" min-width="100" align="right" />
|
|
|
|
|
<el-table-column label="操作员" prop="operCode" min-width="100" />
|
|
|
|
|
<el-table-column label="称量步数" prop="weightCount" min-width="90" align="center" />
|
|
|
|
|
<el-table-column label="混炼步数" prop="mixingCount" min-width="90" align="center" />
|
|
|
|
|
<el-table-column label="配方状态" prop="recipeState" min-width="90" align="center">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-tag :type="row.recipeState === '1' ? 'success' : 'info'" size="small">
|
|
|
|
|
{{ row.recipeState === '1' ? '正用' : '停用' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
<dict-tag :options="recipe_state" :value="row.recipeState" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="创建时间" prop="createTime" min-width="160" />
|
|
|
|
|
<el-table-column label="操作" width="80" align="center" fixed="right">
|
|
|
|
|
<el-table-column label="创建时间" prop="createTime" min-width="170" />
|
|
|
|
|
<el-table-column label="操作" width="90" align="center" fixed="right">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-button link type="primary" @click.stop="openDetail(row)">详情</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
<pagination v-show="traceTotal > 0" :total="traceTotal" v-model:page="traceQuery.pageNum"
|
|
|
|
|
v-model:limit="traceQuery.pageSize" @pagination="getTraceList" />
|
|
|
|
|
<pagination
|
|
|
|
|
v-show="traceTotal > 0"
|
|
|
|
|
:total="traceTotal"
|
|
|
|
|
v-model:page="traceQuery.pageNum"
|
|
|
|
|
v-model:limit="traceQuery.pageSize"
|
|
|
|
|
@pagination="getTraceList"
|
|
|
|
|
/>
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
<!-- ==================== Tab2: SPC分析(图6/7/8/10) ==================== -->
|
|
|
|
|
<el-tab-pane label="SPC分析" name="spc">
|
|
|
|
|
<el-card shadow="hover" class="mb-[10px]">
|
|
|
|
|
<el-form ref="spcQueryFormRef" :model="spcQuery" :inline="true">
|
|
|
|
|
<el-form-item label="机台ID" prop="machineId">
|
|
|
|
|
<el-input v-model="spcQuery.machineId" placeholder="请输入机台ID" clearable />
|
|
|
|
|
<el-form-item label="机台" prop="machineName">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="spcQuery.machineName"
|
|
|
|
|
placeholder="请输入机台名称"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="配方编码" prop="recipeCode">
|
|
|
|
|
<el-input v-model="spcQuery.recipeCode" placeholder="请输入配方编码" clearable />
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="spcQuery.recipeCode"
|
|
|
|
|
placeholder="请输入配方编码"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="胶种编码" prop="rubTypecode">
|
|
|
|
|
<el-input v-model="spcQuery.rubTypecode" placeholder="请输入胶种编码" clearable />
|
|
|
|
|
<el-form-item label="胶种类型" prop="rubType">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="spcQuery.rubType"
|
|
|
|
|
placeholder="请输入胶种类型"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="工步号" prop="mixId">
|
|
|
|
|
<el-input v-model="spcQuery.mixId" placeholder="工步号" clearable style="width: 100px;" />
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="spcQuery.mixId"
|
|
|
|
|
placeholder="请输入工步号"
|
|
|
|
|
clearable
|
|
|
|
|
style="width: 120px"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="分析参数" prop="paramName">
|
|
|
|
|
<el-select v-model="spcQuery.paramName" placeholder="选择分析参数" style="width: 140px;">
|
|
|
|
|
<el-option label="混炼温度" value="mixingTemp" />
|
|
|
|
|
<el-option label="混炼时间" value="mixingTime" />
|
|
|
|
|
<el-option label="混炼能量" value="mixingEnergy" />
|
|
|
|
|
<el-option label="混炼功率" value="mixingPower" />
|
|
|
|
|
<el-option label="混炼压力" value="mixingPress" />
|
|
|
|
|
<el-option label="混炼转速" value="mixingSpeed" />
|
|
|
|
|
<el-select v-model="spcQuery.paramName" placeholder="选择分析参数" style="width: 150px">
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in spcParamOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="子组大小" prop="subgroupSize">
|
|
|
|
|
<el-input-number v-model="spcQuery.subgroupSize" :min="2" :max="10" style="width: 120px;" />
|
|
|
|
|
<el-input-number v-model="spcQuery.subgroupSize" :min="2" :max="10" style="width: 120px" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="日期范围" style="width: 380px;">
|
|
|
|
|
<el-date-picker v-model="spcDateRange" type="daterange" range-separator="-"
|
|
|
|
|
start-placeholder="开始" end-placeholder="结束"
|
|
|
|
|
value-format="YYYY-MM-DD" />
|
|
|
|
|
<el-form-item label="日期范围" style="width: 380px">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="spcDateRange"
|
|
|
|
|
type="daterange"
|
|
|
|
|
range-separator="-"
|
|
|
|
|
start-placeholder="开始"
|
|
|
|
|
end-placeholder="结束"
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-button type="primary" icon="Search" @click="handleSpcQuery">分析</el-button>
|
|
|
|
|
@ -122,7 +181,6 @@
|
|
|
|
|
</el-form>
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
<!-- SPC 统计指标卡片 -->
|
|
|
|
|
<el-row :gutter="10" class="mb-[10px]" v-if="spcResult.sampleCount > 0">
|
|
|
|
|
<el-col :span="3" v-for="item in spcIndicators" :key="item.label">
|
|
|
|
|
<el-card shadow="hover" class="text-center">
|
|
|
|
|
@ -134,44 +192,43 @@
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<!-- SPC 图表区域 -->
|
|
|
|
|
<el-row :gutter="10" class="mb-[10px]" v-if="spcResult.sampleCount > 0">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<template #header><span>能力分析图(直方图)</span></template>
|
|
|
|
|
<div ref="histogramChartRef" style="height: 350px;" />
|
|
|
|
|
<div ref="histogramChartRef" style="height: 350px" />
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<template #header><span>运行图</span></template>
|
|
|
|
|
<div ref="runChartRef" style="height: 350px;" />
|
|
|
|
|
<div ref="runChartRef" style="height: 350px" />
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="10" class="mb-[10px]" v-if="xbarRResult.sampleCount > 0">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<template #header><span>Xbar 均值图</span></template>
|
|
|
|
|
<div ref="xbarChartRef" style="height: 350px;" />
|
|
|
|
|
<div ref="xbarChartRef" style="height: 350px" />
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<template #header><span>R 极差图</span></template>
|
|
|
|
|
<div ref="rChartRef" style="height: 350px;" />
|
|
|
|
|
<div ref="rChartRef" style="height: 350px" />
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<!-- SPC 样本列表 -->
|
|
|
|
|
<el-card shadow="hover" v-if="spcSampleList.length > 0">
|
|
|
|
|
<template #header><span>SPC样本明细</span></template>
|
|
|
|
|
<el-table :data="spcSampleList" border stripe max-height="400">
|
|
|
|
|
<el-table-column label="配方编码" prop="recipeCode" min-width="120" />
|
|
|
|
|
<el-table-column label="机台" prop="machineName" min-width="100" />
|
|
|
|
|
<el-table-column label="机台" prop="machineName" min-width="110" />
|
|
|
|
|
<el-table-column label="工步号" prop="mixId" width="80" align="center" />
|
|
|
|
|
<el-table-column label="工步编码" prop="termCode" min-width="90" />
|
|
|
|
|
<el-table-column label="工步" prop="termCode" min-width="120" />
|
|
|
|
|
<el-table-column label="实测温度" prop="mixingTemp" width="90" align="right" />
|
|
|
|
|
<el-table-column label="设定温度" prop="setTemp" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测时间" prop="mixingTime" width="90" align="right" />
|
|
|
|
|
@ -180,83 +237,83 @@
|
|
|
|
|
<el-table-column label="实测功率" prop="mixingPower" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测压力" prop="mixingPress" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测转速" prop="mixingSpeed" width="90" align="right" />
|
|
|
|
|
<el-table-column label="生产时间" prop="createTime" min-width="160" />
|
|
|
|
|
<el-table-column label="生产时间" prop="createTime" min-width="170" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<pagination v-show="spcSampleTotal > 0" :total="spcSampleTotal"
|
|
|
|
|
v-model:page="spcQuery.pageNum" v-model:limit="spcQuery.pageSize"
|
|
|
|
|
@pagination="getSpcSamples" />
|
|
|
|
|
<pagination
|
|
|
|
|
v-show="spcSampleTotal > 0"
|
|
|
|
|
:total="spcSampleTotal"
|
|
|
|
|
v-model:page="spcQuery.pageNum"
|
|
|
|
|
v-model:limit="spcQuery.pageSize"
|
|
|
|
|
@pagination="getSpcSamples"
|
|
|
|
|
/>
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
</el-tabs>
|
|
|
|
|
|
|
|
|
|
<!-- ==================== 追溯详情抽屉(图9) ==================== -->
|
|
|
|
|
<el-drawer v-model="detailVisible" title="配方追溯详情" size="70%" direction="rtl" destroy-on-close>
|
|
|
|
|
<template v-if="detailData">
|
|
|
|
|
<!-- 基础信息 -->
|
|
|
|
|
<el-descriptions title="基础信息" :column="3" border class="mb-4">
|
|
|
|
|
<el-descriptions-item label="配方编码">{{ detailData.recipeInfo?.recipeCode }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="机台">{{ detailData.recipeInfo?.machineName }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="物料">{{ detailData.recipeInfo?.materialName }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="胶种类型">{{ detailData.recipeInfo?.rubType }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="胶种编码">{{ detailData.recipeInfo?.rubTypecode }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="版本号">{{ detailData.recipeInfo?.edtCode }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="配方重量">{{ detailData.recipeInfo?.totalWeight }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="填充系数">{{ detailData.recipeInfo?.fillCoefficient }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="操作者">{{ detailData.recipeInfo?.operCode }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="操作员">{{ detailData.recipeInfo?.operCode }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="完成时间">{{ detailData.recipeInfo?.doneTime }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="配方状态">
|
|
|
|
|
<el-tag :type="detailData.recipeInfo?.recipeState === '1' ? 'success' : 'info'" size="small">
|
|
|
|
|
{{ detailData.recipeInfo?.recipeState === '1' ? '正用' : '停用' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
<dict-tag :options="recipe_state" :value="detailData.recipeInfo?.recipeState" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="创建时间">{{ detailData.recipeInfo?.createTime }}</el-descriptions-item>
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
<!-- 称量明细 -->
|
|
|
|
|
<div class="mb-4">
|
|
|
|
|
<h4 class="mb-2 font-bold">称量明细({{ detailData.weightList?.length || 0 }}项)</h4>
|
|
|
|
|
<el-table :data="detailData.weightList" border stripe max-height="300" size="small">
|
|
|
|
|
<el-table-column label="序号" prop="weightSeq" width="60" align="center" />
|
|
|
|
|
<el-table-column label="称量类型" prop="weightType" width="90" />
|
|
|
|
|
<el-table-column label="动作编码" prop="actCode" min-width="90" />
|
|
|
|
|
<el-table-column label="设定重量" prop="setWeight" width="90" align="right" />
|
|
|
|
|
<el-table-column label="误差允许" prop="errorAllow" width="90" align="right" />
|
|
|
|
|
<el-table-column label="秤编码" prop="scaleCode" width="80" />
|
|
|
|
|
<el-table-column label="父级编码" prop="fatherCode" width="90" />
|
|
|
|
|
<el-table-column label="子级编码" prop="childCode" width="90" />
|
|
|
|
|
<el-table-column label="使用批次" prop="ifUseBat" width="80" align="center" />
|
|
|
|
|
<el-table-column label="最大比例" prop="maxRate" width="80" />
|
|
|
|
|
<el-table-column label="称量类型" prop="weightType" width="100">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<dict-tag :options="weight_type" :value="row.weightType" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="动作" prop="actCode" min-width="120" />
|
|
|
|
|
<el-table-column label="设定重量" prop="setWeight" width="100" align="right" />
|
|
|
|
|
<el-table-column label="误差允许" prop="errorAllow" width="100" align="right" />
|
|
|
|
|
<el-table-column label="使用批次" prop="ifUseBat" width="90" align="center">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<dict-tag :options="sys_yes_no" :value="row.ifUseBat" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="最大比例" prop="maxRate" width="90" />
|
|
|
|
|
</el-table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 混炼明细 -->
|
|
|
|
|
<div class="mb-4">
|
|
|
|
|
<h4 class="mb-2 font-bold">混炼明细({{ detailData.mixingList?.length || 0 }}项)</h4>
|
|
|
|
|
<el-table :data="detailData.mixingList" border stripe max-height="400" size="small">
|
|
|
|
|
<el-table-column label="步号" prop="mixId" width="60" align="center" />
|
|
|
|
|
<el-table-column label="工步编码" prop="termCode" min-width="80" />
|
|
|
|
|
<el-table-column label="条件编码" prop="condCode" width="80" />
|
|
|
|
|
<el-table-column label="动作编码" prop="actCode" width="80" />
|
|
|
|
|
<el-table-column label="设定时间" prop="setTime" width="80" align="right" />
|
|
|
|
|
<el-table-column label="实测时间" prop="mixingTime" width="80" align="right" />
|
|
|
|
|
<el-table-column label="设定温度" prop="setTemp" width="80" align="right" />
|
|
|
|
|
<el-table-column label="实测温度" prop="mixingTemp" width="80" align="right" />
|
|
|
|
|
<el-table-column label="设定能量" prop="setEnergy" width="80" align="right" />
|
|
|
|
|
<el-table-column label="实测能量" prop="mixingEnergy" width="80" align="right" />
|
|
|
|
|
<el-table-column label="设定功率" prop="setPower" width="80" align="right" />
|
|
|
|
|
<el-table-column label="实测功率" prop="mixingPower" width="80" align="right" />
|
|
|
|
|
<el-table-column label="设定压力" prop="setPres" width="80" align="right" />
|
|
|
|
|
<el-table-column label="实测压力" prop="mixingPress" width="80" align="right" />
|
|
|
|
|
<el-table-column label="设定转速" prop="setRota" width="80" align="right" />
|
|
|
|
|
<el-table-column label="实测转速" prop="mixingSpeed" width="80" align="right" />
|
|
|
|
|
<el-table-column label="工步" prop="termCode" min-width="120" />
|
|
|
|
|
<el-table-column label="条件" prop="condCode" min-width="120" />
|
|
|
|
|
<el-table-column label="动作" prop="actCode" min-width="120" />
|
|
|
|
|
<el-table-column label="设定时间" prop="setTime" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测时间" prop="mixingTime" width="90" align="right" />
|
|
|
|
|
<el-table-column label="设定温度" prop="setTemp" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测温度" prop="mixingTemp" width="90" align="right" />
|
|
|
|
|
<el-table-column label="设定能量" prop="setEnergy" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测能量" prop="mixingEnergy" width="90" align="right" />
|
|
|
|
|
<el-table-column label="设定功率" prop="setPower" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测功率" prop="mixingPower" width="90" align="right" />
|
|
|
|
|
<el-table-column label="设定压力" prop="setPres" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测压力" prop="mixingPress" width="90" align="right" />
|
|
|
|
|
<el-table-column label="设定转速" prop="setRota" width="90" align="right" />
|
|
|
|
|
<el-table-column label="实测转速" prop="mixingSpeed" width="90" align="right" />
|
|
|
|
|
</el-table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 混炼曲线图(图4) -->
|
|
|
|
|
<div class="mb-4" v-if="detailData.mixingList && detailData.mixingList.length > 0">
|
|
|
|
|
<h4 class="mb-2 font-bold">密炼工作曲线</h4>
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<div ref="detailCurveChartRef" style="height: 350px;" />
|
|
|
|
|
<div ref="detailCurveChartRef" style="height: 350px" />
|
|
|
|
|
</el-card>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
@ -265,26 +322,33 @@
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, reactive, computed, nextTick, onMounted, watch } from 'vue';
|
|
|
|
|
import { getCurrentInstance } from 'vue';
|
|
|
|
|
import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, reactive, ref, toRefs } from 'vue';
|
|
|
|
|
import type { ComponentInternalInstance } from 'vue';
|
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
import {
|
|
|
|
|
listMixTrace, exportMixTrace, getMixTraceDetail,
|
|
|
|
|
listSpcSamples, getSpcCapability, getSpcXbarR
|
|
|
|
|
getMixTraceDetail,
|
|
|
|
|
getSpcCapability,
|
|
|
|
|
getSpcRunChart,
|
|
|
|
|
getSpcXbarR,
|
|
|
|
|
listMixTrace,
|
|
|
|
|
listSpcSamples
|
|
|
|
|
} from '@/api/mes/mixTrace';
|
|
|
|
|
import type {
|
|
|
|
|
MixTraceListVO, MixTraceDetailVO, MixTraceSpcSampleVO, MixTraceSpcResultVO
|
|
|
|
|
MixTraceDetailVO,
|
|
|
|
|
MixTraceListVO,
|
|
|
|
|
MixTraceSpcResultVO,
|
|
|
|
|
MixTraceSpcSampleVO
|
|
|
|
|
} from '@/api/mes/mixTrace/types';
|
|
|
|
|
import { download } from '@/utils/request';
|
|
|
|
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
const { recipe_state, weight_type, mix_trace_spc_param, sys_yes_no } = toRefs<any>(
|
|
|
|
|
proxy?.useDict('recipe_state', 'weight_type', 'mix_trace_spc_param', 'sys_yes_no')
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// ==================== 通用状态 ====================
|
|
|
|
|
const activeTab = ref('trace');
|
|
|
|
|
const showSearch = ref(true);
|
|
|
|
|
|
|
|
|
|
// ==================== 追溯列表(图5) ====================
|
|
|
|
|
const traceLoading = ref(false);
|
|
|
|
|
const traceList = ref<MixTraceListVO[]>([]);
|
|
|
|
|
const traceTotal = ref(0);
|
|
|
|
|
@ -292,7 +356,7 @@ const traceDateRange = ref<string[]>([]);
|
|
|
|
|
const traceQueryFormRef = ref();
|
|
|
|
|
const traceQuery = reactive<any>({
|
|
|
|
|
recipeCode: undefined,
|
|
|
|
|
machineId: undefined,
|
|
|
|
|
machineName: undefined,
|
|
|
|
|
materialName: undefined,
|
|
|
|
|
rubType: undefined,
|
|
|
|
|
operCode: undefined,
|
|
|
|
|
@ -302,15 +366,19 @@ const traceQuery = reactive<any>({
|
|
|
|
|
pageSize: 20
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getTraceList = async () => {
|
|
|
|
|
traceLoading.value = true;
|
|
|
|
|
if (traceDateRange.value && traceDateRange.value.length === 2) {
|
|
|
|
|
const applyTraceDateRange = () => {
|
|
|
|
|
if (traceDateRange.value?.length === 2) {
|
|
|
|
|
traceQuery.beginDate = traceDateRange.value[0];
|
|
|
|
|
traceQuery.endDate = traceDateRange.value[1];
|
|
|
|
|
} else {
|
|
|
|
|
traceQuery.beginDate = undefined;
|
|
|
|
|
traceQuery.endDate = undefined;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
traceQuery.beginDate = undefined;
|
|
|
|
|
traceQuery.endDate = undefined;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getTraceList = async () => {
|
|
|
|
|
traceLoading.value = true;
|
|
|
|
|
applyTraceDateRange();
|
|
|
|
|
try {
|
|
|
|
|
const res = await listMixTrace(traceQuery);
|
|
|
|
|
traceList.value = res.rows || [];
|
|
|
|
|
@ -334,18 +402,14 @@ const resetTraceQuery = () => {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleExport = () => {
|
|
|
|
|
if (traceDateRange.value && traceDateRange.value.length === 2) {
|
|
|
|
|
traceQuery.beginDate = traceDateRange.value[0];
|
|
|
|
|
traceQuery.endDate = traceDateRange.value[1];
|
|
|
|
|
}
|
|
|
|
|
exportMixTrace(traceQuery);
|
|
|
|
|
applyTraceDateRange();
|
|
|
|
|
download('/mes/mixTrace/export', { ...traceQuery }, `mix_trace_${Date.now()}.xlsx`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleTraceRowClick = (row: MixTraceListVO) => {
|
|
|
|
|
openDetail(row);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ==================== 追溯详情(图9) ====================
|
|
|
|
|
const detailVisible = ref(false);
|
|
|
|
|
const detailData = ref<MixTraceDetailVO | null>(null);
|
|
|
|
|
const detailCurveChartRef = ref<HTMLElement>();
|
|
|
|
|
@ -359,13 +423,17 @@ const openDetail = async (row: MixTraceListVO) => {
|
|
|
|
|
renderDetailCurveChart();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 渲染密炼工作曲线(图4) */
|
|
|
|
|
const renderDetailCurveChart = () => {
|
|
|
|
|
if (!detailCurveChartRef.value || !detailData.value?.mixingList?.length) return;
|
|
|
|
|
if (detailCurveChart) detailCurveChart.dispose();
|
|
|
|
|
if (!detailCurveChartRef.value || !detailData.value?.mixingList?.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (detailCurveChart) {
|
|
|
|
|
detailCurveChart.dispose();
|
|
|
|
|
}
|
|
|
|
|
detailCurveChart = echarts.init(detailCurveChartRef.value);
|
|
|
|
|
|
|
|
|
|
const mixList = detailData.value.mixingList;
|
|
|
|
|
const xData = mixList.map(m => '步' + m.mixId);
|
|
|
|
|
const xData = mixList.map((m) => `步${m.mixId}`);
|
|
|
|
|
|
|
|
|
|
detailCurveChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
@ -377,29 +445,47 @@ const renderDetailCurveChart = () => {
|
|
|
|
|
{ type: 'value', name: '时间/转速', position: 'right' }
|
|
|
|
|
],
|
|
|
|
|
series: [
|
|
|
|
|
{ name: '实测温度', type: 'line', data: mixList.map(m => m.mixingTemp), smooth: true },
|
|
|
|
|
{ name: '设定温度', type: 'line', data: mixList.map(m => m.setTemp), lineStyle: { type: 'dashed' } },
|
|
|
|
|
{ name: '实测能量', type: 'line', data: mixList.map(m => m.mixingEnergy), smooth: true },
|
|
|
|
|
{ name: '实测功率', type: 'line', data: mixList.map(m => m.mixingPower), smooth: true },
|
|
|
|
|
{ name: '实测转速', type: 'line', yAxisIndex: 1, data: mixList.map(m => m.mixingSpeed), smooth: true },
|
|
|
|
|
{ name: '实测时间', type: 'bar', yAxisIndex: 1, data: mixList.map(m => m.mixingTime), barWidth: 15, opacity: 0.4 }
|
|
|
|
|
{ name: '实测温度', type: 'line', data: mixList.map((m) => m.mixingTemp), smooth: true },
|
|
|
|
|
{
|
|
|
|
|
name: '设定温度',
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: mixList.map((m) => m.setTemp),
|
|
|
|
|
lineStyle: { type: 'dashed' }
|
|
|
|
|
},
|
|
|
|
|
{ name: '实测能量', type: 'line', data: mixList.map((m) => m.mixingEnergy), smooth: true },
|
|
|
|
|
{ name: '实测功率', type: 'line', data: mixList.map((m) => m.mixingPower), smooth: true },
|
|
|
|
|
{
|
|
|
|
|
name: '实测转速',
|
|
|
|
|
type: 'line',
|
|
|
|
|
yAxisIndex: 1,
|
|
|
|
|
data: mixList.map((m) => m.mixingSpeed),
|
|
|
|
|
smooth: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '实测时间',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
yAxisIndex: 1,
|
|
|
|
|
data: mixList.map((m) => m.mixingTime),
|
|
|
|
|
barWidth: 15,
|
|
|
|
|
opacity: 0.4
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ==================== SPC分析(图6/7/8/10) ====================
|
|
|
|
|
const spcSampleList = ref<MixTraceSpcSampleVO[]>([]);
|
|
|
|
|
const spcSampleTotal = ref(0);
|
|
|
|
|
const spcResult = ref<MixTraceSpcResultVO>({ sampleCount: 0 } as MixTraceSpcResultVO);
|
|
|
|
|
const runChartResult = ref<MixTraceSpcResultVO>({ sampleCount: 0 } as MixTraceSpcResultVO);
|
|
|
|
|
const xbarRResult = ref<MixTraceSpcResultVO>({ sampleCount: 0 } as MixTraceSpcResultVO);
|
|
|
|
|
const spcDateRange = ref<string[]>([]);
|
|
|
|
|
const spcQueryFormRef = ref();
|
|
|
|
|
const spcQuery = reactive<any>({
|
|
|
|
|
machineId: undefined,
|
|
|
|
|
machineName: undefined,
|
|
|
|
|
recipeCode: undefined,
|
|
|
|
|
rubTypecode: undefined,
|
|
|
|
|
rubType: undefined,
|
|
|
|
|
mixId: undefined,
|
|
|
|
|
paramName: 'mixingTemp',
|
|
|
|
|
paramName: undefined,
|
|
|
|
|
subgroupSize: 5,
|
|
|
|
|
beginDate: undefined,
|
|
|
|
|
endDate: undefined,
|
|
|
|
|
@ -416,10 +502,13 @@ let runChart: echarts.ECharts | null = null;
|
|
|
|
|
let xbarChart: echarts.ECharts | null = null;
|
|
|
|
|
let rChart: echarts.ECharts | null = null;
|
|
|
|
|
|
|
|
|
|
/** SPC 统计指标卡片 */
|
|
|
|
|
const spcParamOptions = computed(() => mix_trace_spc_param.value || []);
|
|
|
|
|
|
|
|
|
|
const spcIndicators = computed(() => {
|
|
|
|
|
const r = spcResult.value;
|
|
|
|
|
if (!r || !r.sampleCount) return [];
|
|
|
|
|
if (!r || !r.sampleCount) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
return [
|
|
|
|
|
{ label: '样本数', value: r.sampleCount, color: '#409eff' },
|
|
|
|
|
{ label: '均值', value: r.mean?.toFixed(2) ?? '-' },
|
|
|
|
|
@ -432,182 +521,267 @@ const spcIndicators = computed(() => {
|
|
|
|
|
];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const resolveSpcParamLabel = (paramName?: string) => {
|
|
|
|
|
if (!paramName) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
const match = spcParamOptions.value.find((item: any) => String(item.value) === String(paramName));
|
|
|
|
|
return match?.label || paramName;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const cpkColor = (v: number | null | undefined) => {
|
|
|
|
|
if (v == null) return '#999';
|
|
|
|
|
if (v >= 1.33) return '#67c23a';
|
|
|
|
|
if (v >= 1.0) return '#e6a23c';
|
|
|
|
|
if (v == null) {
|
|
|
|
|
return '#999';
|
|
|
|
|
}
|
|
|
|
|
if (v >= 1.33) {
|
|
|
|
|
return '#67c23a';
|
|
|
|
|
}
|
|
|
|
|
if (v >= 1.0) {
|
|
|
|
|
return '#e6a23c';
|
|
|
|
|
}
|
|
|
|
|
return '#f56c6c';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const buildSpcParams = () => {
|
|
|
|
|
if (spcDateRange.value && spcDateRange.value.length === 2) {
|
|
|
|
|
const applySpcDateRange = () => {
|
|
|
|
|
if (spcDateRange.value?.length === 2) {
|
|
|
|
|
spcQuery.beginDate = spcDateRange.value[0];
|
|
|
|
|
spcQuery.endDate = spcDateRange.value[1];
|
|
|
|
|
} else {
|
|
|
|
|
spcQuery.beginDate = undefined;
|
|
|
|
|
spcQuery.endDate = undefined;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
spcQuery.beginDate = undefined;
|
|
|
|
|
spcQuery.endDate = undefined;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSpcQuery = async () => {
|
|
|
|
|
buildSpcParams();
|
|
|
|
|
await Promise.all([getSpcSamples(), fetchSpcCapability(), fetchSpcXbarR()]);
|
|
|
|
|
applySpcDateRange();
|
|
|
|
|
await Promise.all([getSpcSamples(), fetchSpcCapability(), fetchSpcRunChart(), fetchSpcXbarR()]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const resetSpcQuery = () => {
|
|
|
|
|
spcQueryFormRef.value?.resetFields();
|
|
|
|
|
spcDateRange.value = [];
|
|
|
|
|
spcQuery.paramName = 'mixingTemp';
|
|
|
|
|
spcQuery.paramName = undefined;
|
|
|
|
|
spcQuery.subgroupSize = 5;
|
|
|
|
|
spcQuery.pageNum = 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getSpcSamples = async () => {
|
|
|
|
|
buildSpcParams();
|
|
|
|
|
applySpcDateRange();
|
|
|
|
|
const res = await listSpcSamples(spcQuery);
|
|
|
|
|
spcSampleList.value = res.rows || [];
|
|
|
|
|
spcSampleTotal.value = res.total || 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchSpcCapability = async () => {
|
|
|
|
|
buildSpcParams();
|
|
|
|
|
applySpcDateRange();
|
|
|
|
|
const res = await getSpcCapability(spcQuery);
|
|
|
|
|
spcResult.value = res.data || { sampleCount: 0 } as MixTraceSpcResultVO;
|
|
|
|
|
spcResult.value = res.data || ({ sampleCount: 0 } as MixTraceSpcResultVO);
|
|
|
|
|
await nextTick();
|
|
|
|
|
renderHistogramChart();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchSpcRunChart = async () => {
|
|
|
|
|
applySpcDateRange();
|
|
|
|
|
const res = await getSpcRunChart(spcQuery);
|
|
|
|
|
runChartResult.value = res.data || ({ sampleCount: 0 } as MixTraceSpcResultVO);
|
|
|
|
|
await nextTick();
|
|
|
|
|
renderRunChart();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchSpcXbarR = async () => {
|
|
|
|
|
buildSpcParams();
|
|
|
|
|
applySpcDateRange();
|
|
|
|
|
const res = await getSpcXbarR(spcQuery);
|
|
|
|
|
xbarRResult.value = res.data || { sampleCount: 0 } as MixTraceSpcResultVO;
|
|
|
|
|
xbarRResult.value = res.data || ({ sampleCount: 0 } as MixTraceSpcResultVO);
|
|
|
|
|
await nextTick();
|
|
|
|
|
renderXbarChart();
|
|
|
|
|
renderRChart();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 直方图(图7) */
|
|
|
|
|
const renderHistogramChart = () => {
|
|
|
|
|
if (!histogramChartRef.value) return;
|
|
|
|
|
if (!histogramChartRef.value) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const r = spcResult.value;
|
|
|
|
|
if (!r.histogramBins?.length) return;
|
|
|
|
|
if (histogramChart) histogramChart.dispose();
|
|
|
|
|
if (!r.histogramBins?.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (histogramChart) {
|
|
|
|
|
histogramChart.dispose();
|
|
|
|
|
}
|
|
|
|
|
histogramChart = echarts.init(histogramChartRef.value);
|
|
|
|
|
histogramChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
grid: { left: 50, right: 20, bottom: 60, top: 30 },
|
|
|
|
|
xAxis: { type: 'category', data: r.histogramBins, axisLabel: { rotate: 30, fontSize: 10 } },
|
|
|
|
|
yAxis: { type: 'value', name: '频次' },
|
|
|
|
|
series: [{
|
|
|
|
|
type: 'bar', data: r.histogramCounts,
|
|
|
|
|
itemStyle: { color: '#409eff' },
|
|
|
|
|
barWidth: '70%'
|
|
|
|
|
}],
|
|
|
|
|
graphic: [{
|
|
|
|
|
type: 'text',
|
|
|
|
|
left: 'center', bottom: 5,
|
|
|
|
|
style: {
|
|
|
|
|
text: `Cp=${r.cp?.toFixed(3) ?? '-'} Cpk=${r.cpk?.toFixed(3) ?? '-'} Ppk=${r.ppk?.toFixed(3) ?? '-'} σ=${r.sigma?.toFixed(4) ?? '-'}`,
|
|
|
|
|
fontSize: 12, fill: '#666'
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'bar',
|
|
|
|
|
data: r.histogramCounts,
|
|
|
|
|
itemStyle: { color: '#409eff' },
|
|
|
|
|
barWidth: '70%'
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
],
|
|
|
|
|
graphic: [
|
|
|
|
|
{
|
|
|
|
|
type: 'text',
|
|
|
|
|
left: 'center',
|
|
|
|
|
bottom: 5,
|
|
|
|
|
style: {
|
|
|
|
|
text: `Cp=${r.cp?.toFixed(3) ?? '-'} Cpk=${r.cpk?.toFixed(3) ?? '-'} Ppk=${r.ppk?.toFixed(3) ?? '-'} Sigma=${r.sigma?.toFixed(4) ?? '-'}`,
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
fill: '#666'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 运行图(图8) */
|
|
|
|
|
const renderRunChart = () => {
|
|
|
|
|
if (!runChartRef.value) return;
|
|
|
|
|
const r = spcResult.value;
|
|
|
|
|
if (!r.sampleValues?.length) return;
|
|
|
|
|
if (runChart) runChart.dispose();
|
|
|
|
|
if (!runChartRef.value) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const r = runChartResult.value;
|
|
|
|
|
if (!r.sampleValues?.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (runChart) {
|
|
|
|
|
runChart.dispose();
|
|
|
|
|
}
|
|
|
|
|
runChart = echarts.init(runChartRef.value);
|
|
|
|
|
|
|
|
|
|
const markLines: any[] = [];
|
|
|
|
|
if (r.usl != null) markLines.push({ yAxis: r.usl, name: 'USL', lineStyle: { color: '#f56c6c', type: 'dashed' } });
|
|
|
|
|
if (r.lsl != null) markLines.push({ yAxis: r.lsl, name: 'LSL', lineStyle: { color: '#f56c6c', type: 'dashed' } });
|
|
|
|
|
if (r.target != null) markLines.push({ yAxis: r.target, name: 'Target', lineStyle: { color: '#67c23a', type: 'solid' } });
|
|
|
|
|
if (r.mean != null) markLines.push({ yAxis: r.mean, name: 'Mean', lineStyle: { color: '#409eff', type: 'dotted' } });
|
|
|
|
|
if (r.usl != null) {
|
|
|
|
|
markLines.push({ yAxis: r.usl, name: 'USL', lineStyle: { color: '#f56c6c', type: 'dashed' } });
|
|
|
|
|
}
|
|
|
|
|
if (r.lsl != null) {
|
|
|
|
|
markLines.push({ yAxis: r.lsl, name: 'LSL', lineStyle: { color: '#f56c6c', type: 'dashed' } });
|
|
|
|
|
}
|
|
|
|
|
if (r.target != null) {
|
|
|
|
|
markLines.push({ yAxis: r.target, name: 'Target', lineStyle: { color: '#67c23a', type: 'solid' } });
|
|
|
|
|
}
|
|
|
|
|
if (r.mean != null) {
|
|
|
|
|
markLines.push({ yAxis: r.mean, name: 'Mean', lineStyle: { color: '#409eff', type: 'dotted' } });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
grid: { left: 60, right: 20, bottom: 30, top: 20 },
|
|
|
|
|
xAxis: { type: 'category', data: r.sampleLabels || r.sampleValues.map((_, i) => i + 1) },
|
|
|
|
|
yAxis: { type: 'value', name: r.paramLabel || '' },
|
|
|
|
|
series: [{
|
|
|
|
|
type: 'line', data: r.sampleValues, smooth: false,
|
|
|
|
|
symbol: 'circle', symbolSize: 4,
|
|
|
|
|
markLine: { silent: true, data: markLines, label: { position: 'end', fontSize: 10 } }
|
|
|
|
|
}]
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: r.sampleLabels || r.sampleValues.map((_, i) => i + 1)
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: 'value',
|
|
|
|
|
name: resolveSpcParamLabel(r.paramName || spcQuery.paramName)
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: r.sampleValues,
|
|
|
|
|
smooth: false,
|
|
|
|
|
symbol: 'circle',
|
|
|
|
|
symbolSize: 4,
|
|
|
|
|
markLine: { silent: true, data: markLines, label: { position: 'end', fontSize: 10 } }
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Xbar 均值图 */
|
|
|
|
|
const renderXbarChart = () => {
|
|
|
|
|
if (!xbarChartRef.value) return;
|
|
|
|
|
if (!xbarChartRef.value) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const r = xbarRResult.value;
|
|
|
|
|
if (!r.xbarValues?.length) return;
|
|
|
|
|
if (xbarChart) xbarChart.dispose();
|
|
|
|
|
if (!r.xbarValues?.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (xbarChart) {
|
|
|
|
|
xbarChart.dispose();
|
|
|
|
|
}
|
|
|
|
|
xbarChart = echarts.init(xbarChartRef.value);
|
|
|
|
|
xbarChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
grid: { left: 60, right: 20, bottom: 30, top: 20 },
|
|
|
|
|
xAxis: { type: 'category', data: r.subgroupLabels },
|
|
|
|
|
yAxis: { type: 'value', name: 'Xbar' },
|
|
|
|
|
series: [{
|
|
|
|
|
type: 'line', data: r.xbarValues, symbol: 'circle', symbolSize: 5,
|
|
|
|
|
markLine: {
|
|
|
|
|
silent: true,
|
|
|
|
|
label: { position: 'end', fontSize: 10 },
|
|
|
|
|
data: [
|
|
|
|
|
{ yAxis: r.uclX, name: 'UCL', lineStyle: { color: '#f56c6c', type: 'dashed' } },
|
|
|
|
|
{ yAxis: r.clX, name: 'CL', lineStyle: { color: '#67c23a' } },
|
|
|
|
|
{ yAxis: r.lclX, name: 'LCL', lineStyle: { color: '#f56c6c', type: 'dashed' } }
|
|
|
|
|
]
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: r.xbarValues,
|
|
|
|
|
symbol: 'circle',
|
|
|
|
|
symbolSize: 5,
|
|
|
|
|
markLine: {
|
|
|
|
|
silent: true,
|
|
|
|
|
label: { position: 'end', fontSize: 10 },
|
|
|
|
|
data: [
|
|
|
|
|
{ yAxis: r.uclX, name: 'UCL', lineStyle: { color: '#f56c6c', type: 'dashed' } },
|
|
|
|
|
{ yAxis: r.clX, name: 'CL', lineStyle: { color: '#67c23a' } },
|
|
|
|
|
{ yAxis: r.lclX, name: 'LCL', lineStyle: { color: '#f56c6c', type: 'dashed' } }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** R 极差图 */
|
|
|
|
|
const renderRChart = () => {
|
|
|
|
|
if (!rChartRef.value) return;
|
|
|
|
|
if (!rChartRef.value) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const r = xbarRResult.value;
|
|
|
|
|
if (!r.rValues?.length) return;
|
|
|
|
|
if (rChart) rChart.dispose();
|
|
|
|
|
if (!r.rValues?.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (rChart) {
|
|
|
|
|
rChart.dispose();
|
|
|
|
|
}
|
|
|
|
|
rChart = echarts.init(rChartRef.value);
|
|
|
|
|
rChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
grid: { left: 60, right: 20, bottom: 30, top: 20 },
|
|
|
|
|
xAxis: { type: 'category', data: r.subgroupLabels },
|
|
|
|
|
yAxis: { type: 'value', name: 'R' },
|
|
|
|
|
series: [{
|
|
|
|
|
type: 'line', data: r.rValues, symbol: 'circle', symbolSize: 5,
|
|
|
|
|
markLine: {
|
|
|
|
|
silent: true,
|
|
|
|
|
label: { position: 'end', fontSize: 10 },
|
|
|
|
|
data: [
|
|
|
|
|
{ yAxis: r.uclR, name: 'UCL', lineStyle: { color: '#f56c6c', type: 'dashed' } },
|
|
|
|
|
{ yAxis: r.clR, name: 'CL', lineStyle: { color: '#67c23a' } },
|
|
|
|
|
{ yAxis: r.lclR, name: 'LCL', lineStyle: { color: '#f56c6c', type: 'dashed' } }
|
|
|
|
|
]
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: r.rValues,
|
|
|
|
|
symbol: 'circle',
|
|
|
|
|
symbolSize: 5,
|
|
|
|
|
markLine: {
|
|
|
|
|
silent: true,
|
|
|
|
|
label: { position: 'end', fontSize: 10 },
|
|
|
|
|
data: [
|
|
|
|
|
{ yAxis: r.uclR, name: 'UCL', lineStyle: { color: '#f56c6c', type: 'dashed' } },
|
|
|
|
|
{ yAxis: r.clR, name: 'CL', lineStyle: { color: '#67c23a' } },
|
|
|
|
|
{ yAxis: r.lclR, name: 'LCL', lineStyle: { color: '#f56c6c', type: 'dashed' } }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ==================== 初始化 ====================
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
getTraceList();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** 监听窗口变化自适应图表 */
|
|
|
|
|
window.addEventListener('resize', () => {
|
|
|
|
|
const handleResize = () => {
|
|
|
|
|
histogramChart?.resize();
|
|
|
|
|
runChart?.resize();
|
|
|
|
|
xbarChart?.resize();
|
|
|
|
|
rChart?.resize();
|
|
|
|
|
detailCurveChart?.resize();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
getTraceList();
|
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
window.removeEventListener('resize', handleResize);
|
|
|
|
|
histogramChart?.dispose();
|
|
|
|
|
runChart?.dispose();
|
|
|
|
|
xbarChart?.dispose();
|
|
|
|
|
rChart?.dispose();
|
|
|
|
|
detailCurveChart?.dispose();
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|