feat(round-12): 实体卡外贸生产工单/雷达多渠道归因漏斗/AI地道外联草拟/现代图片自适应协商 (87套件1007测试全绿)

这个提交包含在:
wikiboss
2026-09-21 02:06:55 +08:00
父节点 76f0dc17c0
当前提交 3cfbed9e6a
共有 8 个文件被更改,包括 897 次插入 和 0 次删除

查看文件

@@ -0,0 +1,180 @@
import { Provide } from '@midwayjs/core';
import { BaseService } from '@cool-midway/core';
export type ManufacturingBatchStatus =
| 'draft'
| 'ordered'
| 'manufacturing'
| 'qa_inspected'
| 'in_stock'
| 'rejected'
| 'cancelled';
export interface CreateManufacturingBatchDto {
batchNo: string;
materialType: string;
targetQuantity: number;
factoryName: string;
chipModel: string;
cardFinishing?: string;
}
export interface ManufacturingBatchRecord extends CreateManufacturingBatchDto {
id: string;
status: ManufacturingBatchStatus;
qualifiedQuantity: number;
defectQuantity: number;
yieldRate?: number;
createdAt: number;
updatedAt: number;
}
export interface BatchYieldResult {
yieldRate: number;
defectRate: number;
isQualified: boolean;
defectCount: number;
}
/**
* 生产批次工单生命周期合法转换图
*/
const ALLOWED_TRANSITIONS: Record<ManufacturingBatchStatus, ManufacturingBatchStatus[]> = {
draft: ['ordered', 'cancelled'],
ordered: ['manufacturing', 'cancelled'],
manufacturing: ['qa_inspected', 'cancelled'],
qa_inspected: ['in_stock', 'rejected'],
in_stock: [],
rejected: ['manufacturing'], // 返工重制
cancelled: [],
};
/**
* 判定工单状态机流转是否合法
*/
export function canTransitionBatchStatus(
from: ManufacturingBatchStatus,
to: ManufacturingBatchStatus
): boolean {
const allowed = ALLOWED_TRANSITIONS[from];
return allowed != null && allowed.includes(to);
}
/**
* 计算生产良率与报废率
*/
export function calculateBatchYieldRate(
totalPlanned: number,
qualified: number,
defect: number,
qualificationThreshold = 0.95
): BatchYieldResult {
if (totalPlanned <= 0) {
throw new Error('计划生产总量必须大于零');
}
if (qualified < 0 || defect < 0) {
throw new Error('合格数与不良品数不能为负数');
}
if (qualified > totalPlanned) {
throw new Error('合格品数量不能超出计划生产总量');
}
const inspectedTotal = qualified + defect;
if (inspectedTotal > totalPlanned * 1.05) {
// 允许少量备损溢产,超出过多则报错
throw new Error('质检总数超出合理批次生产总数范围');
}
const yieldRate = Number((qualified / totalPlanned).toFixed(3));
const defectRate = Number((defect / totalPlanned).toFixed(3));
const isQualified = yieldRate >= qualificationThreshold;
return {
yieldRate,
defectRate,
isQualified,
defectCount: defect,
};
}
/**
* 跨境实体卡供应链生产批次工单管理服务
*/
@Provide()
export class NfcManufacturingService extends BaseService {
private readonly batches = new Map<string, ManufacturingBatchRecord>();
/**
* 创建生产批次工单
*/
createBatch(dto: CreateManufacturingBatchDto): ManufacturingBatchRecord {
if (!dto.batchNo || !dto.targetQuantity || dto.targetQuantity <= 0) {
throw new Error('生产批次号与计划生产数量为必填项');
}
const now = Date.now();
const record: ManufacturingBatchRecord = {
id: `mfg_${now}_${Math.random().toString(36).slice(2, 6)}`,
...dto,
status: 'draft',
qualifiedQuantity: 0,
defectQuantity: 0,
createdAt: now,
updatedAt: now,
};
this.batches.set(dto.batchNo, record);
return record;
}
/**
* 获取生产工单
*/
getBatch(batchNo: string): ManufacturingBatchRecord | undefined {
return this.batches.get(batchNo);
}
/**
* 流转工单生命周期状态
*/
updateBatchStatus(
batchNo: string,
targetStatus: ManufacturingBatchStatus
): ManufacturingBatchRecord {
const batch = this.batches.get(batchNo);
if (!batch) {
throw new Error(`未找到批次工单: ${batchNo}`);
}
if (!canTransitionBatchStatus(batch.status, targetStatus)) {
throw new Error(`非法状态流转: 不能从 ${batch.status} 流转至 ${targetStatus}`);
}
batch.status = targetStatus;
batch.updatedAt = Date.now();
return batch;
}
/**
* 录入出厂质检数据
*/
recordBatchInspection(
batchNo: string,
qualified: number,
defect: number
): ManufacturingBatchRecord {
const batch = this.batches.get(batchNo);
if (!batch) {
throw new Error(`未找到批次工单: ${batchNo}`);
}
const stats = calculateBatchYieldRate(batch.targetQuantity, qualified, defect);
batch.qualifiedQuantity = qualified;
batch.defectQuantity = defect;
batch.yieldRate = stats.yieldRate;
batch.status = 'qa_inspected';
batch.updatedAt = Date.now();
return batch;
}
}