|
|
|
|
@ -4,6 +4,34 @@
|
|
|
|
|
<div v-show="showSearch" class="mb-[10px]">
|
|
|
|
|
<el-card shadow="hover">
|
|
|
|
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
|
|
|
|
<el-form-item label="日期范围" style="width: 300px">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="dateRange"
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
type="daterange"
|
|
|
|
|
range-separator="-"
|
|
|
|
|
start-placeholder="开始日期"
|
|
|
|
|
end-placeholder="结束日期"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item label="物料编号" prop="materialCode">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="queryParams.materialCode"
|
|
|
|
|
placeholder="请输入物料编号"
|
|
|
|
|
clearable
|
|
|
|
|
@keyup.enter="handleQuery"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item label="物料名称" prop="materialName">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="queryParams.materialName"
|
|
|
|
|
placeholder="请输入物料名称"
|
|
|
|
|
clearable
|
|
|
|
|
@keyup.enter="handleQuery"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<!-- <el-form-item label="日期范围" style="width: 300px">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="dateRange"
|
|
|
|
|
@ -130,14 +158,14 @@
|
|
|
|
|
<el-card shadow="never">
|
|
|
|
|
<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:prodReport:export']">导出</el-button>
|
|
|
|
|
</el-col>-->
|
|
|
|
|
<!-- <el-col :span="1.5">
|
|
|
|
|
<el-button type="warning" plain icon="Download" @click="handleProcessExport" v-hasPermi="['mes:prodReport:export']">按工序统计导出</el-button>
|
|
|
|
|
</el-col> -->
|
|
|
|
|
<right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @queryTable="getList" />
|
|
|
|
|
</el-row>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<el-table v-loading="loading" :data="processStatsList" border row-key="processName">
|
|
|
|
|
<el-table ref="processTableRef" v-loading="loading" :data="processStatsList" border row-key="processId" @expand-change="onProcessRowExpand">
|
|
|
|
|
<!-- 工序聚合统计列 -->
|
|
|
|
|
<el-table-column label="工序名称" align="center" prop="processName" v-if="columns[0].visible" min-width="160" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="计划数量" align="center" prop="planQty" v-if="columns[1].visible" width="120" />
|
|
|
|
|
@ -148,80 +176,38 @@
|
|
|
|
|
<div style="display:flex;align-items:center;justify-content:center;">
|
|
|
|
|
<span style="min-width:42px;text-align:right;font-size:12px;color:#606266;">{{ Number(scope.row.completionRateNum || 0) }}%</span>
|
|
|
|
|
<el-progress
|
|
|
|
|
:percentage="Number(scope.row.completionRateNum || 0)"
|
|
|
|
|
:percentage="Math.min(Number(scope.row.completionRateNum || 0), 100)"
|
|
|
|
|
:color="getProgressColor(Number(scope.row.completionRateNum || 0))"
|
|
|
|
|
:stroke-width="8"
|
|
|
|
|
:show-text="false"
|
|
|
|
|
style="width:90px;margin-left:8px;"
|
|
|
|
|
/>
|
|
|
|
|
<el-tag v-if="Number(scope.row.completionRateNum || 0) > 100" type="danger" size="small" style="margin-left:8px;">超额 +{{ Number(scope.row.completionRateNum || 0) - 100 }}%</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<!-- 展开列:列出该工序下的计划(计划编号) -->
|
|
|
|
|
<el-table-column type="expand" width="50">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-table :data="buildProcessPlanRows(scope.row)" border size="small" style="width: 100%" @expand-change="onPlanRowExpand">
|
|
|
|
|
<el-table-column type="expand" width="50">
|
|
|
|
|
<template #default="pScope">
|
|
|
|
|
<div>
|
|
|
|
|
<el-table v-if="planChildrenCache[getPlanChildKey(pScope.row)] && planChildrenCache[getPlanChildKey(pScope.row)].length"
|
|
|
|
|
:data="planChildrenCache[getPlanChildKey(pScope.row)]"
|
|
|
|
|
border size="small" style="width: 100%">
|
|
|
|
|
<el-table-column label="计划ID" prop="planId" width="120" />
|
|
|
|
|
<el-table-column label="计划编号" prop="planCode" width="140" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="工序ID" prop="processId" width="100" />
|
|
|
|
|
<el-table-column label="工序顺序" prop="processOrder" width="100" />
|
|
|
|
|
<el-table-column label="计划数" prop="planAmount" width="110" />
|
|
|
|
|
<el-table-column label="已完数" prop="completeAmount" width="110" />
|
|
|
|
|
<el-table-column label="完成率" width="160">
|
|
|
|
|
<template #default="cScope">
|
|
|
|
|
<div style="display:flex;align-items:center;">
|
|
|
|
|
<span style="min-width:42px;text-align:right;font-size:12px;color:#606266;">
|
|
|
|
|
{{ Number(cScope.row.planAmount) > 0 ? Math.round((Number(cScope.row.completeAmount || 0) * 100.0) / Number(cScope.row.planAmount)) : 0 }}%
|
|
|
|
|
</span>
|
|
|
|
|
<el-progress
|
|
|
|
|
:percentage="Number(cScope.row.planAmount) > 0 ? Math.round((Number(cScope.row.completeAmount || 0) * 100.0) / Number(cScope.row.planAmount)) : 0"
|
|
|
|
|
:color="getProgressColor(Number(cScope.row.planAmount) > 0 ? Math.round((Number(cScope.row.completeAmount || 0) * 100.0) / Number(cScope.row.planAmount)) : 0)"
|
|
|
|
|
:stroke-width="6"
|
|
|
|
|
:show-text="false"
|
|
|
|
|
style="width:100px;margin-left:8px;"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="班组" prop="teamName" width="140" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="工位" prop="stationName" width="140" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="实际开工" prop="realBeginTime" width="160" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="实际完工" prop="realEndTime" width="160" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="状态" prop="planStatus" width="120">
|
|
|
|
|
<template #default="cScope">
|
|
|
|
|
<el-tag :type="getPlanStatusTagType(cScope.row.planStatus)" size="small">
|
|
|
|
|
{{ getPlanStatusLabel(cScope.row.planStatus) }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-empty v-else description="无子节点或未加载" />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table :data="buildProcessPlanRows(scope.row)" border size="small" style="width: 100%" v-loading="isProcessLoading(scope.row.processId)" element-loading-text="加载中...">
|
|
|
|
|
<el-table-column label="计划编号" prop="planCode" width="140" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="物料编号" prop="materialCode" width="140" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="物料名称" prop="materialName" min-width="160" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="计划数" prop="planAmount" width="100" />
|
|
|
|
|
<el-table-column label="已完数" prop="completeAmount" width="100" />
|
|
|
|
|
<el-table-column label="剩余数" prop="remainingAmount" width="100" />
|
|
|
|
|
<!-- <el-table-column label="剩余数" prop="remainingAmount" width="100" /> -->
|
|
|
|
|
<el-table-column label="完成率" width="160">
|
|
|
|
|
<template #default="pScope">
|
|
|
|
|
<div style="display:flex;align-items:center;justify-content:flex-start;">
|
|
|
|
|
<span style="min-width:42px;text-align:right;font-size:12px;color:#606266;">{{ Number(pScope.row.processProgress || 0) }}%</span>
|
|
|
|
|
<el-progress
|
|
|
|
|
:percentage="Number(pScope.row.processProgress || 0)"
|
|
|
|
|
:percentage="Math.min(Number(pScope.row.processProgress || 0), 100)"
|
|
|
|
|
:color="getProgressColor(Number(pScope.row.processProgress || 0))"
|
|
|
|
|
:stroke-width="6"
|
|
|
|
|
:show-text="false"
|
|
|
|
|
style="width:100px;margin-left:8px;"
|
|
|
|
|
/>
|
|
|
|
|
<el-tag v-if="Number(pScope.row.processProgress || 0) > 100" type="danger" size="small" style="margin-left:8px;">超额 +{{ Number(pScope.row.processProgress || 0) - 100 }}%</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
@ -312,7 +298,7 @@ import type { ElFormInstance } from 'element-plus';
|
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
import { listWipTrackingReport, exportWipTrackingReport } from '@/api/mes/wipTrackingReport';
|
|
|
|
|
import { WipTrackingReportVO, WipTrackingReportQuery, ProcessProgressVO } from '@/api/mes/wipTrackingReport/types';
|
|
|
|
|
import { planProcessChildren } from '@/api/mes/prodReport';
|
|
|
|
|
import { planProcessChildren, processWorkOrderStatsPage, exportProcessWorkOrderStats, processPlanList } from '@/api/mes/prodReport';
|
|
|
|
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
|
|
|
|
|
@ -323,6 +309,7 @@ const showSearch = ref(true);
|
|
|
|
|
const total = ref(0);
|
|
|
|
|
const queryFormRef = ref<ElFormInstance>();
|
|
|
|
|
const dateRange = ref<string[]>(['', '']);
|
|
|
|
|
const processTableRef = ref<any>(null);
|
|
|
|
|
|
|
|
|
|
// 图表引用
|
|
|
|
|
const statusChartRef = ref<HTMLDivElement | null>(null);
|
|
|
|
|
@ -345,6 +332,47 @@ const columns = ref([
|
|
|
|
|
|
|
|
|
|
// 计划子节点缓存:key = planCode__processId
|
|
|
|
|
const planChildrenCache = ref<Record<string, any[]>>({});
|
|
|
|
|
// 工序下计划列表缓存:key = processId
|
|
|
|
|
const processPlansCache = ref<Record<string, any[]>>({});
|
|
|
|
|
// 工序展开加载状态:key = processId
|
|
|
|
|
const processPlansLoading = ref<Record<string, boolean>>({});
|
|
|
|
|
function isProcessLoading(pid: any) {
|
|
|
|
|
const k = String(pid ?? '');
|
|
|
|
|
return !!processPlansLoading.value[k];
|
|
|
|
|
}
|
|
|
|
|
// 记录已展开的工序ID,搜索后自动恢复展开
|
|
|
|
|
const expandedProcessIds = ref<number[]>([]);
|
|
|
|
|
function addExpanded(pid: any) {
|
|
|
|
|
const id = Number(pid);
|
|
|
|
|
if (!expandedProcessIds.value.includes(id)) expandedProcessIds.value.push(id);
|
|
|
|
|
}
|
|
|
|
|
function removeExpanded(pid: any) {
|
|
|
|
|
const id = Number(pid);
|
|
|
|
|
expandedProcessIds.value = expandedProcessIds.value.filter(x => x !== id);
|
|
|
|
|
}
|
|
|
|
|
function reExpandProcessRows() {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
expandedProcessIds.value.forEach((pid) => {
|
|
|
|
|
const row = (processStatsList.value || []).find((r: any) => String(r?.processId ?? '') === String(pid));
|
|
|
|
|
if (row && processTableRef.value?.toggleRowExpansion) {
|
|
|
|
|
processTableRef.value.toggleRowExpansion(row, true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 搜索时需要收起所有已展开的子行,不进行自动恢复
|
|
|
|
|
const skipReexpandOnce = ref(false);
|
|
|
|
|
function collapseAllProcessRows() {
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
const rows = processStatsList.value || [];
|
|
|
|
|
if (processTableRef.value?.toggleRowExpansion) {
|
|
|
|
|
rows.forEach((row: any) => {
|
|
|
|
|
processTableRef.value.toggleRowExpansion(row, false);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const queryParams = ref<WipTrackingReportQuery>({
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
@ -371,22 +399,29 @@ watch(dateRange, (newVal) => {
|
|
|
|
|
/** 查询在制品跟踪报表列表 */
|
|
|
|
|
function getList() {
|
|
|
|
|
loading.value = true;
|
|
|
|
|
// 为保证“工序统计”与子节点计划列表不受后端按计划分页影响,
|
|
|
|
|
// 这里按工序视角一次性拉取足够大的计划数据集进行前端聚合。
|
|
|
|
|
// 清理缓存,避免筛选条件变化导致子表旧数据残留
|
|
|
|
|
processPlansCache.value = {};
|
|
|
|
|
planChildrenCache.value = {};
|
|
|
|
|
processPlansLoading.value = {};
|
|
|
|
|
const baseQuery = { ...queryParams.value };
|
|
|
|
|
const allQuery = { ...baseQuery, pageNum: 1, pageSize: 100000 };
|
|
|
|
|
listWipTrackingReport(allQuery)
|
|
|
|
|
.then((response: any) => {
|
|
|
|
|
// 使用全量计划数据进行工序聚合统计与子列表构建
|
|
|
|
|
reportList.value = response?.rows || [];
|
|
|
|
|
// 顶层分页改为按工序维度,total 等于工序统计项数量
|
|
|
|
|
processStatsList.value = buildProcessStatsFromReport(reportList.value);
|
|
|
|
|
total.value = processStatsList.value.length;
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
|
|
|
|
// 1) 顶层按工序分页
|
|
|
|
|
const procReq = processWorkOrderStatsPage(baseQuery);
|
|
|
|
|
|
|
|
|
|
Promise.all([procReq])
|
|
|
|
|
.then(([procRes]: any[]) => {
|
|
|
|
|
// 顶层工序聚合分页数据
|
|
|
|
|
processStatsList.value = procRes?.rows || [];
|
|
|
|
|
total.value = procRes?.total || (processStatsList.value?.length || 0);
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
updateCharts();
|
|
|
|
|
// 根据标记决定是否恢复展开的工序
|
|
|
|
|
if (!skipReexpandOnce.value) {
|
|
|
|
|
reExpandProcessRows();
|
|
|
|
|
}
|
|
|
|
|
// 仅跳过一次,后续恢复默认行为
|
|
|
|
|
skipReexpandOnce.value = false;
|
|
|
|
|
});
|
|
|
|
|
loading.value = false;
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
@ -396,6 +431,14 @@ function getList() {
|
|
|
|
|
/** 搜索按钮操作 */
|
|
|
|
|
function handleQuery() {
|
|
|
|
|
queryParams.value.pageNum = 1;
|
|
|
|
|
// 清理缓存,确保加载新筛选条件下的数据
|
|
|
|
|
processPlansCache.value = {};
|
|
|
|
|
planChildrenCache.value = {};
|
|
|
|
|
processPlansLoading.value = {};
|
|
|
|
|
// 搜索时收起所有子节点并且不自动恢复展开
|
|
|
|
|
expandedProcessIds.value = [];
|
|
|
|
|
skipReexpandOnce.value = true;
|
|
|
|
|
collapseAllProcessRows();
|
|
|
|
|
getList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -417,12 +460,12 @@ function resetQuery() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 导出按钮操作 */
|
|
|
|
|
function handleExport() {
|
|
|
|
|
proxy?.$modal.confirm('是否确认导出所有在制品跟踪报表数据项?').then(() => {
|
|
|
|
|
function handleProcessExport() {
|
|
|
|
|
proxy?.$modal.confirm('是否确认导出按工序统计数据?').then(() => {
|
|
|
|
|
proxy?.$modal.loading('正在导出数据,请稍候...');
|
|
|
|
|
return exportWipTrackingReport(queryParams.value);
|
|
|
|
|
return exportProcessWorkOrderStats(queryParams.value);
|
|
|
|
|
}).then((response: any) => {
|
|
|
|
|
proxy?.$download.blob(response, '在制品跟踪报表.xlsx');
|
|
|
|
|
proxy?.$download.blob(response, '工序生产统计.xlsx');
|
|
|
|
|
proxy?.$modal.closeLoading();
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
proxy?.$modal.closeLoading();
|
|
|
|
|
@ -431,6 +474,7 @@ function handleExport() {
|
|
|
|
|
|
|
|
|
|
/** 获取进度颜色 */
|
|
|
|
|
function getProgressColor(percentage: number) {
|
|
|
|
|
if (percentage > 100) return '#f56c6c';
|
|
|
|
|
if (percentage < 30) return '#f56c6c';
|
|
|
|
|
if (percentage < 70) return '#e6a23c';
|
|
|
|
|
return '#67c23a';
|
|
|
|
|
@ -489,43 +533,46 @@ function buildProcessTree(row: WipTrackingReportVO) {
|
|
|
|
|
* 从 reportList 的每个订单的 processProgressList 中,筛选出工序名称匹配的项
|
|
|
|
|
*/
|
|
|
|
|
function buildProcessPlanRows(procRow: any) {
|
|
|
|
|
const rows: any[] = [];
|
|
|
|
|
const targetProcessName = procRow?.processName;
|
|
|
|
|
if (!targetProcessName) return rows;
|
|
|
|
|
|
|
|
|
|
(reportList.value || []).forEach(order => {
|
|
|
|
|
const procs = (order as any).processProgressList || [];
|
|
|
|
|
procs.forEach((p: any) => {
|
|
|
|
|
if (p?.processName === targetProcessName) {
|
|
|
|
|
const planAmount = Number(p?.planAmount ?? 0);
|
|
|
|
|
const completeAmount = Number(p?.completeAmount ?? 0);
|
|
|
|
|
const remainingAmount = p?.remainingAmount != null
|
|
|
|
|
? Number(p.remainingAmount)
|
|
|
|
|
: Math.max(planAmount - completeAmount, 0);
|
|
|
|
|
const progressNum = p?.processProgress != null
|
|
|
|
|
? Number(p.processProgress)
|
|
|
|
|
: (planAmount > 0 ? Math.round((completeAmount * 100.0) / planAmount) : 0);
|
|
|
|
|
rows.push({
|
|
|
|
|
planCode: p?.planCode || (order as any).planCode || '',
|
|
|
|
|
processId: p?.processId || '',
|
|
|
|
|
materialName: p?.materialName || (order as any).materialName || '',
|
|
|
|
|
materialCode: p?.materialCode || (order as any).materialCode || '',
|
|
|
|
|
planAmount,
|
|
|
|
|
completeAmount,
|
|
|
|
|
remainingAmount,
|
|
|
|
|
processProgress: progressNum,
|
|
|
|
|
isCompleted: (p?.isCompleted === 1) || !!p?.isCompleted,
|
|
|
|
|
isInProgress: (p?.isInProgress === 1) || !!p?.isInProgress
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 进度高的排前
|
|
|
|
|
const key = String(procRow?.processId ?? '');
|
|
|
|
|
const rows = (key && processPlansCache.value[key]) ? processPlansCache.value[key] : [];
|
|
|
|
|
// 进度高的排前(若有字段)
|
|
|
|
|
rows.sort((a, b) => Number(b.processProgress || 0) - Number(a.processProgress || 0));
|
|
|
|
|
return rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 外层工序展开时触发:加载该工序下计划列表(不分页) */
|
|
|
|
|
async function onProcessRowExpand(row: any, expanded: boolean) {
|
|
|
|
|
const key = String(row?.processId ?? '');
|
|
|
|
|
// 事件无 expanded 参数时也兼容加载
|
|
|
|
|
if (!key) return;
|
|
|
|
|
// 同步维护已展开工序集合
|
|
|
|
|
if (typeof expanded === 'boolean') {
|
|
|
|
|
expanded ? addExpanded(row?.processId) : removeExpanded(row?.processId);
|
|
|
|
|
}
|
|
|
|
|
if (processPlansCache.value[key] && processPlansCache.value[key].length) return;
|
|
|
|
|
// 标记该工序展开区为加载中
|
|
|
|
|
processPlansLoading.value[key] = true;
|
|
|
|
|
// 组装查询参数
|
|
|
|
|
const query: any = {
|
|
|
|
|
processId: Number(row?.processId),
|
|
|
|
|
beginDate: queryParams.value.beginDate,
|
|
|
|
|
endDate: queryParams.value.endDate,
|
|
|
|
|
materialCode: queryParams.value.materialCode,
|
|
|
|
|
materialName: queryParams.value.materialName,
|
|
|
|
|
planCode: queryParams.value.planCode
|
|
|
|
|
};
|
|
|
|
|
try {
|
|
|
|
|
const res: any = await processPlanList(query);
|
|
|
|
|
const data = (res?.data || res?.rows || res) || [];
|
|
|
|
|
processPlansCache.value[key] = data;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
processPlansCache.value[key] = [];
|
|
|
|
|
} finally {
|
|
|
|
|
// 结束加载态
|
|
|
|
|
processPlansLoading.value[key] = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 生成计划子节点缓存Key */
|
|
|
|
|
function getPlanChildKey(row: any) {
|
|
|
|
|
return `${row?.planCode || ''}__${row?.processId || ''}`;
|
|
|
|
|
@ -693,6 +740,9 @@ function updateProcessStatsChart() {
|
|
|
|
|
const completedData = sorted.map((r: any) => Number(r.completedQty || 0));
|
|
|
|
|
const uncompletedData = sorted.map((r: any) => Number(r.uncompletedQty || 0));
|
|
|
|
|
const completionRateData = sorted.map((r: any) => Number(r.completionRateNum || 0));
|
|
|
|
|
const maxRate = completionRateData.length ? Math.max(...completionRateData) : 0;
|
|
|
|
|
const yMax = Math.max(100, Math.ceil(maxRate / 10) * 10);
|
|
|
|
|
const showExcessArea = yMax > 100;
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
title: { text: '工序生产统计(Top10)', left: 'center', textStyle: { fontSize: 14 } },
|
|
|
|
|
@ -702,12 +752,18 @@ function updateProcessStatsChart() {
|
|
|
|
|
xAxis: { type: 'category', data: processNames },
|
|
|
|
|
yAxis: [
|
|
|
|
|
{ type: 'value', name: '数量' },
|
|
|
|
|
{ type: 'value', name: '完成率%', min: 0, max: 100, position: 'right' }
|
|
|
|
|
{ type: 'value', name: '完成率%', min: 0, max: yMax, position: 'right', axisLabel: { formatter: '{value}%' } }
|
|
|
|
|
],
|
|
|
|
|
series: [
|
|
|
|
|
{ name: '已完成数量', type: 'bar', data: completedData },
|
|
|
|
|
{ name: '未完成数量', type: 'bar', data: uncompletedData },
|
|
|
|
|
{ name: '完成率%', type: 'line', yAxisIndex: 1, data: completionRateData, smooth: true }
|
|
|
|
|
{ name: '完成率%', type: 'line', yAxisIndex: 1, data: completionRateData, smooth: true,
|
|
|
|
|
markArea: showExcessArea ? {
|
|
|
|
|
itemStyle: { color: 'rgba(245,108,108,0.12)' },
|
|
|
|
|
label: { color: '#f56c6c', position: 'insideTop', formatter: '超额区间' },
|
|
|
|
|
data: [ [ { yAxis: 100 }, { yAxis: yMax } ] ]
|
|
|
|
|
} : undefined
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|