@@ -6,6 +6,7 @@
width = "1200px"
@register ="registerModal"
@ok ="handleSubmit"
@ visible -change = " onModalVisibleChange "
>
< BasicForm @register ="registerForm" >
< template # prodEquipmentPicker = "{ model, field }" >
@@ -25,7 +26,15 @@
< / BasicForm >
< template v-if = "useNewDetail" >
< a -divider orientation = "left" > 数据标准明细 < / a-divider >
< div class = "detail-section" >
< div class = "detail-section__header" >
< span class = "detail-section__accent" / >
< div class = "detail-section__titles" >
< span class = "detail-section__title" > 数据标准明细 < / span >
< span class = "detail-section__desc" > 实验标准数据点及上下限快照 < / span >
< / div >
< / div >
< div class = "detail-section__body" >
< JVxeTable
v-if = "tableReady"
row -number
@@ -39,8 +48,18 @@
:dataSource = "stdLineDataSource"
disabled
/ >
< / div >
< / div >
< a- divider orientation = "left" > 试验结果明细 < / a-divider >
< div class = "detail-section" >
< div class = "detail-section__header" >
< span class = "detail-section__accent detail-section__accent--green" / >
< div class = "detail-section__titles" >
< span class = "detail-section__title" > 试验结果明细 < / span >
< span class = "detail-section__desc" > 各次试验检测值与单次检验结果 < / span >
< / div >
< / div >
< div class = "detail-section__body" >
< JVxeTable
v-if = "tableReady"
row -number
@@ -54,22 +73,46 @@
:dataSource = "rawLineDataSource"
:disabled = "isDetail"
/ >
< / div >
< / div >
< a- divider orientation = "left" > 曲线图 < / a-divider >
< div class = "detail-section detail-section--chart" >
< div class = "detail-section__header" >
< span class = "detail-section__accent detail-section__accent--orange" / >
< div class = "detail-section__titles" >
< span class = "detail-section__title" > 曲线图明细 < / span >
< span class = "detail-section__desc" > 密炼过程温度与扭矩曲线 < / span >
< / div >
< / div >
< div class = "detail-section__body detail-section__body--chart" >
< a-row :gutter = "16" >
< a-col :span = "12" >
< div class = "chart-title " > 温度曲线 ( 上模 / 下模 ) < / div >
< div class = "chart-card " >
< div class = "chart-card__title" > 温度曲线 ( 上模 / 下模 ) < / div >
< div ref = "tempChartRef" class = "chart-box" > < / div >
< / div >
< / a-col >
< a-col :span = "12" >
< div class = "chart-title " > S '(dNm) 曲线</div>
< div class = "chart-card " >
< div class = "chart-card__title" > S '(dNm) 曲线</div>
<div ref="torqueChartRef" class="chart-box"></div>
</div>
</a-col>
</a-row>
</div>
</div>
</template>
<template v-else>
<a- divider orientation="left">检验明细(历史数据)</a-divider >
<div class="detail-section" >
<div class="detail-section__header">
<span class="detail-section__accent detail-section__accent--gray" />
<div class="detail-section__titles">
<span class="detail-section__title">检验明细(历史数据)</span>
<span class="detail-section__desc">旧版汇总检验数据</span>
</div>
</div>
<div class="detail-section__body">
<JVxeTable
v-if="tableReady"
row-number
@@ -83,6 +126,8 @@
:dataSource="lineDataSource"
:disabled="isDetail"
/>
</div>
</div>
</template>
<MesXslEquipmentLedgerSelectModal @register="registerLedgerModal" @select="onLedgerSelect" />
@@ -102,7 +147,13 @@
stdLineJVxeColumns,
rawLineJVxeColumns,
} from ' . . / MesXslRubberQuickTestRecord . data ';
import { saveOrUpdate, queryById, queryChartPointListByRecordId } from ' . . / MesXslRubberQuickTestRecord . api ';
import {
saveOrUpdate,
queryById,
queryChartPointListByRecordId,
queryStdLineListByRecordId,
queryRawLineListByRecordId,
} from ' . . / MesXslRubberQuickTestRecord . api ';
import MesXslEquipmentLedgerSelectModal from ' / @ / views / xslmes / mesXslEquipInspectConfig / components / MesXslEquipmentLedgerSelectModal . vue ';
const emit = defineEmits([' register ', ' success ']);
@@ -135,6 +186,35 @@
const [registerLedgerModal, { openModal: openLedgerModal }] = useModal();
function unwrapApiList(payload: unknown): Recordable[] {
if (Array.isArray(payload)) return payload;
if (payload && typeof payload === ' object ') {
const result = (payload as Recordable).result;
if (Array.isArray(result)) return result;
}
return [];
}
function unwrapApiRecord(payload: unknown): Recordable {
if (payload && typeof payload === ' object ' && (payload as Recordable).id != null) {
return payload as Recordable;
}
if (payload && typeof payload === ' object ' && (payload as Recordable).result) {
return ((payload as Recordable).result ?? {}) as Recordable;
}
return (payload ?? {}) as Recordable;
}
function normalizeChartPoint(point: Recordable): Recordable {
return {
sortNo: point.sortNo ?? point.sort_no ?? 0,
timeMin: point.timeMin ?? point.time_min,
upperTemp: point.upperTemp ?? point.upper_temp,
lowerTemp: point.lowerTemp ?? point.lower_temp,
torqueS: point.torqueS ?? point.torque_s,
};
}
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
tableReady.value = false;
stdLineDataSource.value = [];
@@ -149,9 +229,9 @@
if (data?.record?.id) {
detailLoading.value = true;
const recordId = data.record.id as string;
try {
const mainRaw = await queryById({ id: data. record.i d });
const m = (mainRaw as any)?.id != null ? mainRaw : (mainRaw as any)?.result ?? mainRaw;
const m = unwrapApiRecord( await queryById({ id: recordI d })) ;
const patch: Recordable = { ...m };
if (data?.showFooter && !patch.inspectorRealname && !patch.inspectorUserId) {
const user = userStore.getUserInfo || {};
@@ -161,22 +241,35 @@
}
await setFieldsValue(patch);
cons t stdLines = m?.stdLineList ?? [] ;
cons t rawLines = m?.rawLineList ?? [] ;
let chartPo int s = m?.chartPo int List ?? [] ;
const legacyLines = m?.lineList ?? [];
le t stdLines = unwrapApiList( m?.stdLineList) ;
le t rawLines = unwrapApiList( m?.rawLineList) ;
const legacyL ine s = unwrapApiList(m?.l ine List) ;
if (stdLines.length > 0 || rawLines.length > 0 || chartPoints.length > 0 ) {
if (! stdLines.length) {
try {
stdLines = unwrapApiList(await queryStdLineListByRecordId({ id: recordId }));
} catch (_) {
stdLines = [];
}
}
if (!rawLines.length) {
try {
rawLines = unwrapApiList(await queryRawLineListByRecordId({ id: recordId }));
} catch (_) {
rawLines = [];
}
}
if (stdLines.length > 0 || rawLines.length > 0) {
useNewDetail.value = true;
stdLineDataSource.value = stdLines;
rawLineDataSource.value = rawLines;
if (!chartPoints.length && data?.record?.id) {
let chartPoints: Recordable[] = [];
try {
const chartRes = await queryChartPointListByRecordId({ id: data. record.i d });
chartPoints = Array.isArray(chartRes) ? chartRes : (chartRes as any)?.result ?? [];
chartPoints = unwrapApiList( await queryChartPointListByRecordId({ id: recordI d })).map(normalizeChartPoint) ;
} catch (_) {
chartPoints = [] ;
}
chartPoints = unwrapApiList(m?.chartPointList).map(normalizeChartPoint) ;
}
chartPointDataSource.value = chartPoints;
} else {
@@ -195,19 +288,48 @@
async function scheduleRenderCharts(points: Recordable[]) {
await nextTick();
await nextTick();
await new Promise<void>((resolve) => {
window.setTimeout(() => {
renderCharts(points);
resizeTempChart();
resizeTorqueChart();
}, 120 );
resolve( );
}, 280);
});
}
function onModalVisibleChange(visible: boolean) {
if (visible && useNewDetail.value) {
scheduleRenderCharts(chartPointDataSource.value);
}
}
watch(useNewDetail, async (visible) => {
if (visible && chartPointDataSource.value.length ) {
if (visible) {
await scheduleRenderCharts(chartPointDataSource.value);
}
});
watch(
() => [useNewDetail.value, tempChartRef.value, torqueChartRef.value] as const,
([visible, tempEl, torqueEl]) => {
if (visible && tempEl && torqueEl) {
scheduleRenderCharts(chartPointDataSource.value);
}
},
{ flush: ' post ' },
);
watch(
chartPointDataSource,
async (points) => {
if (useNewDetail.value && points?.length) {
await scheduleRenderCharts(points);
}
},
{ deep: true },
);
const title = computed(() => (unref(isDetail) ? ' 快检记录详情 ' : ' 编辑胶料快检记录 '));
function toChartNumber(value: unknown) {
@@ -217,24 +339,27 @@
}
function renderCharts(points: Recordable[]) {
if (! points?.length) {
const normalized = (points ?? []).map((p) => normalizeChartPoint(p));
if (!normalized.length) {
setTempChartOptions({ title: { text: ' 暂无曲线数据 ', left: ' center ', top: ' center ', textStyle: { fontSize: 14 } } });
setTorqueChartOptions({ title: { text: ' 暂无曲线数据 ', left: ' center ', top: ' center ', textStyle: { fontSize: 14 } } });
return;
}
const sorted = [...points ].sort((a, b) => (a.sortNo ?? 0) - (b.sortNo ?? 0));
const times = sorted.map((p) => toChartNumber(p.timeMin) ?? 0);
const sorted = [...normalized ].sort((a, b) => (Number (a.sortNo) || 0) - (Number (b.sortNo) || 0));
const tempUpper = sorted.map((p) => [ toChartNumber(p.timeMin) ?? 0, toChartNumber(p.upperTemp)] );
const tempLower = sorted.map((p) => [toChartNumber(p.timeMin) ?? 0, toChartNumber(p.lowerTemp)]);
const torque = sorted.map((p) => [toChartNumber(p.timeMin) ?? 0, toChartNumber(p.torqueS)]);
setTempChartOptions({
title: undefined,
tooltip: { trigger: ' axis ' },
legend: { data: [' 上模温度 ', ' 下模温度 '] },
grid: { left: 48, right: 24, top: 40, bottom: 32 },
xAxis: { type: ' category ', name: ' 时间 ( min ) ', data: times },
yAxis: { type: ' value ', name: ' 温度 ( ℃ ) ', min: 189, max: 201, interval: 3 },
xAxis: { type: ' value ', name: ' 时间 ( min ) ', min: 0, max: 2, interval: 0.5 },
yAxis: { type: ' value ', name: ' 温度 ( ℃ ) ', scale: true },
series: [
{ name: ' 上模温度 ', type: ' line ', smooth: true, data: sorted.map((p) => toChartNumber(p.upperTemp)) },
{ name: ' 下模温度 ', type: ' line ', smooth: true, data: sorted.map((p) => toChartNumber(p.lowerTemp)) },
{ name: ' 上模温度 ', type: ' line ', smooth: true, showSymbol: true, data: tempUpper },
{ name: ' 下模温度 ', type: ' line ', smooth: true, showSymbol: true, data: tempLower },
],
});
@@ -243,9 +368,9 @@
tooltip: { trigger: ' axis ' },
legend: { data: ["S' ( dNm ) "] },
grid: { left: 48, right: 24, top: 40, bottom: 32 },
xAxis: { type: 'category ', name: '时间(min)', data: times },
yAxis: { type: 'value', name: " S '(dNm)", min: 0, max: 14.8 },
series: [{ name: "S' ( dNm ) " , type : 'line' , smooth : true , data : sorted . map ( ( p ) => toChartNumber ( p . torqueS ) ) } ] ,
xAxis: { type: 'value ', name: '时间(min)', min: 0, max: 2, interval: 0.5 },
yAxis: { type: 'value', name: " S '(dNm)", scale: true },
series: [{ name: "S' ( dNm ) " , type : 'line' , smooth : true , showSymbol : true , data : torque } ] ,
} ) ;
}
@@ -331,13 +456,96 @@
< / script >
< style scoped >
. chart - title {
font - size : 13 px ;
color : rgba ( 0 , 0 , 0 , 0.65 ) ;
margin - bottom : 8 px ;
. detail - section {
margin - top : 20 px ;
}
. detail - section : first - of - type {
margin - top : 8 px ;
}
. detail - section _ _header {
display : flex ;
align - items : center ;
gap : 10 px ;
padding : 10 px 14 px ;
background : linear - gradient ( 90 deg , # f7f9fc 0 % , # fafbfc 100 % ) ;
border : 1 px solid # eef1f5 ;
border - bottom : none ;
border - radius : 8 px 8 px 0 0 ;
}
. detail - section _ _accent {
flex - shrink : 0 ;
width : 4 px ;
height : 18 px ;
border - radius : 2 px ;
background : var ( -- j - global - primary - color , # 1677 ff ) ;
}
. detail - section _ _accent -- green {
background : # 52 c41a ;
}
. detail - section _ _accent -- orange {
background : # fa8c16 ;
}
. detail - section _ _accent -- gray {
background : # 8 c8c8c ;
}
. detail - section _ _titles {
display : flex ;
flex - direction : column ;
gap : 2 px ;
min - width : 0 ;
}
. detail - section _ _title {
font - size : 15 px ;
font - weight : 600 ;
line - height : 1.35 ;
color : rgba ( 0 , 0 , 0 , 0.88 ) ;
letter - spacing : 0.2 px ;
}
. detail - section _ _desc {
font - size : 12 px ;
line - height : 1.4 ;
color : rgba ( 0 , 0 , 0 , 0.45 ) ;
}
. detail - section _ _body {
padding : 12 px ;
background : # fff ;
border : 1 px solid # eef1f5 ;
border - radius : 0 0 8 px 8 px ;
}
. detail - section _ _body -- chart {
padding : 12 px 12 px 4 px ;
}
. chart - card {
padding : 10 px 12 px 8 px ;
background : # fafbfc ;
border : 1 px solid # f0f2f5 ;
border - radius : 6 px ;
}
. chart - card _ _title {
margin - bottom : 8 px ;
padding - left : 8 px ;
font - size : 13 px ;
font - weight : 500 ;
color : rgba ( 0 , 0 , 0 , 0.72 ) ;
border - left : 2 px solid rgba ( 0 , 0 , 0 , 0.12 ) ;
}
. chart - box {
width : 100 % ;
height : 220 px ;
min - height : 220 px ;
}
< / style >