|
|
|
@ -49,48 +49,176 @@
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</transition>
|
|
|
|
</transition>
|
|
|
|
|
|
|
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
<!-- 主内容区:左-右分栏 (mix_code.png 布局) -->
|
|
|
|
<template #header>
|
|
|
|
<el-row :gutter="10">
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
<!-- 左侧面板:配方树 (§1.1) -->
|
|
|
|
<el-col :span="1.5">
|
|
|
|
<el-col :span="5">
|
|
|
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['mes:mixTrace:export']">导出</el-button>
|
|
|
|
<el-card shadow="hover" class="tree-panel">
|
|
|
|
</el-col>
|
|
|
|
<template #header><span>配方树</span></template>
|
|
|
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getTraceList" />
|
|
|
|
<el-input v-model="treeFilterText" placeholder="搜索配方" clearable size="small" class="mb-2" />
|
|
|
|
</el-row>
|
|
|
|
<el-scrollbar height="340px">
|
|
|
|
</template>
|
|
|
|
<el-tree
|
|
|
|
|
|
|
|
ref="recipeTreeRef"
|
|
|
|
|
|
|
|
:data="recipeTreeData"
|
|
|
|
|
|
|
|
:filter-node-method="filterTreeNode"
|
|
|
|
|
|
|
|
node-key="id"
|
|
|
|
|
|
|
|
highlight-current
|
|
|
|
|
|
|
|
default-expand-all
|
|
|
|
|
|
|
|
:props="{ label: 'label', children: 'children' }"
|
|
|
|
|
|
|
|
@node-click="handleTreeNodeClick"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</el-scrollbar>
|
|
|
|
|
|
|
|
<el-divider />
|
|
|
|
|
|
|
|
<div class="px-1">
|
|
|
|
|
|
|
|
<div class="text-sm mb-1 font-bold">托盘条码</div>
|
|
|
|
|
|
|
|
<el-input v-model="trayBarcode" clearable size="small" placeholder="扫描或输入条码" />
|
|
|
|
|
|
|
|
<el-button type="primary" size="small" class="mt-2 w-full" @click="handleTrayTrace">耗用本车生产追溯</el-button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table v-loading="traceLoading" :data="traceList" highlight-current-row border stripe>
|
|
|
|
<!-- 右侧面板:列表 + 底部详情 (§1.1) -->
|
|
|
|
<el-table-column label="计划编号" prop="planCode" min-width="140" />
|
|
|
|
<el-col :span="19">
|
|
|
|
<el-table-column label="明细编号" prop="planDetailCode" min-width="130" />
|
|
|
|
<el-card shadow="hover">
|
|
|
|
<el-table-column label="生产条码" prop="productionBarcode" min-width="130" />
|
|
|
|
<template #header>
|
|
|
|
<el-table-column label="配方编码" prop="recipeCode" min-width="120" />
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
|
|
<el-table-column label="机台" prop="machineName" min-width="100" />
|
|
|
|
<el-col :span="1.5">
|
|
|
|
<el-table-column label="物料" prop="materialName" min-width="120" />
|
|
|
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['mes:mixTrace:export']">导出</el-button>
|
|
|
|
<el-table-column label="班次" prop="shiftName" min-width="90" />
|
|
|
|
</el-col>
|
|
|
|
<el-table-column label="班组" prop="classTeamName" min-width="90" />
|
|
|
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getTraceList" />
|
|
|
|
<el-table-column label="计划数" prop="planAmount" min-width="90" align="right" />
|
|
|
|
</el-row>
|
|
|
|
<el-table-column label="完成数" prop="completeAmount" min-width="90" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="密炼车次" prop="trainNumber" min-width="90" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="状态" prop="recipeState" min-width="80" align="center">
|
|
|
|
|
|
|
|
<template #default="{ row }"><dict-tag :options="recipe_state" :value="row.recipeState" /></template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="开始生产时间" prop="realBeginTime" min-width="160" />
|
|
|
|
|
|
|
|
<el-table-column label="创建时间" prop="createTime" min-width="160" />
|
|
|
|
|
|
|
|
<el-table-column label="操作" fixed="right" width="150" align="center">
|
|
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
|
|
<el-button link type="primary" @click.stop="openDetail(row)">本车耗用追溯</el-button>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pagination
|
|
|
|
<!-- 列表字段逐列对齐 mix_code.png (§1.1) -->
|
|
|
|
v-show="traceTotal > 0"
|
|
|
|
<el-table ref="traceTableRef" v-loading="traceLoading" :data="traceList" highlight-current-row border stripe @current-change="handleRowSelect" max-height="400">
|
|
|
|
:total="traceTotal"
|
|
|
|
<el-table-column label="机台" prop="machineName" min-width="100" />
|
|
|
|
v-model:page="traceQuery.pageNum"
|
|
|
|
<el-table-column label="班次" prop="shiftName" min-width="80" />
|
|
|
|
v-model:limit="traceQuery.pageSize"
|
|
|
|
<el-table-column label="班组" prop="classTeamName" min-width="80" />
|
|
|
|
@pagination="getTraceList"
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="120" show-overflow-tooltip />
|
|
|
|
/>
|
|
|
|
<el-table-column label="计划编号" prop="planCode" min-width="130" show-overflow-tooltip />
|
|
|
|
</el-card>
|
|
|
|
<el-table-column label="车次号" prop="trainNumber" min-width="80" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="开始生产时间" prop="realBeginTime" min-width="160" />
|
|
|
|
|
|
|
|
<el-table-column label="设量" prop="totalWeight" min-width="80" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="实量" min-width="80" align="right">
|
|
|
|
|
|
|
|
<template #default="{ row }">{{ row.realWeight != null ? Number(row.realWeight).toFixed(1) : '-' }}</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="检验结果" min-width="90" align="center">
|
|
|
|
|
|
|
|
<template #default="{ row }">{{ row.testResult || '-' }}</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="累计车次" prop="totalTrainNo" min-width="90" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="生产状态" prop="planDetailStatus" min-width="90" align="center" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pagination v-show="traceTotal > 0" :total="traceTotal" v-model:page="traceQuery.pageNum" v-model:limit="traceQuery.pageSize" @pagination="getTraceList" />
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部 Tab:每车基本信息 / 每车明细信息 (§1.1 底部双Tab) -->
|
|
|
|
|
|
|
|
<el-card shadow="hover" class="mt-[10px]" v-if="selectedRow">
|
|
|
|
|
|
|
|
<el-tabs v-model="detailTab" type="border-card">
|
|
|
|
|
|
|
|
<!-- 每车基本信息 Tab:轻量摘要 -->
|
|
|
|
|
|
|
|
<el-tab-pane label="每车基本信息" name="basic">
|
|
|
|
|
|
|
|
<el-descriptions :column="6" border size="small" v-if="summary.recipeId" class="trace-summary">
|
|
|
|
|
|
|
|
<el-descriptions-item label="配方编码">{{ summary.recipeCode || recipeInfo.recipeCode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="计划编号">{{ summary.planCode || recipeInfo.planCode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="生产条码">{{ summary.productionBarcode || recipeInfo.productionBarcode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="机台">{{ summary.machineName || recipeInfo.machineName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="物料">{{ summary.materialName || recipeInfo.materialName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="班次">{{ summary.shiftName || recipeInfo.shiftName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="班组">{{ summary.classTeamName || recipeInfo.classTeamName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="计划数">{{ n(summary.planAmount) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="设定重量">{{ n(summary.settingWeight) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="完成重量">{{ n(summary.completedWeight) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="每车能量">{{ n(summary.eachCarEnergy) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="密炼车次">{{ summary.mixingTrainNo ?? '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="累计车次">{{ summary.totalTrainNo ?? '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="超差报警">{{ summary.overToleranceAlarm || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="密炼状态">{{ summary.mixingStatus || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="检验结果">{{ summary.testResult || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="排胶温度">{{ n(summary.dischargeTemp) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="排胶功率">{{ n(summary.dischargePower) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="排胶能量">{{ n(summary.dischargeEnergy) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="混炼时间">{{ n(summary.mixingTime) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="消耗时间">{{ n(summary.consumeTime) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="间隔时间">{{ n(summary.intervalTime) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="配方时间">{{ summary.recipeTime ?? '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="开始生产时间">{{ summary.beginProduceTime || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
<el-empty v-else description="加载中..." :image-size="60" />
|
|
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 每车明细信息 Tab:完整追溯详情 (§1.2 mix.jpg) -->
|
|
|
|
|
|
|
|
<el-tab-pane label="每车明细信息" name="detail" lazy>
|
|
|
|
|
|
|
|
<div v-if="detailData" class="trace-detail-content">
|
|
|
|
|
|
|
|
<el-row :gutter="8" class="mb-[8px]">
|
|
|
|
|
|
|
|
<el-col :span="6" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>本车耗用追溯树</template>
|
|
|
|
|
|
|
|
<el-tree :data="treeData" node-key="id" default-expand-all :props="{ label: 'label', children: 'children' }" style="max-height: 300px; overflow: auto" />
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="9" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>称量信息</template>
|
|
|
|
|
|
|
|
<el-table :data="usageDisplayList" border stripe size="small" max-height="300">
|
|
|
|
|
|
|
|
<el-table-column label="序号" prop="weightSeq" width="50" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="类别" prop="categoryName" min-width="80" />
|
|
|
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="100" show-overflow-tooltip />
|
|
|
|
|
|
|
|
<el-table-column label="设量" prop="setWeight" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="实量" prop="actualWeight" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="差值" prop="diffWeight" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="公差" prop="tolerance" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="超差" width="55" align="center">
|
|
|
|
|
|
|
|
<template #default="{ row }">{{ row.overToleranceFlag === '1' ? '是' : row.overToleranceFlag === '0' ? '否' : '-' }}</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="称量状态" prop="actionStatus" width="80" align="center" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="9" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>混炼信息</template>
|
|
|
|
|
|
|
|
<el-table :data="stepDisplayList" border stripe size="small" max-height="300">
|
|
|
|
|
|
|
|
<el-table-column label="步骤" prop="mixId" width="50" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="条件名称" prop="condName" min-width="90" />
|
|
|
|
|
|
|
|
<el-table-column label="动作名称" prop="actName" min-width="90" />
|
|
|
|
|
|
|
|
<el-table-column label="时间" prop="mixingTime" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="温度" prop="mixingTemp" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="能量" prop="mixingEnergy" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="功率" prop="mixingPower" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="压力" prop="mixingPress" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="转速" prop="mixingSpeed" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="设时" prop="setTime" width="55" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="设温" prop="setTemp" width="55" align="right" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
<el-row :gutter="8">
|
|
|
|
|
|
|
|
<el-col :span="10" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>批次信息</template>
|
|
|
|
|
|
|
|
<el-table :data="batchList" border stripe size="small" max-height="260">
|
|
|
|
|
|
|
|
<el-table-column label="批次" prop="batchCode" min-width="130" />
|
|
|
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="120" />
|
|
|
|
|
|
|
|
<el-table-column label="入库时间" prop="instockTime" min-width="150" />
|
|
|
|
|
|
|
|
<el-table-column label="供应商" prop="supplierName" min-width="100" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
<el-col :span="14" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>历史密炼曲线</template>
|
|
|
|
|
|
|
|
<div ref="detailCurveChartRef" style="height: 260px" />
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<el-empty v-else description="加载中..." :image-size="60" />
|
|
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
</el-tabs>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
</el-tab-pane>
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
|
|
<el-tab-pane label="SPC分析" name="spc">
|
|
|
|
<el-tab-pane label="SPC分析" name="spc">
|
|
|
|
@ -192,120 +320,7 @@
|
|
|
|
</el-tab-pane>
|
|
|
|
</el-tab-pane>
|
|
|
|
</el-tabs>
|
|
|
|
</el-tabs>
|
|
|
|
|
|
|
|
|
|
|
|
<el-drawer
|
|
|
|
<!-- Drawer 已移除,详情内容已迁移至底部 Tab(每车基本信息/每车明细信息) -->
|
|
|
|
v-model="detailVisible"
|
|
|
|
|
|
|
|
class="mix-trace-drawer"
|
|
|
|
|
|
|
|
title="密炼追溯详情"
|
|
|
|
|
|
|
|
size="92%"
|
|
|
|
|
|
|
|
direction="rtl"
|
|
|
|
|
|
|
|
destroy-on-close
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<template v-if="detailData">
|
|
|
|
|
|
|
|
<div class="trace-one-page">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="mb-[8px]">
|
|
|
|
|
|
|
|
<template #header>配方基础信息与追溯摘要</template>
|
|
|
|
|
|
|
|
<el-descriptions :column="6" border size="small" class="trace-summary">
|
|
|
|
|
|
|
|
<el-descriptions-item label="配方编码">{{ summary.recipeCode || recipeInfo.recipeCode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="计划编号">{{ summary.planCode || recipeInfo.planCode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="明细编号">{{ summary.planDetailCode || recipeInfo.planDetailCode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="生产条码">{{ summary.productionBarcode || recipeInfo.productionBarcode || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="机台">{{ summary.machineName || recipeInfo.machineName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="物料">{{ summary.materialName || recipeInfo.materialName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="班次">{{ summary.shiftName || recipeInfo.shiftName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="班组">{{ summary.classTeamName || recipeInfo.classTeamName || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="计划数">{{ n(summary.planAmount) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="设定重量">{{ n(summary.settingWeight) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="完成重量">{{ n(summary.completedWeight) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="每车能量">{{ n(summary.eachCarEnergy) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="密炼车次">{{ summary.mixingTrainNo ?? '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="累计车次">{{ summary.totalTrainNo ?? '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="超差报警">{{ summary.overToleranceAlarm || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="密炼结果">{{ summary.mixingStatus || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="排胶温度">{{ n(summary.dischargeTemp) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="排胶功率">{{ n(summary.dischargePower) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="排胶能量">{{ n(summary.dischargeEnergy) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="混炼时间">{{ n(summary.mixingTime) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="消耗时间">{{ n(summary.consumeTime) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="间隔时间">{{ n(summary.intervalTime) }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="开始生产时间">{{ summary.beginProduceTime || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
<el-descriptions-item label="结束生产时间">{{ summary.endProduceTime || '-' }}</el-descriptions-item>
|
|
|
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="8" class="mb-[8px]">
|
|
|
|
|
|
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="6" :span="6" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>本车耗用追溯树</template>
|
|
|
|
|
|
|
|
<el-tree
|
|
|
|
|
|
|
|
:data="treeData"
|
|
|
|
|
|
|
|
node-key="id"
|
|
|
|
|
|
|
|
default-expand-all
|
|
|
|
|
|
|
|
:props="{ label: 'label', children: 'children' }"
|
|
|
|
|
|
|
|
class="mix-trace-tree"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="8" :span="8" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>称量信息(追溯 + 配方字段)</template>
|
|
|
|
|
|
|
|
<el-table :data="usageDisplayList" border stripe size="small" max-height="350">
|
|
|
|
|
|
|
|
<el-table-column label="序号" prop="weightSeq" width="64" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="料别" prop="categoryName" min-width="90" />
|
|
|
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="130" />
|
|
|
|
|
|
|
|
<el-table-column label="设量" prop="setWeight" min-width="80" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="实量" prop="actualWeight" min-width="80" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="差值" prop="diffWeight" min-width="80" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="公差" prop="tolerance" min-width="80" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="数量状态" prop="quantityStatus" min-width="90" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="控制方式" prop="controlMode" min-width="90" align="center" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="10" :span="10" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>混炼信息(追溯 + 配方字段)</template>
|
|
|
|
|
|
|
|
<el-table :data="stepDisplayList" border stripe size="small" max-height="350">
|
|
|
|
|
|
|
|
<el-table-column label="步骤" prop="mixId" width="64" align="center" />
|
|
|
|
|
|
|
|
<el-table-column label="条件名称" prop="condName" min-width="110" />
|
|
|
|
|
|
|
|
<el-table-column label="动作名称" prop="actName" min-width="110" />
|
|
|
|
|
|
|
|
<el-table-column label="时间" prop="mixingTime" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="温度" prop="mixingTemp" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="能量" prop="mixingEnergy" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="功率" prop="mixingPower" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="压力" prop="mixingPress" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="转速" prop="mixingSpeed" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="设时" prop="setTime" width="70" align="right" />
|
|
|
|
|
|
|
|
<el-table-column label="设温" prop="setTemp" width="70" align="right" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="8">
|
|
|
|
|
|
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="10" :span="10" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>批次信息</template>
|
|
|
|
|
|
|
|
<el-table :data="batchList" border stripe size="small" max-height="300">
|
|
|
|
|
|
|
|
<el-table-column label="批次" prop="batchCode" min-width="130" />
|
|
|
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="120" />
|
|
|
|
|
|
|
|
<el-table-column label="入库时间" prop="instockTime" min-width="150" />
|
|
|
|
|
|
|
|
<el-table-column label="供应商" prop="supplierName" min-width="110" />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="14" :span="14" class="trace-panel-col">
|
|
|
|
|
|
|
|
<el-card shadow="never" class="trace-panel-card">
|
|
|
|
|
|
|
|
<template #header>历史密炼曲线</template>
|
|
|
|
|
|
|
|
<div ref="detailCurveChartRef" style="height: 300px" />
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-drawer>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
@ -331,12 +346,24 @@ const { recipe_state, mix_trace_spc_param } = toRefs<any>(proxy?.useDict('recipe
|
|
|
|
const activeTab = ref('trace');
|
|
|
|
const activeTab = ref('trace');
|
|
|
|
const showSearch = ref(true);
|
|
|
|
const showSearch = ref(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 当前选中行(列表点击后触发详情加载) */
|
|
|
|
|
|
|
|
const selectedRow = ref<any>(null);
|
|
|
|
|
|
|
|
/** 底部详情Tab:basic=每车基本信息, detail=每车明细信息 */
|
|
|
|
|
|
|
|
const detailTab = ref('basic');
|
|
|
|
|
|
|
|
/** 配方树数据(从列表按 recipeId 分组构建) */
|
|
|
|
|
|
|
|
const recipeTreeData = ref<any[]>([]);
|
|
|
|
|
|
|
|
const recipeTreeRef = ref();
|
|
|
|
|
|
|
|
const traceTableRef = ref();
|
|
|
|
|
|
|
|
const treeFilterText = ref('');
|
|
|
|
|
|
|
|
const trayBarcode = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
const traceLoading = ref(false);
|
|
|
|
const traceLoading = ref(false);
|
|
|
|
const traceList = ref<any[]>([]);
|
|
|
|
const traceList = ref<any[]>([]);
|
|
|
|
const traceTotal = ref(0);
|
|
|
|
const traceTotal = ref(0);
|
|
|
|
const traceDateRange = ref<string[]>([]);
|
|
|
|
const traceDateRange = ref<string[]>([]);
|
|
|
|
const traceQueryFormRef = ref();
|
|
|
|
const traceQueryFormRef = ref();
|
|
|
|
const traceQuery = reactive<MixTraceQuery>({
|
|
|
|
const traceQuery = reactive<MixTraceQuery>({
|
|
|
|
|
|
|
|
recipeId: undefined,
|
|
|
|
recipeCode: undefined,
|
|
|
|
recipeCode: undefined,
|
|
|
|
planCode: undefined,
|
|
|
|
planCode: undefined,
|
|
|
|
planDetailCode: undefined,
|
|
|
|
planDetailCode: undefined,
|
|
|
|
@ -383,8 +410,17 @@ const handleTraceQuery = () => {
|
|
|
|
const resetTraceQuery = () => {
|
|
|
|
const resetTraceQuery = () => {
|
|
|
|
traceQueryFormRef.value?.resetFields();
|
|
|
|
traceQueryFormRef.value?.resetFields();
|
|
|
|
traceDateRange.value = [];
|
|
|
|
traceDateRange.value = [];
|
|
|
|
|
|
|
|
// 清除配方树点击设置的 recipeId 和托盘条码
|
|
|
|
|
|
|
|
traceQuery.recipeId = undefined;
|
|
|
|
|
|
|
|
traceQuery.productionBarcode = undefined;
|
|
|
|
|
|
|
|
trayBarcode.value = '';
|
|
|
|
traceQuery.pageNum = 1;
|
|
|
|
traceQuery.pageNum = 1;
|
|
|
|
traceQuery.pageSize = 20;
|
|
|
|
traceQuery.pageSize = 20;
|
|
|
|
|
|
|
|
// 清除选中状态
|
|
|
|
|
|
|
|
selectedRow.value = null;
|
|
|
|
|
|
|
|
detailData.value = null;
|
|
|
|
|
|
|
|
// 清除配方树高亮
|
|
|
|
|
|
|
|
recipeTreeRef.value?.setCurrentKey(null);
|
|
|
|
handleTraceQuery();
|
|
|
|
handleTraceQuery();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@ -393,7 +429,6 @@ const handleExport = () => {
|
|
|
|
download('/mes/mixTrace/export', { ...traceQuery }, `mix_trace_${Date.now()}.xlsx`);
|
|
|
|
download('/mes/mixTrace/export', { ...traceQuery }, `mix_trace_${Date.now()}.xlsx`);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const detailVisible = ref(false);
|
|
|
|
|
|
|
|
const detailData = ref<MixTraceDetailVO | null>(null);
|
|
|
|
const detailData = ref<MixTraceDetailVO | null>(null);
|
|
|
|
const detailCurveChartRef = ref<HTMLElement>();
|
|
|
|
const detailCurveChartRef = ref<HTMLElement>();
|
|
|
|
let detailCurveChart: echarts.ECharts | null = null;
|
|
|
|
let detailCurveChart: echarts.ECharts | null = null;
|
|
|
|
@ -421,7 +456,7 @@ const usageDisplayList = computed<any[]>(() => {
|
|
|
|
return recipeWeightList.value.map((item: any, index: number) => ({
|
|
|
|
return recipeWeightList.value.map((item: any, index: number) => ({
|
|
|
|
weightSeq: item.weightSeq ?? index + 1,
|
|
|
|
weightSeq: item.weightSeq ?? index + 1,
|
|
|
|
categoryName: item.weightType || '-',
|
|
|
|
categoryName: item.weightType || '-',
|
|
|
|
materialName: item.childCode || '-',
|
|
|
|
materialName: item.materialName || item.childCode || '-',
|
|
|
|
setWeight: item.setWeight,
|
|
|
|
setWeight: item.setWeight,
|
|
|
|
actualWeight: '-',
|
|
|
|
actualWeight: '-',
|
|
|
|
tolerance: item.errorAllow,
|
|
|
|
tolerance: item.errorAllow,
|
|
|
|
@ -468,9 +503,69 @@ const curveDisplayList = computed<any[]>(() => {
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const openDetail = async (row: any) => {
|
|
|
|
/** 点击列表行时加载追溯详情(底部Tab展示,非Drawer) */
|
|
|
|
|
|
|
|
const handleRowSelect = (row: any) => {
|
|
|
|
|
|
|
|
if (!row) {
|
|
|
|
|
|
|
|
selectedRow.value = null;
|
|
|
|
|
|
|
|
detailData.value = null;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
selectedRow.value = row;
|
|
|
|
|
|
|
|
loadDetail(row);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 配方树节点点击:按 recipeId 过滤列表 */
|
|
|
|
|
|
|
|
const handleTreeNodeClick = (node: any) => {
|
|
|
|
|
|
|
|
if (node.recipeId) {
|
|
|
|
|
|
|
|
traceQuery.recipeId = node.recipeId;
|
|
|
|
|
|
|
|
handleTraceQuery();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 配方树过滤 */
|
|
|
|
|
|
|
|
const filterTreeNode = (value: string, data: any) => {
|
|
|
|
|
|
|
|
if (!value) return true;
|
|
|
|
|
|
|
|
return (data.label || '').toLowerCase().includes(value.toLowerCase());
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 托盘条码追溯 */
|
|
|
|
|
|
|
|
const handleTrayTrace = () => {
|
|
|
|
|
|
|
|
if (!trayBarcode.value) {
|
|
|
|
|
|
|
|
proxy?.$modal?.msgWarning?.('请输入托盘条码');
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
traceQuery.productionBarcode = trayBarcode.value;
|
|
|
|
|
|
|
|
handleTraceQuery();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 从列表数据构建配方树(父=配方编码+物料名,子=该配方下的记录) */
|
|
|
|
|
|
|
|
const buildRecipeTree = (list: any[]) => {
|
|
|
|
|
|
|
|
const grouped = new Map<string, { label: string; recipeId: any; children: any[] }>();
|
|
|
|
|
|
|
|
for (const item of list) {
|
|
|
|
|
|
|
|
const key = String(item.recipeId);
|
|
|
|
|
|
|
|
if (!grouped.has(key)) {
|
|
|
|
|
|
|
|
grouped.set(key, {
|
|
|
|
|
|
|
|
label: `${item.recipeCode || ''} (${item.materialName || ''})`,
|
|
|
|
|
|
|
|
recipeId: item.recipeId,
|
|
|
|
|
|
|
|
children: []
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
grouped.get(key)!.children.push({
|
|
|
|
|
|
|
|
id: `${key}_${item.planDetailId || item.trainNumber || Math.random()}`,
|
|
|
|
|
|
|
|
label: `车次${item.trainNumber ?? '-'} ${item.planCode || ''}`,
|
|
|
|
|
|
|
|
recipeId: item.recipeId,
|
|
|
|
|
|
|
|
planDetailId: item.planDetailId
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
recipeTreeData.value = Array.from(grouped.values()).map((g, i) => ({
|
|
|
|
|
|
|
|
id: `recipe_${g.recipeId || i}`,
|
|
|
|
|
|
|
|
...g
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 加载追溯详情到底部Tab */
|
|
|
|
|
|
|
|
const loadDetail = async (row: any) => {
|
|
|
|
const requestSeq = ++detailRequestSeq;
|
|
|
|
const requestSeq = ++detailRequestSeq;
|
|
|
|
detailVisible.value = true;
|
|
|
|
|
|
|
|
detailData.value = null;
|
|
|
|
detailData.value = null;
|
|
|
|
|
|
|
|
|
|
|
|
const q: MixTraceDetailQuery = {
|
|
|
|
const q: MixTraceDetailQuery = {
|
|
|
|
@ -485,27 +580,17 @@ const openDetail = async (row: any) => {
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const res = await getMixTraceDetail(row.recipeId, q);
|
|
|
|
const res = await getMixTraceDetail(row.recipeId, q);
|
|
|
|
if (requestSeq !== detailRequestSeq) {
|
|
|
|
if (requestSeq !== detailRequestSeq) return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!res?.data) {
|
|
|
|
if (!res?.data) {
|
|
|
|
proxy?.$modal?.msgWarning?.('未查询到追溯详情');
|
|
|
|
proxy?.$modal?.msgWarning?.('未查询到追溯详情');
|
|
|
|
detailCurveChart?.dispose();
|
|
|
|
|
|
|
|
detailCurveChart = null;
|
|
|
|
|
|
|
|
detailVisible.value = false;
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
detailData.value = res.data;
|
|
|
|
detailData.value = res.data;
|
|
|
|
await nextTick();
|
|
|
|
await nextTick();
|
|
|
|
renderDetailCurve();
|
|
|
|
renderDetailCurve();
|
|
|
|
} catch {
|
|
|
|
} catch {
|
|
|
|
if (requestSeq !== detailRequestSeq) {
|
|
|
|
if (requestSeq !== detailRequestSeq) return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
detailData.value = null;
|
|
|
|
detailData.value = null;
|
|
|
|
detailCurveChart?.dispose();
|
|
|
|
|
|
|
|
detailCurveChart = null;
|
|
|
|
|
|
|
|
detailVisible.value = false;
|
|
|
|
|
|
|
|
proxy?.$modal?.msgError?.('加载追溯详情失败');
|
|
|
|
proxy?.$modal?.msgError?.('加载追溯详情失败');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@ -805,17 +890,32 @@ watch(
|
|
|
|
{ immediate: true }
|
|
|
|
{ immediate: true }
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
watch(detailVisible, (visible) => {
|
|
|
|
/** 列表数据变化时构建配方树 */
|
|
|
|
if (!visible) {
|
|
|
|
watch(traceList, (list) => {
|
|
|
|
detailData.value = null;
|
|
|
|
buildRecipeTree(list);
|
|
|
|
detailCurveChart?.dispose();
|
|
|
|
});
|
|
|
|
detailCurveChart = null;
|
|
|
|
|
|
|
|
|
|
|
|
/** 配方树搜索过滤 */
|
|
|
|
|
|
|
|
watch(treeFilterText, (val) => {
|
|
|
|
|
|
|
|
recipeTreeRef.value?.filter(val);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 切换到明细Tab时渲染曲线(lazy tab-pane 中 ref 需延迟绑定) */
|
|
|
|
|
|
|
|
watch(detailTab, async (tab) => {
|
|
|
|
|
|
|
|
if (tab === 'detail' && detailData.value) {
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
|
|
renderDetailCurve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
onMounted(() => {
|
|
|
|
getTraceList();
|
|
|
|
getTraceList();
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
|
|
|
|
// 重置查询时清除选中状态
|
|
|
|
|
|
|
|
watch(() => traceQuery.pageNum, () => {
|
|
|
|
|
|
|
|
selectedRow.value = null;
|
|
|
|
|
|
|
|
detailData.value = null;
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
@ -829,39 +929,31 @@ onBeforeUnmount(() => {
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
<style scoped>
|
|
|
|
.text-center {
|
|
|
|
/* 配方树面板 */
|
|
|
|
text-align: center;
|
|
|
|
.tree-panel :deep(.el-card__body) {
|
|
|
|
|
|
|
|
padding: 8px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.trace-one-page .trace-panel-col {
|
|
|
|
/* 详情面板 */
|
|
|
|
|
|
|
|
.trace-detail-content .trace-panel-col {
|
|
|
|
display: flex;
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.trace-one-page .trace-panel-card {
|
|
|
|
.trace-detail-content .trace-panel-card {
|
|
|
|
width: 100%;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-trace-tree {
|
|
|
|
.trace-detail-content :deep(.el-card__header) {
|
|
|
|
min-height: 300px;
|
|
|
|
|
|
|
|
max-height: 350px;
|
|
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.mix-trace-drawer :deep(.el-drawer__body) {
|
|
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.mix-trace-drawer :deep(.el-card__header) {
|
|
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
padding: 8px 12px;
|
|
|
|
font-weight: 600;
|
|
|
|
font-weight: 600;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-trace-drawer :deep(.el-card__body) {
|
|
|
|
.trace-detail-content :deep(.el-card__body) {
|
|
|
|
padding: 8px;
|
|
|
|
padding: 8px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-trace-drawer :deep(.el-descriptions__label) {
|
|
|
|
.trace-summary :deep(.el-descriptions__label) {
|
|
|
|
width: 98px;
|
|
|
|
width: 98px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</style>
|
|
|
|
|