import api from "./api"; import type { ProductOutboundMaterial, ProductScanResponse, ProductScrap, } from "../types/api"; /** 扫码查询 — 根据 16 位产品身份证查产品 + 顶层任务 */ export async function scanProduct(serialNumber: string): Promise { const { data } = await api.get( `/products/scan/${encodeURIComponent(serialNumber)}` ); return data; } // ============================================================ // 设备的 MOM 出库明细(统一后只有这一组) // // 原先这里是两组接口,对应两张表: // · outbound-orders —— 产品 ↔ 出库**单**(单据级 product_outbounds) // · materials —— 任务 ↔ 出库**明细**(明细级 task_outbound_materials) // 两者是同一个概念,却因为粒度不同被拆开:用户要面对两个入口两张卡, // 而且走单据级挂的料**没有明细行 id,报不了废**。 // 现已合并成一张表、一组接口、界面上只有一张卡。 // ============================================================ /** * 列出该设备挂载的全部 MOM 出库明细(按出库时间倒序)。 * 对应后端 GET /api/v1/products/{productId}/outbound-materials * * 一行 = 一条出库明细。`mom_line_id` 为空表示这条是**单据级存档** * (MOM 回调时查不到明细),能看、能标撤回,但**不能报废**。 */ export async function getProductOutboundMaterials( productId: string, ): Promise { const { data } = await api.get( `/products/${productId}/outbound-materials`, ); return data; } /** * 给设备挂载 MOM 出库明细(网页端/移动端的「+ 领料」都走这里)。 * 对应后端 POST /api/v1/products/{productId}/outbound-materials * * ⚠️ 只传 `mom_line_ids`,物料快照由后端现查 MOM —— 前端不传快照。 * ⚠️ `taskId` 可空,仅作溯源(这条料挂在哪条任务上),不参与展示/报废/删除。 * 幂等:已挂过的明细会被后端跳过。返回该设备当前**全部**出库明细。 */ export async function mountProductOutboundMaterials( productId: string, momLineIds: number[], taskId?: string | null, ): Promise { const { data } = await api.post( `/products/${productId}/outbound-materials`, { mom_line_ids: momLineIds, task_id: taskId || null }, ); return data; } /** * 摘掉一条**人工挂载**的出库明细(挂错了要能撤)。 * 对应后端 DELETE /api/v1/products/{productId}/outbound-materials/{materialId} * * ⚠️ 只能删 `source='manual'` 的。MOM 回调自动存档的行后端返回 409 —— * 那是系统事实,要撤得去 MOM 撤回。返回该设备**剩余**的全部出库明细。 */ export async function removeProductOutboundMaterial( productId: string, materialId: number, ): Promise { const { data } = await api.delete( `/products/${productId}/outbound-materials/${materialId}`, ); return data; } /** * 整张出库单一起摘掉(挂错了要能撤)。 * 对应后端 DELETE /api/v1/products/{productId}/outbound-materials/by-order/{outboundNo} * * 界面上更容易碰到的是「这一单整个挂错了」,逐条删要删好几下。 * 规则与逐条删一致:含 webhook 存档记录的单整单删不掉(后端 409)。 */ export async function removeProductOutboundOrder( productId: string, outboundNo: string, ): Promise { const { data } = await api.delete( `/products/${productId}/outbound-materials/by-order/${encodeURIComponent(outboundNo)}`, ); return data; } // ============================================================ // 生产报废 // ============================================================ /** * 列出该设备的报废记录(含实时回查 MOM 的状态与金额)。 * 对应后端 GET /api/v1/products/{productId}/scraps */ export async function listProductScraps(productId: string): Promise { const { data } = await api.get(`/products/${productId}/scraps`); return data; } /** * 提交一条生产报废(领用的料在生产中损坏)。 * 对应后端 POST /api/v1/products/{productId}/scraps * * ⚠️ `track_ref` 必须在**打开弹窗时生成一次**并在重试时复用 —— * 每次提交都换新的话,用户重试会在 MOM 里多报一张报废单。 */ export async function submitProductScrap( productId: string, payload: { mom_line_id: number; quantity: number; track_ref: string; reason?: string | null }, ): Promise { const { data } = await api.post( `/products/${productId}/scraps`, payload, ); return data; }