chore: synchronize local fixes to gitea
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import { Request, Response } from 'express';
|
||||
import * as applicationRecordService from '../services/applicationRecordService.js';
|
||||
import * as paintingSchemeService from '../services/paintingSchemeService.js';
|
||||
import * as inspectionService from '../services/inspectionService.js';
|
||||
|
||||
interface AnalysisResult {
|
||||
pieceDescription: string;
|
||||
schemeName: string;
|
||||
schemeType: string;
|
||||
|
||||
// Yield (Rendimento)
|
||||
realYield: number;
|
||||
theoreticalYield: number;
|
||||
yieldVariance: number; // percentage
|
||||
yieldStatus: 'approved' | 'warning' | 'critical';
|
||||
|
||||
// Dilution
|
||||
diluentUsed: number;
|
||||
volumeUsed: number;
|
||||
realDilution: number;
|
||||
targetDilution: number;
|
||||
dilutionStatus: 'approved' | 'warning' | 'critical';
|
||||
|
||||
// Thickness (Espessura)
|
||||
realDFT: number; // Average of dryThicknessCalc or inspection points
|
||||
minDFT: number;
|
||||
maxDFT: number;
|
||||
dftStatus: 'approved' | 'warning' | 'critical';
|
||||
|
||||
notes: string[];
|
||||
}
|
||||
|
||||
export const getProjectAnalysis = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { projectId } = req.params;
|
||||
|
||||
const records = await applicationRecordService.getApplicationRecordsByProject(projectId as string);
|
||||
const schemes = await paintingSchemeService.getPaintingSchemesByProject(projectId as string);
|
||||
const inspections = await inspectionService.getInspectionsByProject(projectId as string);
|
||||
|
||||
const analysis: AnalysisResult[] = [];
|
||||
|
||||
// Group records by pieceDescription to handle multiple layers/records for same piece if needed
|
||||
// For simple MVP, assuming 1 record per piece for calculation or analyzing individual records
|
||||
|
||||
for (const record of records) {
|
||||
// Find scheme used (assuming application record doesn't store schemeId directly, we might need to match by name or context?
|
||||
// Checking types.ts, ApplicationRecord doesn't have schemeId. It has 'coatStage'.
|
||||
// PaintingScheme has 'type' which might match 'coatStage' or project context.
|
||||
// Without direct link, we might have to infer or maybe the user links them by name/description effectively?
|
||||
// Actually, in many cases there's only one scheme active per project or we check if schemes exist.
|
||||
// Let's try to match if possible, or use a default if only one scheme exists.
|
||||
|
||||
// Note: In a real robust system we'd link Record -> Scheme.
|
||||
// Here we will try to find a scheme that matches the coatStage or just take the first one if length is 1.
|
||||
const scheme = schemes.find(s => s.type === record.coatStage) || schemes[0];
|
||||
|
||||
if (!scheme) continue;
|
||||
|
||||
// Calculations
|
||||
|
||||
// 1. Yield
|
||||
// Yield = Area / Volume
|
||||
const realYield = (record.areaPainted && record.volumeUsed)
|
||||
? (record.areaPainted / record.volumeUsed)
|
||||
: 0;
|
||||
|
||||
const theoreticalYield = scheme.yieldTheoretical || 0;
|
||||
|
||||
const yieldData = calculateVariance(realYield, theoreticalYield);
|
||||
|
||||
// 2. Dilution
|
||||
const diluent = record.diluentUsed || 0;
|
||||
const volume = record.volumeUsed || 1; // avoid div by zero
|
||||
const realDilution = (diluent / volume) * 100;
|
||||
const targetDilution = scheme.dilution || 0;
|
||||
|
||||
const dilutionData = calculateVariance(realDilution, targetDilution); // true for "lower is not always better/worse", requires exact match?
|
||||
// Actually for dilution, usually there's a limit. Let's assume variance check.
|
||||
|
||||
// 3. DFT (Dry Film Thickness)
|
||||
// Use inspection data if available for this piece, otherwise calculated
|
||||
const pieceInspection = inspections.find(i => i.pieceDescription === record.pieceDescription);
|
||||
|
||||
let realDFT = 0;
|
||||
if (pieceInspection) {
|
||||
const points = (pieceInspection.epsPoints || []).filter((p: number | null | undefined): p is number => p !== undefined && p !== null);
|
||||
if (points.length > 0) {
|
||||
realDFT = points.reduce((a: number, b: number) => a + b, 0) / points.length;
|
||||
}
|
||||
} else {
|
||||
realDFT = record.dryThicknessCalc || 0;
|
||||
}
|
||||
|
||||
const minDFT = scheme.epsMin || 0;
|
||||
const maxDFT = scheme.epsMax || 9999;
|
||||
|
||||
let dftStatus: 'approved' | 'warning' | 'critical' = 'approved';
|
||||
if (realDFT < minDFT) dftStatus = 'critical';
|
||||
else if (realDFT > maxDFT) dftStatus = 'warning';
|
||||
|
||||
|
||||
analysis.push({
|
||||
pieceDescription: record.pieceDescription || 'Desconhecido',
|
||||
schemeName: scheme.name,
|
||||
schemeType: scheme.type || '',
|
||||
|
||||
realYield: Number(realYield.toFixed(2)),
|
||||
theoreticalYield: Number(theoreticalYield.toFixed(2)),
|
||||
yieldVariance: Number(yieldData.variance.toFixed(2)),
|
||||
yieldStatus: yieldData.status,
|
||||
|
||||
diluentUsed: diluent,
|
||||
volumeUsed: volume,
|
||||
realDilution: Number(realDilution.toFixed(1)),
|
||||
targetDilution: Number(targetDilution.toFixed(1)),
|
||||
dilutionStatus: dilutionData.status, // We might want to warn if dilution is > target
|
||||
|
||||
realDFT: Number(realDFT.toFixed(1)),
|
||||
minDFT: minDFT,
|
||||
maxDFT: maxDFT,
|
||||
dftStatus,
|
||||
|
||||
notes: []
|
||||
});
|
||||
}
|
||||
|
||||
res.json(analysis);
|
||||
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||
res.status(500).json({ error: message });
|
||||
}
|
||||
};
|
||||
|
||||
function calculateVariance(actual: number, target: number): { variance: number, status: 'approved' | 'warning' | 'critical' } {
|
||||
if (!target) return { variance: 0, status: 'approved' };
|
||||
|
||||
// Variance % = ((Actual - Target) / Target) * 100
|
||||
const variance = ((actual - target) / target) * 100;
|
||||
|
||||
// Rules (Simplified)
|
||||
// Yield: Higher is usually good (efficient), but too high might mean too thin.
|
||||
// Lower means using more paint -> expensive.
|
||||
|
||||
let status: 'approved' | 'warning' | 'critical' = 'approved';
|
||||
|
||||
// If deviation is > 20% (warning) or > 30% (critical)
|
||||
if (Math.abs(variance) > 30) status = 'critical';
|
||||
else if (Math.abs(variance) > 20) status = 'warning';
|
||||
|
||||
return { variance, status };
|
||||
}
|
||||
Reference in New Issue
Block a user