(function (root, factory) {
  "use strict";
  const api = factory();
  if (typeof module === "object" && module.exports) module.exports = api;
  if (root) root.JIANGLAI_QUOTE_INDUSTRIES = Object.freeze(api);
})(typeof globalThis !== "undefined" ? globalThis : this, function () {
  "use strict";

  const categories = Object.freeze({
    "包装印刷": Object.freeze(["包装彩盒", "手提袋", "标签贴纸", "名片印刷", "画册/说明书"]),
    "纺织服装": Object.freeze(["棉布纺织", "无纺布袋", "服装/内衣/袜子"]),
    "塑料制品": Object.freeze(["塑料袋/OPP袋", "硅胶橡胶"]),
    "五金加工": Object.freeze(["五金钣金", "金属标牌/徽章"]),
    "礼品日用": Object.freeze(["亚克力展示架", "木制品/竹制品", "礼品日用品"]),
    "电子配件": Object.freeze(["电子配件/小家电", "通用加工"])
  });

  const descriptions = Object.freeze({
    "包装印刷": "纸盒、纸袋、标签、名片、画册",
    "纺织服装": "棉布袋、无纺布袋、服装、内衣袜子",
    "塑料制品": "塑料袋、OPP袋、硅胶橡胶",
    "五金加工": "钣金、冲压、金属标牌、徽章",
    "礼品日用": "亚克力、木竹制品、礼品日用品",
    "电子配件": "数据线、小家电、电子配件、通用加工"
  });

  const productTemplateExtensions = Object.freeze({
    "服装/内衣/袜子": Object.freeze({ product: "服装/内衣/袜子", material: "面料待确认", process: "裁剪, 车缝, 印花/刺绣, 包装", delivery: "按尺码、颜色、数量和排产确认" }),
    "塑料袋/OPP袋": Object.freeze({ product: "塑料袋/OPP袋", material: "PE/OPP材料", process: "印刷, 制袋, 封边, 打孔", delivery: "7-12天，需确认厚度、封边和印刷" }),
    "硅胶橡胶": Object.freeze({ product: "硅胶/橡胶制品", material: "硅胶/橡胶", process: "开模, 成型, 修边, 印刷", delivery: "打样和模具周期需单独确认" }),
    "五金钣金": Object.freeze({ product: "五金钣金件", material: "金属材质待确认", process: "切割, 冲压, 折弯, 表面处理", delivery: "按图纸、公差、表面处理和数量确认" }),
    "金属标牌/徽章": Object.freeze({ product: "金属标牌/徽章", material: "锌合金/不锈钢/铝材", process: "冲压, 腐蚀, 烤漆, 电镀", delivery: "需确认图纸、颜色、厚度和包装防刮" }),
    "亚克力展示架": Object.freeze({ product: "亚克力展示架", material: "亚克力板", process: "激光切割, 折弯, 丝印, 组装", delivery: "需确认厚度、结构、包装防护" }),
    "木制品/竹制品": Object.freeze({ product: "木制品/竹制品", material: "木材/竹材", process: "切割, 打磨, 喷漆, 雕刻", delivery: "需确认材质、含水率、喷漆和包装" }),
    "礼品日用品": Object.freeze({ product: "礼品日用品", material: "材料待确认", process: "Logo定制, 组装, 包装, 装箱", delivery: "需确认样品、颜色、Logo位置和质检标准" }),
    "电子配件/小家电": Object.freeze({ product: "电子配件/小家电", material: "规格待确认", process: "组装, 测试, Logo, 包装", delivery: "需确认认证、参数、质保和功能测试" })
  });

  const presets = Object.freeze({
    "包装印刷": Object.freeze({
      capacityRules: "包装印刷=彩盒/纸袋/标签/画册，起订500-1000，交期7-12天，特殊工艺需打样",
      materialRules: "350g白卡=0.42\n300g铜版纸=0.36\n牛皮纸=0.31\n特种纸=0.58",
      processRules: "覆膜=0.08\n哑膜=0.08\n烫银=0.16\n烫金=0.16\n模切=0.06\n糊盒=0.07\nUV=0.12",
      print: 180, printUnit: 0.12, moq: 1000, utilizationRate: 0.90,
      delivery: "7-10天，具体以确认稿和排产为准"
    }),
    "纺织服装": Object.freeze({
      capacityRules: "纺织服装=棉布袋/无纺布袋/服装辅料，起订1000，交期10-15天，需确认克重和色牢度",
      materialRules: "80g无纺布=0.38\n10安纯棉帆布=2.60\n12安纯棉帆布=3.20\n涤棉面料=1.85",
      processRules: "裁剪=0.12\n车缝=0.35\n单色丝印=0.28\n彩色印花=0.65\n刺绣=0.80",
      print: 120, printUnit: 0.18, moq: 1000, utilizationRate: 0.85,
      delivery: "10-15天，需确认克重、尺寸、颜色和印花牢度"
    }),
    "塑料制品": Object.freeze({
      capacityRules: "塑料制品=PE袋/OPP袋/复合袋/硅胶件，起订按袋型和模具确认，需确认厚度和材质等级",
      materialRules: "PE材料=0.22\nOPP材料=0.18\n复合膜=0.36\n食品级材料=0.42",
      processRules: "印刷=0.10\n制袋=0.08\n封边=0.05\n打孔=0.03\n开模=0.30",
      print: 160, printUnit: 0.10, moq: 3000, utilizationRate: 0.95,
      delivery: "7-12天，需确认厚度、材质、袋型和印刷颜色"
    }),
    "五金加工": Object.freeze({
      capacityRules: "五金加工=钣金/冲压/标牌/徽章，按图报价，需提供图纸、公差和表面处理要求",
      materialRules: "不锈钢=1.80\n铝材=1.35\n镀锌板=1.10\n锌合金=1.55",
      processRules: "激光切割=0.80\n冲压=0.55\n折弯=0.65\n拉丝=0.45\n电镀=0.75\n烤漆=0.68",
      print: 260, printUnit: 0.35, moq: 300, utilizationRate: 0.85,
      delivery: "按图纸、公差、表面处理和排产确认"
    }),
    "礼品日用": Object.freeze({
      capacityRules: "礼品日用=亚克力/竹木制品/定制礼品，起订按产品确认，需确认样品、Logo和包装标准",
      materialRules: "亚克力板=1.20\n竹木材料=1.55\n通用礼品材料=0.95\n包装辅料=0.35",
      processRules: "激光切割=0.55\n折弯=0.45\n雕刻=0.60\n丝印=0.30\n组装=0.38\n独立包装=0.25",
      print: 180, printUnit: 0.22, moq: 500, utilizationRate: 0.85,
      delivery: "按样品、Logo、结构、包装和排产确认"
    }),
    "电子配件": Object.freeze({
      capacityRules: "电子配件=线材/电子组件/小家电组装，需确认规格、认证、测试标准和质保要求",
      materialRules: "电子组件=2.80\n塑胶外壳=0.85\n线材=1.20\n包装辅料=0.42",
      processRules: "组装=0.65\n功能测试=0.45\n老化测试=0.55\n丝印Logo=0.30\n独立包装=0.28",
      print: 280, printUnit: 0.40, moq: 500, utilizationRate: 0.98,
      delivery: "需确认规格、认证、测试标准、质保和排产"
    })
  });

  const field = (id, label, placeholder, options = {}) => Object.freeze({
    id, label, placeholder, inputMode: options.inputMode || "decimal",
    required: options.required !== false, defaultValue: options.defaultValue ?? "",
    help: options.help || ""
  });

  const commonTimeFields = Object.freeze([
    field("quoteLaborMinutes", "标准人工分钟（分钟/件）", "裁切、组装、车缝等标准工时", { required: false }),
    field("quoteMachineMinutes", "设备分钟（分钟/件）", "印刷、激光、冲压等设备时间", { required: false })
  ]);

  const strategies = Object.freeze({
    packaging_printing: Object.freeze({
      id: "packaging_printing",
      label: "包装印刷专属公式",
      categoryLabel: "包装印刷",
      formula: "展开宽×展开高换算面积，结合克重得到净纸重，再按排版利用率计算材料耗用；印刷、模切、覆膜、糊盒等费用按本厂工艺表另计。",
      source: "按展开尺寸、克重、拼版利用率和标准工时核算；正式生产前必须以刀线和上机纸复核。",
      calibration: Object.freeze(["常用纸张采购价（元/kg或元/吨）", "常用上机纸与拼版利用率", "印刷开机费与印工", "模切、覆膜、糊盒计价", "完全人工及设备机时"]),
      fields: Object.freeze([
        field("quotePackageFlatWidthMm", "单件展开宽（mm）", "按刀线填写"),
        field("quotePackageFlatHeightMm", "单件展开高（mm）", "按刀线填写"),
        field("quotePackageGsm", "纸张/纸板克重（g/㎡）", "例如：350"),
        field("quoteMaterialUnitPrice", "纸张采购价（元/kg）", "例如：6.8"),
        field("quoteUtilizationRate", "拼版利用率（%）", "例如：90"),
        ...commonTimeFields
      ])
    }),
    acrylic: Object.freeze({
      id: "acrylic",
      label: "亚克力制品专属公式",
      categoryLabel: "亚克力制品",
      formula: "长×宽×厚度×材料密度计算净重，再按排料利用率计算板材成本；激光切割、折弯、粘接、丝印和包装分别计费。",
      source: "密度默认值仅用于PMMA常规估算，必须按实际板材牌号和供应商数据确认。",
      calibration: Object.freeze(["常用厚度板材采购价（元/kg或元/张）", "板材密度与排料利用率", "激光机时费", "每道折弯/粘接费用", "包装防刮费用"]),
      fields: Object.freeze([
        field("quoteAcrylicWidthMm", "板件宽（mm）", "按图纸展开尺寸"),
        field("quoteAcrylicHeightMm", "板件高（mm）", "按图纸展开尺寸"),
        field("quoteAcrylicThicknessMm", "板材厚度（mm）", "例如：3"),
        field("quoteAcrylicDensity", "材料密度（g/cm³）", "按牌号确认", { defaultValue: "1.19", help: "PMMA常见参考值为1.19，仍需按实际牌号核对。" }),
        field("quoteMaterialUnitPrice", "板材采购价（元/kg）", "使用本厂当前采购价"),
        field("quoteUtilizationRate", "排料利用率（%）", "例如：85"),
        field("quoteAcrylicBendCost", "折弯/粘接（元/件）", "没有可填0", { required: false }),
        field("quoteAcrylicAssemblyCost", "组装与防刮包装（元/件）", "没有可填0", { required: false }),
        ...commonTimeFields
      ])
    }),
    metal: Object.freeze({
      id: "metal",
      label: "五金加工专属公式",
      categoryLabel: "五金加工",
      formula: "长×宽×厚度×材料密度计算净重，再按套料利用率计算材料成本；切割、冲压、折弯、焊接和表面处理分别计费。",
      source: "密度、套料利用率、公差与表面处理必须按实际材质、图纸和生产路线确认。",
      calibration: Object.freeze(["各材质采购价（元/kg）", "材料密度与套料利用率", "切割/冲压机时费", "每折弯或每工序费用", "电镀、拉丝、烤漆等表面处理"]),
      fields: Object.freeze([
        field("quoteMetalWidthMm", "下料宽（mm）", "按图纸展开尺寸"),
        field("quoteMetalHeightMm", "下料长（mm）", "按图纸展开尺寸"),
        field("quoteMetalThicknessMm", "材料厚度（mm）", "按图纸填写"),
        field("quoteMetalDensity", "材料密度（g/cm³）", "按材质确认", { defaultValue: "7.85", help: "7.85仅为普通钢材参考值，不锈钢、铝、铜等必须改为实际值。" }),
        field("quoteMaterialUnitPrice", "金属采购价（元/kg）", "使用本厂当前采购价"),
        field("quoteUtilizationRate", "套料利用率（%）", "例如：85"),
        field("quoteMetalCutCost", "切割/冲压（元/件）", "没有可填0", { required: false }),
        field("quoteMetalBendCount", "折弯次数（次/件）", "没有可填0", { required: false }),
        field("quoteMetalBendUnitCost", "每次折弯费用（元）", "没有可填0", { required: false }),
        field("quoteMetalSurfaceCost", "表面处理（元/件）", "没有可填0", { required: false }),
        ...commonTimeFields
      ])
    }),
    textile_bag: Object.freeze({
      id: "textile_bag",
      label: "布袋纺织专属公式",
      categoryLabel: "布袋纺织",
      formula: "按唛架/排料得到单件净面料面积，结合克重换算净重，再按利用率计入裁剪损耗；印花、车缝、辅料和包装分别计费。",
      source: "净面积应来自实际纸样或唛架；缩水、对条对格、色差和残损不能用固定通用比例猜测。",
      calibration: Object.freeze(["常用面料克重与采购价", "实际唛架/排料利用率", "裁剪与车缝标准分钟", "丝印/热转印/刺绣费用", "提手、拉链、包装等辅料"]),
      fields: Object.freeze([
        field("quoteTextileNetAreaM2", "单件净面料面积（㎡/件）", "来自纸样或唛架"),
        field("quoteTextileGsm", "面料克重（g/㎡）", "例如：100"),
        field("quoteMaterialUnitPrice", "面料采购价（元/kg）", "使用本厂当前采购价"),
        field("quoteUtilizationRate", "排料利用率（%）", "例如：85"),
        field("quoteTextilePrintCost", "印花/丝印（元/件）", "不印刷可填0", { required: false }),
        field("quoteTextileAccessoryCost", "提手/拉链/包装辅料（元/件）", "没有可填0", { required: false }),
        ...commonTimeFields
      ])
    }),
    generic_weight: Object.freeze({
      id: "generic_weight",
      label: "材料耗用与工时公式",
      categoryLabel: "其他制造",
      formula: "按单件净耗用、实际采购价、材料利用率、人工和设备标准时间核算。",
      source: "净耗用、采购价和标准工时必须来自本厂记录。",
      calibration: Object.freeze(["单件净耗用", "实际采购价", "材料利用率", "完全人工与设备机时"]),
      fields: Object.freeze([
        field("quoteUnitUsage", "单件材料净耗用", "按图纸、排料或称重填写"),
        field("quoteMaterialUnitPrice", "材料采购价（元/耗用单位）", "使用本厂当前采购价"),
        field("quoteUtilizationRate", "材料利用率（%）", "例如：90"),
        ...commonTimeFields
      ])
    }),
    electronics_bom: Object.freeze({
      id: "electronics_bom",
      label: "电子BOM专属公式",
      categoryLabel: "电子配件",
      formula: "BOM单件成本、贴装/焊点、测试、组装人工和设备标准时间分别核算。",
      source: "BOM、点数、测试方案和良率必须使用当前订单或本厂已确认版本。",
      calibration: Object.freeze(["BOM单件成本", "贴装/焊点单价", "测试费用", "组装标准工时"]),
      fields: Object.freeze([
        field("quoteBomCost", "BOM单件成本（元/件）", "元器件、PCB、外壳、线材等"),
        field("quoteSmtPoints", "贴装/焊点数（点/件）", "没有可填0", { required: false }),
        field("quoteSmtPointPrice", "贴装单价（元/点）", "按本厂或供应商价格", { required: false }),
        field("quoteTestCost", "测试费用（元/件）", "功能/老化/安规测试", { required: false }),
        ...commonTimeFields
      ])
    })
  });

  const templateStrategies = Object.freeze({
    "亚克力展示架": "acrylic",
    "五金钣金": "metal",
    "金属标牌/徽章": "metal",
    "棉布纺织": "textile_bag",
    "无纺布袋": "textile_bag",
    "服装/内衣/袜子": "textile_bag"
  });

  function resolveStrategy(category, templateName) {
    const explicit = templateStrategies[String(templateName || "")];
    if (explicit) return strategies[explicit];
    if (String(category || "") === "包装印刷") return strategies.packaging_printing;
    if (String(category || "") === "五金加工") return strategies.metal;
    if (String(category || "") === "纺织服装") return strategies.textile_bag;
    if (String(category || "") === "电子配件") return strategies.electronics_bom;
    return strategies.generic_weight;
  }

  function toNumber(value) {
    if (typeof value === "string") value = value.trim().replace(/,/g, "");
    const number = Number(value);
    return Number.isFinite(number) ? number : 0;
  }

  function toRate(value, fallback = 0) {
    const number = toNumber(value);
    if (!number) return fallback;
    return number > 1 ? number / 100 : number;
  }

  function calculate(strategyId, input = {}) {
    const strategy = strategies[strategyId] || strategies.generic_weight;
    const quantity = toNumber(input.quantity);
    if (!(quantity > 0)) return { ok: false, error: "产品数量必须大于0。" };
    const values = input.values && typeof input.values === "object" ? input.values : {};
    const laborMinutes = toNumber(values.quoteLaborMinutes);
    const machineMinutes = toNumber(values.quoteMachineMinutes);
    const laborHourly = toNumber(input.laborHourly);
    const machineHourly = toNumber(input.machineHourly);
    if (laborMinutes > 0 && !(laborHourly > 0)) return { ok: false, error: "价格表还没有填写完全人工成本（元/小时）。" };
    if (machineMinutes > 0 && !(machineHourly > 0)) return { ok: false, error: "价格表还没有填写设备机时费（元/小时）。" };
    const laborCost = laborMinutes * laborHourly / 60 * quantity;
    const machineCost = machineMinutes * machineHourly / 60 * quantity;
    const utilization = toRate(values.quoteUtilizationRate, toRate(input.defaultUtilization, 0));
    const requirePositive = (id, label) => {
      const value = toNumber(values[id]);
      if (!(value > 0)) throw new Error(`请填写${label}。`);
      return value;
    };
    const requireUtilization = () => {
      if (!(utilization > 0 && utilization <= 1)) throw new Error("材料利用率必须大于0且不超过100%。");
      return utilization;
    };
    let materialCost = 0;
    let extraDirectCost = 0;
    let materialLabel = "";
    let extraLabel = "";
    let formulaInput = {};
    const includedProcessNames = [];
    try {
      if (strategy.id === "packaging_printing") {
        const widthMm = requirePositive("quotePackageFlatWidthMm", "单件展开宽");
        const heightMm = requirePositive("quotePackageFlatHeightMm", "单件展开高");
        const gsm = requirePositive("quotePackageGsm", "纸张/纸板克重");
        const pricePerKg = requirePositive("quoteMaterialUnitPrice", "纸张采购价");
        const rate = requireUtilization();
        const netKgPerPiece = widthMm * heightMm / 1_000_000 * gsm / 1000;
        materialCost = netKgPerPiece / rate * pricePerKg * quantity;
        materialLabel = `${widthMm}×${heightMm}mm × ${gsm}g/㎡ = ${netKgPerPiece.toFixed(4)}kg/件 ÷ 利用率${(rate * 100).toFixed(1)}%`;
        formulaInput = { widthMm, heightMm, gsm, pricePerKg, utilizationRate: rate, netKgPerPiece };
      } else if (strategy.id === "acrylic") {
        const widthMm = requirePositive("quoteAcrylicWidthMm", "板件宽");
        const heightMm = requirePositive("quoteAcrylicHeightMm", "板件高");
        const thicknessMm = requirePositive("quoteAcrylicThicknessMm", "板材厚度");
        const densityGcm3 = requirePositive("quoteAcrylicDensity", "材料密度");
        const pricePerKg = requirePositive("quoteMaterialUnitPrice", "板材采购价");
        const rate = requireUtilization();
        const netKgPerPiece = widthMm * heightMm * thicknessMm * densityGcm3 / 1_000_000;
        const bendCost = toNumber(values.quoteAcrylicBendCost);
        const assemblyCost = toNumber(values.quoteAcrylicAssemblyCost);
        if (bendCost > 0) includedProcessNames.push("折弯", "粘接");
        if (assemblyCost > 0) includedProcessNames.push("组装", "包装", "防刮包装");
        materialCost = netKgPerPiece / rate * pricePerKg * quantity;
        extraDirectCost = (bendCost + assemblyCost) * quantity;
        materialLabel = `${widthMm}×${heightMm}×${thicknessMm}mm × ${densityGcm3}g/cm³ = ${netKgPerPiece.toFixed(4)}kg/件 ÷ 利用率${(rate * 100).toFixed(1)}%`;
        extraLabel = `折弯/粘接 ¥${bendCost.toFixed(3)}/件 + 组装防刮 ¥${assemblyCost.toFixed(3)}/件`;
        formulaInput = { widthMm, heightMm, thicknessMm, densityGcm3, pricePerKg, utilizationRate: rate, netKgPerPiece, bendCost, assemblyCost };
      } else if (strategy.id === "metal") {
        const widthMm = requirePositive("quoteMetalWidthMm", "下料宽");
        const heightMm = requirePositive("quoteMetalHeightMm", "下料长");
        const thicknessMm = requirePositive("quoteMetalThicknessMm", "材料厚度");
        const densityGcm3 = requirePositive("quoteMetalDensity", "材料密度");
        const pricePerKg = requirePositive("quoteMaterialUnitPrice", "金属采购价");
        const rate = requireUtilization();
        const netKgPerPiece = widthMm * heightMm * thicknessMm * densityGcm3 / 1_000_000;
        const cutCost = toNumber(values.quoteMetalCutCost);
        const bendCount = toNumber(values.quoteMetalBendCount);
        const bendUnitCost = toNumber(values.quoteMetalBendUnitCost);
        const surfaceCost = toNumber(values.quoteMetalSurfaceCost);
        if (cutCost > 0) includedProcessNames.push("切割", "激光切割", "冲压");
        if (bendCount > 0 && bendUnitCost > 0) includedProcessNames.push("折弯");
        if (surfaceCost > 0) includedProcessNames.push("表面处理", "电镀", "拉丝", "烤漆");
        materialCost = netKgPerPiece / rate * pricePerKg * quantity;
        extraDirectCost = (cutCost + bendCount * bendUnitCost + surfaceCost) * quantity;
        materialLabel = `${widthMm}×${heightMm}×${thicknessMm}mm × ${densityGcm3}g/cm³ = ${netKgPerPiece.toFixed(4)}kg/件 ÷ 利用率${(rate * 100).toFixed(1)}%`;
        extraLabel = `切割/冲压 ¥${cutCost.toFixed(3)}/件 + ${bendCount}折×¥${bendUnitCost.toFixed(3)} + 表面处理 ¥${surfaceCost.toFixed(3)}/件`;
        formulaInput = { widthMm, heightMm, thicknessMm, densityGcm3, pricePerKg, utilizationRate: rate, netKgPerPiece, cutCost, bendCount, bendUnitCost, surfaceCost };
      } else if (strategy.id === "textile_bag") {
        const netAreaM2 = requirePositive("quoteTextileNetAreaM2", "单件净面料面积");
        const gsm = requirePositive("quoteTextileGsm", "面料克重");
        const pricePerKg = requirePositive("quoteMaterialUnitPrice", "面料采购价");
        const rate = requireUtilization();
        const netKgPerPiece = netAreaM2 * gsm / 1000;
        const printCost = toNumber(values.quoteTextilePrintCost);
        const accessoryCost = toNumber(values.quoteTextileAccessoryCost);
        if (printCost > 0) includedProcessNames.push("印花", "丝印", "热转印", "刺绣");
        if (accessoryCost > 0) includedProcessNames.push("辅料", "提手", "拉链", "包装");
        materialCost = netKgPerPiece / rate * pricePerKg * quantity;
        extraDirectCost = (printCost + accessoryCost) * quantity;
        materialLabel = `${netAreaM2.toFixed(4)}㎡/件 × ${gsm}g/㎡ = ${netKgPerPiece.toFixed(4)}kg/件 ÷ 利用率${(rate * 100).toFixed(1)}%`;
        extraLabel = `印花/丝印 ¥${printCost.toFixed(3)}/件 + 辅料包装 ¥${accessoryCost.toFixed(3)}/件`;
        formulaInput = { netAreaM2, gsm, pricePerKg, utilizationRate: rate, netKgPerPiece, printCost, accessoryCost };
      } else if (strategy.id === "electronics_bom") {
        const bomCost = requirePositive("quoteBomCost", "BOM单件成本");
        const points = toNumber(values.quoteSmtPoints);
        const pointPrice = toNumber(values.quoteSmtPointPrice);
        const testCost = toNumber(values.quoteTestCost);
        if (points > 0 && !(pointPrice > 0)) throw new Error("已填写贴装/焊点数，请同时填写每点单价。");
        if (points > 0 && pointPrice > 0) includedProcessNames.push("SMT", "贴装", "焊点", "焊接");
        if (testCost > 0) includedProcessNames.push("测试", "功能测试", "老化测试");
        materialCost = bomCost * quantity;
        extraDirectCost = (points * pointPrice + testCost) * quantity;
        materialLabel = `BOM ¥${bomCost.toFixed(3)}/件 × ${quantity.toFixed(0)}件`;
        extraLabel = `贴装 ${points.toFixed(0)}点 × ¥${pointPrice.toFixed(4)} + 测试 ¥${testCost.toFixed(3)}/件`;
        formulaInput = { bomCost, points, pointPrice, testCost };
      } else {
        const usage = requirePositive("quoteUnitUsage", "单件材料净耗用");
        const materialPrice = requirePositive("quoteMaterialUnitPrice", "材料采购价");
        const rate = requireUtilization();
        materialCost = usage * materialPrice * quantity / rate;
        materialLabel = `${usage.toFixed(4)}单位/件 × ¥${materialPrice.toFixed(3)} ÷ 利用率${(rate * 100).toFixed(1)}%`;
        formulaInput = { usage, materialPrice, utilizationRate: rate };
      }
    } catch (error) {
      return { ok: false, error: String(error && error.message || error) };
    }
    return {
      ok: true,
      schemaVersion: 1,
      engine: "industry-quote-v2",
      strategyId: strategy.id,
      strategyLabel: strategy.label,
      category: strategy.categoryLabel,
      quantity,
      materialCost,
      materialUnitCost: materialCost / quantity,
      extraDirectCost,
      laborCost,
      machineCost,
      materialLabel,
      extraLabel,
      includedProcessNames: [...new Set(includedProcessNames)],
      basis: `${strategy.formula} 本单使用本厂已校准数据。`,
      input: { ...formulaInput, laborMinutes, machineMinutes, laborHourly, machineHourly, quantity },
      result: { materialCost, extraDirectCost, laborCost, machineCost }
    };
  }

  const fieldIds = Object.freeze([...new Set(Object.values(strategies).flatMap(item => item.fields.map(item => item.id)))]);

  return Object.freeze({
    schemaVersion: 1,
    categories,
    descriptions,
    productTemplateExtensions,
    presets,
    strategies,
    fieldIds,
    resolveStrategy,
    calculate
  });
});
