CSharp:Condition Variable Pattern

项目结构:

c626b199-2e1f-4f07-8c05-185dd46f7146

 

/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : BusinessOrder.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 业务跟单实体(业务环节)。
/// <para>记录客户跟单与商务信息:客户等级、商务条款、跟单员与业务状态。</para>
/// </summary>
public sealed class BusinessOrder
{
    /// <summary>
    /// 业务跟单编号(唯一标识)。
    /// </summary>
    public string BusinessNo { get; set; } = string.Empty;

    /// <summary>
    /// 客户等级(例如:VIP、普通、潜在)。
    /// </summary>
    public string CustomerLevel { get; set; } = string.Empty;

    /// <summary>
    /// 商务条款(例如:预付 30%,尾款发货前结清)。
    /// </summary>
    public string Terms { get; set; } = string.Empty;

    /// <summary>
    /// 跟单员姓名。
    /// </summary>
    public string AccountManager { get; set; } = string.Empty;

    /// <summary>
    /// 客户意向度评分(0-100)。
    /// </summary>
    public int IntentionScore { get; set; }

    /// <summary>
    /// 是否已确认商务条款。
    /// </summary>
    public bool IsConfirmed { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:结构型模式 Structural Patterns  装饰器模式 Decorator Pattern  演示业务层
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : DesignDrawing.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 设计制图实体(设计制图环节)。
/// <para>记录珠宝款式设计图:图纸编号、设计版本、工艺要求与审核状态。</para>
/// </summary>
public sealed class DesignDrawing
{
    /// <summary>
    /// 图纸编号(唯一标识)。
    /// </summary>
    public string DrawingNo { get; set; } = string.Empty;

    /// <summary>
    /// 设计款式名称。
    /// </summary>
    public string StyleName { get; set; } = string.Empty;

    /// <summary>
    /// 设计版本号(设计迭代递增)。
    /// </summary>
    public int Version { get; set; } = 1;

    /// <summary>
    /// 设计师姓名。
    /// </summary>
    public string DesignerName { get; set; } = string.Empty;

    /// <summary>
    /// 工艺要求描述(例如:爪镶、抛光、刻字)。
    /// </summary>
    public string CraftRequirement { get; set; } = string.Empty;

    /// <summary>
    /// 是否已审核通过(未通过不得进入生产环节)。
    /// </summary>
    public bool IsApproved { get; set; }

    /// <summary>
    /// 审核人姓名。
    /// </summary>
    public string ApprovedBy { get; set; } = string.Empty;

    /// <summary>
    /// 设计完成时间。
    /// </summary>
    public DateTime DesignedAt { get; set; } = DateTime.Now;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : FinanceInvoice.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 财务发票/结算实体(财务环节)。
/// <para>记录订单的财务结算信息:采购付款、销售收款、发票开具与结算状态。</para>
/// </summary>
public sealed class FinanceInvoice
{
    /// <summary>
    /// 财务结算单号(唯一标识)。
    /// </summary>
    public string SettlementNo { get; set; } = string.Empty;

    /// <summary>
    /// 采购付款金额(元)。
    /// </summary>
    public decimal PurchasePayment { get; set; }

    /// <summary>
    /// 销售收款金额(元)。
    /// </summary>
    public decimal SalesReceipt { get; set; }

    /// <summary>
    /// 毛利金额(元,销售收款 - 采购付款)。
    /// </summary>
    public decimal GrossProfit { get; set; }

    /// <summary>
    /// 发票号码(增值税发票)。
    /// </summary>
    public string InvoiceNo { get; set; } = string.Empty;

    /// <summary>
    /// 是否已结算完成。
    /// </summary>
    public bool IsSettled { get; set; }

    /// <summary>
    /// 结算完成时间。
    /// </summary>
    public DateTime? SettledAt { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : HrRecord.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 人事行政记录实体(人事行政环节)。
/// <para>记录订单相关的行政与人事协同信息:经办员工、考勤与行政事务状态。</para>
/// </summary>
public sealed class HrRecord
{
    /// <summary>
    /// 人事行政记录编号(唯一标识)。
    /// </summary>
    public string HrNo { get; set; } = string.Empty;

    /// <summary>
    /// 经办员工工号。
    /// </summary>
    public string EmployeeNo { get; set; } = string.Empty;

    /// <summary>
    /// 经办员工姓名。
    /// </summary>
    public string EmployeeName { get; set; } = string.Empty;

    /// <summary>
    /// 所属部门(例如:生产部、销售部、设计部)。
    /// </summary>
    public string Department { get; set; } = string.Empty;

    /// <summary>
    /// 行政事务描述(例如:会议室预订、差旅安排、盖章用印)。
    /// </summary>
    public string AdminTask { get; set; } = string.Empty;

    /// <summary>
    /// 行政事务是否已完成。
    /// </summary>
    public bool IsCompleted { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ItAsset.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// IT 资产/系统记录实体(IT 环节)。
/// <para>记录订单相关的 IT 协同信息:业务系统单据、设备资产与权限处理状态。</para>
/// </summary>
public sealed class ItAsset
{
    /// <summary>
    /// IT 记录编号(唯一标识)。
    /// </summary>
    public string ItNo { get; set; } = string.Empty;

    /// <summary>
    /// 涉及的业务系统名称(例如:ERP、MES、CRM、WMS)。
    /// </summary>
    public string SystemName { get; set; } = string.Empty;

    /// <summary>
    /// 系统单据号(ERP 订单号 / MES 工单号等)。
    /// </summary>
    public string SystemDocNo { get; set; } = string.Empty;

    /// <summary>
    /// 涉及的设备资产编号(可为空)。
    /// </summary>
    public string AssetNo { get; set; } = string.Empty;

    /// <summary>
    /// 权限处理描述(例如:为跟单员开通 CRM 订单查看权限)。
    /// </summary>
    public string PermissionTask { get; set; } = string.Empty;

    /// <summary>
    /// 是否已完成。
    /// </summary>
    public bool IsCompleted { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : JewelryOrder.cs

 */

using JewelryWorkflow.Domain.Enums;

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 珠宝订单(主订单聚合根)。
/// <para>贯穿全程业务流程的核心实体:一个订单从原料采购核验开始,
/// 依次经过设计、生产、质检、包装、物流,并由财务/营销/业务/人事/IT/培训
/// 等支持环节协同处理。聚合根负责维护订单级状态机。</para>
/// </summary>
public sealed class JewelryOrder
{
    /// <summary>
    /// 订单唯一编号(流水线上下文与日志中使用的业务主键)。
    /// </summary>
    public long OrderId { get; set; }

    /// <summary>
    /// 客户名称。
    /// </summary>
    public string CustomerName { get; set; } = string.Empty;

    /// <summary>
    /// 订单商品描述(例如:18K金镶钻戒指 1 克拉)。
    /// </summary>
    public string ProductDescription { get; set; } = string.Empty;

    /// <summary>
    /// 订单金额(元)。
    /// </summary>
    public decimal OrderAmount { get; set; }

    /// <summary>
    /// 订单创建时间。
    /// </summary>
    public DateTime CreatedAt { get; set; } = DateTime.Now;

    /// <summary>
    /// 订单状态(状态机流转:已创建 → 流程执行中 → 已完成/已失败)。
    /// </summary>
    public OrderStatus Status { get; set; } = OrderStatus.Created;

    /// <summary>
    /// 当前已完成的流程环节数(用于进度展示与日志输出)。
    /// </summary>
    public int CompletedStageCount { get; set; }

    /// <summary>
    /// 全流程完成时间(为 null 表示尚未完成)。
    /// </summary>
    public DateTime? CompletedAt { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogisticsWaybill.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 物流运单实体(物流环节)。
/// <para>记录成品出库后的物流运输信息:承运商、运单号、收件信息与运输状态。</para>
/// </summary>
public sealed class LogisticsWaybill
{
    /// <summary>
    /// 物流运单号(唯一标识)。
    /// </summary>
    public string WaybillNo { get; set; } = string.Empty;

    /// <summary>
    /// 关联的包装单号。
    /// </summary>
    public string PackageNo { get; set; } = string.Empty;

    /// <summary>
    /// 承运商名称(例如:顺丰、EMS、DHL)。
    /// </summary>
    public string CarrierName { get; set; } = string.Empty;

    /// <summary>
    /// 收货人姓名。
    /// </summary>
    public string ReceiverName { get; set; } = string.Empty;

    /// <summary>
    /// 收货地址。
    /// </summary>
    public string ReceiverAddress { get; set; } = string.Empty;

    /// <summary>
    /// 是否已发货。
    /// </summary>
    public bool IsShipped { get; set; }

    /// <summary>
    /// 发货时间。
    /// </summary>
    public DateTime? ShippedAt { get; set; }

    /// <summary>
    /// 运输状态描述(例如:运输中、已签收)。
    /// </summary>
    public string TrackingStatus { get; set; } = "待发货";
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:结# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MarketingCampaign.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 营销推广活动实体(营销推广环节)。
/// <para>记录面向该订单/产品的营销活动信息:推广渠道、活动主题、预算与状态。</para>
/// </summary>
public sealed class MarketingCampaign
{
    /// <summary>
    /// 营销活动编号(唯一标识)。
    /// </summary>
    public string CampaignNo { get; set; } = string.Empty;

    /// <summary>
    /// 活动主题名称。
    /// </summary>
    public string CampaignName { get; set; } = string.Empty;

    /// <summary>
    /// 推广渠道(例如:抖音、小红书、天猫、线下门店)。
    /// </summary>
    public string Channel { get; set; } = string.Empty;

    /// <summary>
    /// 投放预算(元)。
    /// </summary>
    public decimal Budget { get; set; }

    /// <summary>
    /// 预估曝光量(次)。
    /// </summary>
    public long EstimatedImpressions { get; set; }

    /// <summary>
    /// 活动是否已上线。
    /// </summary>
    public bool IsLaunched { get; set; }

    /// <summary>
    /// 活动上线时间。
    /// </summary>
    public DateTime? LaunchedAt { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MaterialBatch.cs

 */

using JewelryWorkflow.Domain.Enums;

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 原料批次实体(原料采购核验环节)。
/// <para>记录一批珠宝原料(金料/银料/钻石/宝石等)的采购信息、证书信息与核验状态。</para>
/// </summary>
public sealed class MaterialBatch
{
    /// <summary>
    /// 原料批次号(唯一标识)。
    /// </summary>
    public string BatchNo { get; set; } = string.Empty;

    /// <summary>
    /// 原料类型(例如:足金、18K金、钻石、红宝石)。
    /// </summary>
    public string MaterialType { get; set; } = string.Empty;

    /// <summary>
    /// 原料重量(克)。
    /// </summary>
    public decimal WeightGram { get; set; }

    /// <summary>
    /// 原料成色(例如足金 999、18K、750)。
    /// </summary>
    public string Purity { get; set; } = string.Empty;

    /// <summary>
    /// 供应商名称。
    /// </summary>
    public string SupplierName { get; set; } = string.Empty;

    /// <summary>
    /// 采购价格(元)。
    /// </summary>
    public decimal PurchasePrice { get; set; }

    /// <summary>
    /// 原料质检证书编号(采购核验时校验)。
    /// </summary>
    public string CertificateNo { get; set; } = string.Empty;

    /// <summary>
    /// 核验状态(待核验 → 核验中 → 合格入库/不合格退货)。
    /// </summary>
    public MaterialStatus Status { get; set; } = MaterialStatus.Pending;

    /// <summary>
    /// 核验备注(记录核验结果与操作人信息)。
    /// </summary>
    public string VerifyRemark { get; set; } = string.Empty;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PackageInfo.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 包装信息实体(包装环节)。
/// <para>记录成品的包装方案:包装类型、防伪标识、装箱信息。</para>
/// </summary>
public sealed class PackageInfo
{
    /// <summary>
    /// 包装单号(唯一标识)。
    /// </summary>
    public string PackageNo { get; set; } = string.Empty;

    /// <summary>
    /// 关联的质检报告编号。
    /// </summary>
    public string QualityReportNo { get; set; } = string.Empty;

    /// <summary>
    /// 包装类型(例如:礼盒装、精品盒、裸钻袋)。
    /// </summary>
    public string PackageType { get; set; } = string.Empty;

    /// <summary>
    /// 是否包含防伪标识(二维码/镭射标)。
    /// </summary>
    public bool HasAntiFakeTag { get; set; }

    /// <summary>
    /// 装箱数量(件)。
    /// </summary>
    public int BoxCount { get; set; }

    /// <summary>
    /// 包装完成时间。
    /// </summary>
    public DateTime PackagedAt { get; set; } = DateTime.Now;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ProductionOrder.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 生产工单实体(加工生产环节)。
/// <para>记录一条珠宝的加工生产任务:工艺路线、投入原料、产出重量与生产状态。</para>
/// </summary>
public sealed class ProductionOrder
{
    /// <summary>
    /// 生产工单号(唯一标识)。
    /// </summary>
    public string WorkOrderNo { get; set; } = string.Empty;

    /// <summary>
    /// 关联的设计图纸编号。
    /// </summary>
    public string DrawingNo { get; set; } = string.Empty;

    /// <summary>
    /// 使用的原料批次号。
    /// </summary>
    public string MaterialBatchNo { get; set; } = string.Empty;

    /// <summary>
    /// 工艺路线(用分号分隔的工序列表,例如:倒模;执模;镶石;抛光)。
    /// </summary>
    public string ProcessRoute { get; set; } = string.Empty;

    /// <summary>
    /// 投入原料重量(克)。
    /// </summary>
    public decimal InputWeightGram { get; set; }

    /// <summary>
    /// 产出成品重量(克,一般略小于投入,存在加工损耗)。
    /// </summary>
    public decimal OutputWeightGram { get; set; }

    /// <summary>
    /// 加工损耗率(百分比,用于成本核算)。
    /// </summary>
    public decimal LossRatePercent { get; set; }

    /// <summary>
    /// 是否生产完成。
    /// </summary>
    public bool IsFinished { get; set; }

    /// <summary>
    /// 生产完成时间。
    /// </summary>
    public DateTime? FinishedAt { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : QualityReport.cs

 */

using JewelryWorkflow.Domain.Enums;

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 质检报告实体(质检环节)。
/// <para>记录成品的质检结果:成色、重量复称、工艺评分与质检等级。
/// 质检等级决定是否放行进入包装环节。</para>
/// </summary>
public sealed class QualityReport
{
    /// <summary>
    /// 质检报告编号(唯一标识)。
    /// </summary>
    public string ReportNo { get; set; } = string.Empty;

    /// <summary>
    /// 关联的生产工单号。
    /// </summary>
    public string WorkOrderNo { get; set; } = string.Empty;

    /// <summary>
    /// 质检员姓名。
    /// </summary>
    public string InspectorName { get; set; } = string.Empty;

    /// <summary>
    /// 实测成色(例如 999、18K)。
    /// </summary>
    public string MeasuredPurity { get; set; } = string.Empty;

    /// <summary>
    /// 复称重量(克)。
    /// </summary>
    public decimal MeasuredWeightGram { get; set; }

    /// <summary>
    /// 工艺评分(0-100 分)。
    /// </summary>
    public int CraftScore { get; set; }

    /// <summary>
    /// 质检等级(优等/合格/次品/废品)。
    /// </summary>
    public QualityGrade Grade { get; set; } = QualityGrade.Qualified;

    /// <summary>
    /// 是否通过质检(优等与合格放行,次品返工,废品报废)。
    /// </summary>
    public bool IsPassed { get; set; }

    /// <summary>
    /// 质检完成时间。
    /// </summary>
    public DateTime InspectedAt { get; set; } = DateTime.Now;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : TrainingRecord.cs

 */

namespace JewelryWorkflow.Domain.Entities;

/// <summary>
/// 培训记录实体(培训环节)。
/// <para>记录与该订单关联的员工培训信息:课程、学时、讲师与考核结果。</para>
/// </summary>
public sealed class TrainingRecord
{
    /// <summary>
    /// 培训记录编号(唯一标识)。
    /// </summary>
    public string TrainingNo { get; set; } = string.Empty;

    /// <summary>
    /// 课程名称(例如:珠宝鉴定基础、销售话术训练)。
    /// </summary>
    public string CourseName { get; set; } = string.Empty;

    /// <summary>
    /// 参训员工姓名。
    /// </summary>
    public string TraineeName { get; set; } = string.Empty;

    /// <summary>
    /// 讲师姓名。
    /// </summary>
    public string LecturerName { get; set; } = string.Empty;

    /// <summary>
    /// 培训学时(小时)。
    /// </summary>
    public decimal Hours { get; set; }

    /// <summary>
    /// 考核是否通过。
    /// </summary>
    public bool IsPassed { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MaterialStatus.cs

 */

namespace JewelryWorkflow.Domain.Enums;

/// <summary>
/// 原料批次状态枚举。
/// <para>用于原料采购核验环节的状态流转:待核验 → 核验中 → 合格入库 / 不合格退货。</para>
/// </summary>
public enum MaterialStatus
{
    /// <summary>
    /// 待核验:原料已到货,等待质检与证书核验。
    /// </summary>
    Pending = 0,

    /// <summary>
    /// 核验中:正在执行供应商资质与原料证书核验。
    /// </summary>
    Verifying = 1,

    /// <summary>
    /// 合格入库:核验通过,允许进入生产环节。
    /// </summary>
    Approved = 2,

    /// <summary>
    /// 不合格退货:核验不通过,退回供应商。
    /// </summary>
    Rejected = 3
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : BusinessRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 业务环节输入 DTO。
/// <para>由业务端提交:客户等级、商务条款与跟单信息。</para>
/// </summary>
public sealed class BusinessRequestDto
{
    /// <summary>
    /// 客户等级(例如:VIP、普通、潜在)。
    /// </summary>
    public string CustomerLevel { get; set; } = string.Empty;

    /// <summary>
    /// 商务条款(例如:预付 30%,尾款发货前结清)。
    /// </summary>
    public string Terms { get; set; } = string.Empty;

    /// <summary>
    /// 跟单员姓名。
    /// </summary>
    public string AccountManager { get; set; } = string.Empty;

    /// <summary>
    /// 客户意向度评分(0-100)。
    /// </summary>
    public int IntentionScore { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : DesignRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 设计制图环节输入 DTO。
/// <para>由设计端提交:款式信息与工艺要求。</para>
/// </summary>
public sealed class DesignRequestDto
{
    /// <summary>
    /// 设计款式名称(例如:经典六爪钻戒)。
    /// </summary>
    public string StyleName { get; set; } = string.Empty;

    /// <summary>
    /// 设计师姓名。
    /// </summary>
    public string DesignerName { get; set; } = string.Empty;

    /// <summary>
    /// 工艺要求描述(例如:爪镶、抛光、内圈刻字)。
    /// </summary>
    public string CraftRequirement { get; set; } = string.Empty;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : FinanceRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 财务环节输入 DTO。
/// <para>由财务端提交:采购付款、销售收款与开票要求。</para>
/// </summary>
public sealed class FinanceRequestDto
{
    /// <summary>
    /// 采购付款金额(元)。
    /// </summary>
    public decimal PurchasePayment { get; set; }

    /// <summary>
    /// 销售收款金额(元)。
    /// </summary>
    public decimal SalesReceipt { get; set; }

    /// <summary>
    /// 是否需要开具增值税发票。
    /// </summary>
    public bool NeedInvoice { get; set; } = true;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : HrRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 人事行政环节输入 DTO。
/// <para>由行政端提交:经办员工与行政事务信息。</para>
/// </summary>
public sealed class HrRequestDto
{
    /// <summary>
    /// 经办员工工号。
    /// </summary>
    public string EmployeeNo { get; set; } = string.Empty;

    /// <summary>
    /// 经办员工姓名。
    /// </summary>
    public string EmployeeName { get; set; } = string.Empty;

    /// <summary>
    /// 所属部门。
    /// </summary>
    public string Department { get; set; } = string.Empty;

    /// <summary>
    /// 行政事务描述(例如:会议室预订、差旅安排、盖章用印)。
    /// </summary>
    public string AdminTask { get; set; } = string.Empty;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ItRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// IT 环节输入 DTO。
/// <para>由 IT 端提交:涉及的系统、设备与权限任务。</para>
/// </summary>
public sealed class ItRequestDto
{
    /// <summary>
    /// 涉及的业务系统名称(例如:ERP、MES、CRM、WMS)。
    /// </summary>
    public string SystemName { get; set; } = string.Empty;

    /// <summary>
    /// 涉及的设备资产编号(可为空)。
    /// </summary>
    public string AssetNo { get; set; } = string.Empty;

    /// <summary>
    /// 权限处理描述(例如:为跟单员开通 CRM 订单查看权限)。
    /// </summary>
    public string PermissionTask { get; set; } = string.Empty;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogisticsRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 物流环节输入 DTO。
/// <para>由销售/业务端提交:承运商与收件信息。</para>
/// </summary>
public sealed class LogisticsRequestDto
{
    /// <summary>
    /// 承运商名称(例如:顺丰、EMS、DHL)。
    /// </summary>
    public string CarrierName { get; set; } = string.Empty;

    /// <summary>
    /// 收货人姓名。
    /// </summary>
    public string ReceiverName { get; set; } = string.Empty;

    /// <summary>
    /// 收货地址。
    /// </summary>
    public string ReceiverAddress { get; set; } = string.Empty;
}

/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MarketingRequestDto.cs

 */
namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 营销推广环节输入 DTO。
/// <para>由市场端提交:推广渠道、活动主题与预算。</para>
/// </summary>
public sealed class MarketingRequestDto
{
    /// <summary>
    /// 活动主题名称。
    /// </summary>
    public string CampaignName { get; set; } = string.Empty;

    /// <summary>
    /// 推广渠道(例如:抖音、小红书、天猫、线下门店)。
    /// </summary>
    public string Channel { get; set; } = string.Empty;

    /// <summary>
    /// 投放预算(元)。
    /// </summary>
    public decimal Budget { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MaterialProcurementDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 原料采购核验环节输入 DTO。
/// <para>由业务端提交:待采购/核验原料的基本信息与预算。</para>
/// </summary>
public sealed class MaterialProcurementDto
{
    /// <summary>
    /// 原料类型(例如:足金、18K金、钻石、红宝石)。
    /// </summary>
    public string MaterialType { get; set; } = string.Empty;

    /// <summary>
    /// 原料重量(克)。
    /// </summary>
    public decimal WeightGram { get; set; }

    /// <summary>
    /// 原料成色(例如 999、18K、750)。
    /// </summary>
    public string Purity { get; set; } = string.Empty;

    /// <summary>
    /// 供应商名称。
    /// </summary>
    public string SupplierName { get; set; } = string.Empty;

    /// <summary>
    /// 原料质检证书编号(核验时与第三方核验结果比对)。
    /// </summary>
    public string CertificateNo { get; set; } = string.Empty;

    /// <summary>
    /// 采购预算(元)。
    /// </summary>
    public decimal Budget { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PackagingRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 包装环节输入 DTO。
/// <para>由包装端提交:包装类型、防伪与装箱要求。</para>
/// </summary>
public sealed class PackagingRequestDto
{
    /// <summary>
    /// 包装类型(例如:礼盒装、精品盒、裸钻袋)。
    /// </summary>
    public string PackageType { get; set; } = string.Empty;

    /// <summary>
    /// 是否需要防伪标识(二维码/镭射标)。
    /// </summary>
    public bool HasAntiFakeTag { get; set; } = true;

    /// <summary>
    /// 装箱数量(件)。
    /// </summary>
    public int BoxCount { get; set; } = 1;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ProductionRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 加工生产环节输入 DTO。
/// <para>由生产端提交:工艺路线与目标产出重量。</para>
/// </summary>
public sealed class ProductionRequestDto
{
    /// <summary>
    /// 工艺路线(分号分隔的工序列表,例如:倒模;执模;镶石;抛光)。
    /// </summary>
    public string ProcessRoute { get; set; } = string.Empty;

    /// <summary>
    /// 目标产出重量(克)。
    /// </summary>
    public decimal ExpectedWeightGram { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : QualityInspectionDto.cs

 */

using JewelryWorkflow.Domain.Enums;

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 质检环节输入 DTO。
/// <para>由质检端提交:质检员与最低放行等级(低于该等级视为不合格)。</para>
/// </summary>
public sealed class QualityInspectionDto
{
    /// <summary>
    /// 质检员姓名。
    /// </summary>
    public string InspectorName { get; set; } = string.Empty;

    /// <summary>
    /// 最低放行等级(默认合格品;低于该等级进入返工/报废分支)。
    /// </summary>
    public QualityGrade MinimumPassGrade { get; set; } = QualityGrade.Qualified;
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : TrainingRequestDto.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 培训环节输入 DTO。
/// <para>由人力资源/培训端提交:课程、学员、讲师与学时信息。</para>
/// </summary>
public sealed class TrainingRequestDto
{
    /// <summary>
    /// 课程名称(例如:珠宝鉴定基础、销售话术训练)。
    /// </summary>
    public string CourseName { get; set; } = string.Empty;

    /// <summary>
    /// 参训员工姓名。
    /// </summary>
    public string TraineeName { get; set; } = string.Empty;

    /// <summary>
    /// 讲师姓名。
    /// </summary>
    public string LecturerName { get; set; } = string.Empty;

    /// <summary>
    /// 培训学时(小时)。
    /// </summary>
    public decimal Hours { get; set; }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : WorkflowContext.cs

 */

using System.Collections.Concurrent;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 工作流上下文(贯穿全程业务流程的数据载体,等价于"流程总线")。
/// <para>每个订单在流水线中拥有独立的上下文实例:
/// 携带主订单、12 个环节的输入 DTO 与产出实体、流程状态。
/// 支持线程安全的快照读取(支持流程并行读取),并预留扩展数据槽。</para>
/// </summary>
public sealed class WorkflowContext
{
    // 状态保护锁:保证多线程(主线线程与支持流程线程)安全读写状态字段。
    private readonly object _stateLock = new();

    /// <summary>
    /// 订单唯一编号(与 <see cref="Order"/> 的 OrderId 保持一致)。
    /// </summary>
    public long OrderId { get; }

    /// <summary>
    /// 主订单聚合根。
    /// </summary>
    public JewelryOrder Order { get; }

    /// <summary>
    /// 流程开始时间。
    /// </summary>
    public DateTime StartedAt { get; } = DateTime.Now;

    /// <summary>
    /// 流程完成时间(为 null 表示尚未完成)。
    /// </summary>
    public DateTime? FinishedAt { get; private set; }

    /// <summary>
    /// 流程是否已全部成功完成。
    /// </summary>
    public bool IsCompleted { get; private set; }

    /// <summary>
    /// 失败信息(任一环节失败后记录)。
    /// </summary>
    public string? FailureMessage { get; private set; }

    // ==================== 12 个环节的输入 DTO ====================

    /// <summary>
    /// 原料采购核验环节输入(供应商、证书、重量、预算)。
    /// </summary>
    public MaterialProcurementDto? Procurement { get; set; }

    /// <summary>
    /// 设计制图环节输入(款式、设计师、工艺要求)。
    /// </summary>
    public DesignRequestDto? Design { get; set; }

    /// <summary>
    /// 加工生产环节输入(工艺路线、目标重量)。
    /// </summary>
    public ProductionRequestDto? Production { get; set; }

    /// <summary>
    /// 质检环节输入(质检员、最低放行等级)。
    /// </summary>
    public QualityInspectionDto? Inspection { get; set; }

    /// <summary>
    /// 包装环节输入(包装类型、防伪、装箱数)。
    /// </summary>
    public PackagingRequestDto? Packaging { get; set; }

    /// <summary>
    /// 物流环节输入(承运商、收件人)。
    /// </summary>
    public LogisticsRequestDto? Logistics { get; set; }

    /// <summary>
    /// 财务环节输入(采购付款、销售收款、是否开票)。
    /// </summary>
    public FinanceRequestDto? Finance { get; set; }

    /// <summary>
    /// 营销推广环节输入(渠道、预算、活动名)。
    /// </summary>
    public MarketingRequestDto? Marketing { get; set; }

    /// <summary>
    /// 业务环节输入(客户等级、商务条款、跟单员)。
    /// </summary>
    public BusinessRequestDto? Business { get; set; }

    /// <summary>
    /// 人事行政环节输入(经办员工、部门、行政事务)。
    /// </summary>
    public HrRequestDto? HrAdmin { get; set; }

    /// <summary>
    /// IT 环节输入(系统、设备、权限任务)。
    /// </summary>
    public ItRequestDto? InformationTechnology { get; set; }

    /// <summary>
    /// 培训环节输入(课程、学员、讲师、学时)。
    /// </summary>
    public TrainingRequestDto? Training { get; set; }

    // ==================== 12 个环节的产出实体 ====================

    /// <summary>
    /// 原料采购核验环节产出(原料批次)。
    /// </summary>
    public MaterialBatch? MaterialBatchResult { get; set; }

    /// <summary>
    /// 设计制图环节产出(设计图纸)。
    /// </summary>
    public DesignDrawing? DesignResult { get; set; }

    /// <summary>
    /// 加工生产环节产出(生产工单)。
    /// </summary>
    public ProductionOrder? ProductionResult { get; set; }

    /// <summary>
    /// 质检环节产出(质检报告)。
    /// </summary>
    public QualityReport? QualityResult { get; set; }

    /// <summary>
    /// 包装环节产出(包装信息)。
    /// </summary>
    public PackageInfo? PackagingResult { get; set; }

    /// <summary>
    /// 物流环节产出(物流运单)。
    /// </summary>
    public LogisticsWaybill? LogisticsResult { get; set; }

    /// <summary>
    /// 财务环节产出(结算单)。
    /// </summary>
    public FinanceInvoice? FinanceResult { get; set; }

    /// <summary>
    /// 营销推广环节产出(营销活动)。
    /// </summary>
    public MarketingCampaign? MarketingResult { get; set; }

    /// <summary>
    /// 业务环节产出(跟单记录)。
    /// </summary>
    public BusinessOrder? BusinessResult { get; set; }

    /// <summary>
    /// 人事行政环节产出(人事记录)。
    /// </summary>
    public HrRecord? HrResult { get; set; }

    /// <summary>
    /// IT 环节产出(IT 记录)。
    /// </summary>
    public ItAsset? ItResult { get; set; }

    /// <summary>
    /// 培训环节产出(培训记录)。
    /// </summary>
    public TrainingRecord? TrainingResult { get; set; }

    /// <summary>
    /// 扩展数据槽:供后续业务扩展挂载自定义数据(线程安全字典)。
    /// </summary>
    public ConcurrentDictionary<string, object> Extensions { get; } = new();

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="orderId">订单编号。</param>
    /// <param name="order">主订单聚合根。</param>
    public WorkflowContext(long orderId, JewelryOrder order)
    {
        OrderId = orderId;
        Order = order;
    }

    /// <summary>
    /// 标记流程成功完成(线程安全)。
    /// </summary>
    public void MarkCompleted()
    {
        lock (_stateLock)
        {
            IsCompleted = true;
            FinishedAt = DateTime.Now;
            Order.Status = OrderStatus.Completed;
            Order.CompletedAt = FinishedAt;
            Order.CompletedStageCount = 12;
        }
    }

    /// <summary>
    /// 标记流程失败(线程安全)。
    /// </summary>
    /// <param name="stage">失败环节。</param>
    /// <param name="message">失败原因。</param>
    public void MarkFailed(WorkflowStage stage, string message)
    {
        lock (_stateLock)
        {
            IsCompleted = false;
            FinishedAt = DateTime.Now;
            Order.Status = OrderStatus.Failed;
            Order.CompletedAt = FinishedAt;
            FailureMessage = $"[{stage}] {message}";
        }
    }

    /// <summary>
    /// 创建只读快照(供支持流程并行线程安全读取,避免主流程后续写入造成竞态)。
    /// </summary>
    /// <returns>当前上下文的浅拷贝快照。</returns>
    public WorkflowContext Snapshot()
    {
        // 浅拷贝:引用型产出实体为只读使用,拷贝后不再由主流程修改(各环节产出后即固定)。
        return (WorkflowContext)MemberwiseClone();
    }

    /// <summary>
    /// 已完成的环节数(进度展示用)。
    /// </summary>
    /// <returns>已产出实体的环节数量。</returns>
    public int ProgressCount()
        => (MaterialBatchResult != null ? 1 : 0)
         + (DesignResult != null ? 1 : 0)
         + (ProductionResult != null ? 1 : 0)
         + (QualityResult != null ? 1 : 0)
         + (PackagingResult != null ? 1 : 0)
         + (LogisticsResult != null ? 1 : 0)
         + (FinanceResult != null ? 1 : 0)
         + (MarketingResult != null ? 1 : 0)
         + (BusinessResult != null ? 1 : 0)
         + (HrResult != null ? 1 : 0)
         + (ItResult != null ? 1 : 0)
         + (TrainingResult != null ? 1 : 0);

    /// <summary>
    /// 输出上下文摘要(用于日志打印)。
    /// </summary>
    /// <returns>摘要字符串。</returns>
    public override string ToString()
        => $"Order#{OrderId} {Order.ProductDescription} 进度={ProgressCount()}/12 状态={Order.Status}";
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : WorkflowRunSummary.cs

 */

namespace JewelryWorkflow.Domain.Dtos;

/// <summary>
/// 工作流批量运行汇总结果。
/// <para>记录一批订单在流水线中的总体执行情况,供宿主层展示与监控。</para>
/// </summary>
public sealed class WorkflowRunSummary
{
    /// <summary>
    /// 本批订单总数。
    /// </summary>
    public int Total { get; set; }

    /// <summary>
    /// 成功订单数。
    /// </summary>
    public int SuccessCount { get; set; }

    /// <summary>
    /// 失败订单数。
    /// </summary>
    public int FailureCount { get; set; }

    /// <summary>
    /// 全部订单耗时(毫秒)。
    /// </summary>
    public long ElapsedMilliseconds { get; set; }

    /// <summary>
    /// 输出汇总字符串。
    /// </summary>
    public override string ToString()
        => $"总订单={Total} 成功={SuccessCount} 失败={FailureCount} 耗时={ElapsedMilliseconds}ms";
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : IRepository.cs

 */

using JewelryWorkflow.Domain.Common;

namespace JewelryWorkflow.Domain.Contracts;

/// <summary>
/// 通用仓储契约接口(领域层依赖倒置)。
/// <para>基础设施层(如内存仓储)实现本接口,应用层只依赖抽象,
/// 便于将来替换为 EF Core / Dapper / NoSQL 实现而不改动业务代码。</para>
/// </summary>
/// <typeparam name="TKey">主键类型。</typeparam>
/// <typeparam name="TEntity">实体类型。</typeparam>
public interface IRepository<TKey, TEntity> where TEntity : class
{
    /// <summary>
    /// 按主键查询实体。
    /// </summary>
    /// <param name="key">主键。</param>
    /// <returns>实体或 null。</returns>
    Task<TEntity?> GetByIdAsync(TKey key);

    /// <summary>
    /// 保存实体(新增或更新,由实现决定 Upsert 语义)。
    /// </summary>
    /// <param name="entity">实体。</param>
    /// <returns>保存结果。</returns>
    Task<Result> SaveAsync(TEntity entity);

    /// <summary>
    /// 按主键删除实体。
    /// </summary>
    /// <param name="key">主键。</param>
    /// <returns>是否删除成功。</returns>
    Task<bool> DeleteAsync(TKey key);

    /// <summary>
    /// 查询全部实体。
    /// </summary>
    /// <returns>实体集合。</returns>
    Task<IReadOnlyList<TEntity>> GetAllAsync();
}

  

/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : FileLogOptions.cs

 */
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Infrastructure.Logging;

/// <summary>
/// 分级日期文件日志配置(强类型 Options,可从 appsettings.json 绑定)。
/// <para>目标目录结构:
/// Logs/
///   yyyy-MM-dd/
///     app-info.log      (Information 级)
///     app-error.log     (Error / Critical 级)
///     app-debug.log     (Debug / Trace 级)
///     app-warn.log      (Warning 级)
/// </para>
/// </summary>
public sealed class FileLogOptions
{
    /// <summary>
    /// 日志根目录(相对运行目录或绝对路径,默认 "Logs")。
    /// </summary>
    public string RootPath { get; set; } = "Logs";

    /// <summary>
    /// 是否启用分级文件日志(默认启用;调试时可通过配置关闭)。
    /// </summary>
    public bool Enabled { get; set; } = true;

    /// <summary>
    /// 是否记录作用域(Scopes),默认关闭。
    /// </summary>
    public bool IncludeScopes { get; set; }

    /// <summary>
    /// 批量刷盘间隔(毫秒):消费者攒批后周期性写入磁盘,减少 IO 次数。
    /// </summary>
    public int FlushIntervalMilliseconds { get; set; } = 200;

    /// <summary>
    /// 批量刷盘阈值(条数):队列中待写条数达到该值时立即刷盘。
    /// </summary>
    public int FlushThreshold { get; set; } = 50;

    /// <summary>
    /// 单个日志文件最大字节数(超过后归档为 app-xxx.log.1 等,避免无限增长)。
    /// </summary>
    public long MaxFileBytes { get; set; } = 5 * 1024 * 1024;

    /// <summary>
    /// 根据日志等级计算应写入的文件名(app-info.log / app-error.log / app-debug.log / app-warn.log)。
    /// <para>映射规则:Trace/Debug → debug;Information → info;Warning → warn;Error/Critical → error。</para>
    /// </summary>
    /// <param name="level">日志等级。</param>
    /// <returns>等级文件名(不含目录)。</returns>
    public static string FileNameForLevel(LogLevel level) => level switch
    {
        LogLevel.Trace or LogLevel.Debug => "app-debug.log",
        LogLevel.Information => "app-info.log",
        LogLevel.Warning => "app-warn.log",
        LogLevel.Error or LogLevel.Critical => "app-error.log",
        _ => "app-info.log"
    };
}

/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LeveledFileLogger.cs

 */
using System.Text;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Infrastructure.Logging;

/// <summary>
/// 分级日期文件日志器(实现 <see cref="ILogger"/>)。
/// <para>所有等级/分类的日志统一进入全局 Channel 队列(先入队、立即返回),
/// 由 <see cref="LeveledFileLoggerProvider"/> 的消费者线程异步落盘,
/// 从而保证高并发调用日志时写入方不被磁盘 IO 阻塞。</para>
/// </summary>
internal sealed class LeveledFileLogger : ILogger
{
    // 日志分类(ILogger<T> 的 T 类型全名)。
    private readonly string _categoryName;

    // 宿主 Provider(持有队列与配置)。
    private readonly LeveledFileLoggerProvider _provider;

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="categoryName">日志分类。</param>
    /// <param name="provider">宿主 Provider。</param>
    public LeveledFileLogger(string categoryName, LeveledFileLoggerProvider provider)
    {
        _categoryName = categoryName;
        _provider = provider;
    }

    /// <summary>
    /// 是否启用指定等级(由配置文件日志最小等级控制)。
    /// </summary>
    /// <param name="logLevel">日志等级。</param>
    /// <returns>是否启用。</returns>
    public bool IsEnabled(LogLevel logLevel)
        => logLevel >= _provider.MinimumLevel && logLevel != LogLevel.None;

    /// <summary>
    /// 写入一条日志:格式化消息后入队(不阻塞调用线程)。
    /// </summary>
    /// <typeparam name="TState">状态类型。</typeparam>
    /// <param name="logLevel">日志等级。</param>
    /// <param name="eventId">事件编号。</param>
    /// <param name="state">状态对象(含结构化参数)。</param>
    /// <param name="exception">异常。</param>
    /// <param name="formatter">格式化委托。</param>
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
    {
        // 等级过滤:低于最小等级直接丢弃。
        if (!IsEnabled(logLevel))
        {
            return;
        }

        // 构造日志条目并入队(Channel 写入,O(1) 不阻塞)。
        _provider.Enqueue(new LogEntry
        {
            Time = DateTime.Now,
            Level = logLevel,
            Category = _categoryName,
            Message = formatter(state, exception),
            Exception = exception,
            EventId = eventId
        });
    }

    /// <summary>
    /// 创建作用域(本实现未启用作用域写入,返回空作用域对象)。
    /// </summary>
    /// <typeparam name="TState">状态类型。</typeparam>
    /// <param name="state">状态对象。</param>
    /// <returns>空作用域。</returns>
    public IDisposable? BeginScope<TState>(TState state)
        where TState : notnull
        => NullScope.Instance;

    /// <summary>
    /// 空作用域(BeginScope 的默认返回)。
    /// </summary>
    private sealed class NullScope : IDisposable
    {
        /// <summary>单例实例。</summary>
        public static NullScope Instance { get; } = new();

        /// <summary>空实现。</summary>
        public void Dispose()
        {
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LeveledFileLoggerProvider.cs

 */
using System.Collections.Concurrent;
using System.Threading.Channels;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace JewelryWorkflow.Infrastructure.Logging;

/// <summary>
/// 分级日期文件日志提供器(实现 <see cref="ILoggerProvider"/>)。
/// <para>高并发架构:
/// 1. 无界 Channel 队列承接所有日志写入(SingleReader 优化);
/// 2. 单消费者后台线程批量出队,按"日期目录 + 等级文件"路由;
/// 3. 每文件一个 <see cref="LogFileWriter"/>(ConcurrentDictionary 缓存,含锁与批量刷盘);
/// 4. 定时刷盘(默认 200ms)+ 条数阈值刷盘(默认 50 条),显著降低磁盘 IO。
/// 目录结构:Logs/yyyy-MM-dd/app-{info,error,debug,warn}.log。</para>
/// </summary>
public sealed class LeveledFileLoggerProvider : ILoggerProvider
{
    /// <summary>
    /// 配置(强类型 Options)。
    /// </summary>
    private readonly FileLogOptions _options;

    /// <summary>
    /// 日志队列(无界,单消费者)。
    /// </summary>
    private readonly Channel<LogEntry> _queue;

    /// <summary>
    /// 文件写入器缓存:完整文件路径 → 写入器(按日期+等级维度唯一)。
    /// </summary>
    private readonly ConcurrentDictionary<string, LogFileWriter> _writers = new();

    /// <summary>
    /// 消费者线程(后台常驻,负责批量落盘)。
    /// </summary>
    private readonly Thread _consumerThread;

    /// <summary>
    /// 当前写入的日期键(yyyy-MM-dd;日期变化时清空写入器缓存,切到新目录)。
    /// </summary>
    private string _currentDateKey = string.Empty;

    /// <summary>
    /// 已停止标记(Dispose 后不再入队)。
    /// </summary>
    private volatile bool _stopped;

    /// <summary>
    /// 文件日志最小等级(低于该等级的日志直接丢弃,避免无效 IO)。
    /// </summary>
    public LogLevel MinimumLevel { get; }

    /// <summary>
    /// 构造函数(由 DI 通过 IOptions 注入配置)。
    /// </summary>
    /// <param name="options">分级文件日志配置。</param>
    public LeveledFileLoggerProvider(IOptions<FileLogOptions> options)
    {
        _options = options.Value;
        MinimumLevel = LogLevel.Trace;

        // 无界队列 + 单消费者(高频写入、低频落盘)。
        _queue = Channel.CreateUnbounded<LogEntry>(new UnboundedChannelOptions
        {
            SingleReader = true,
            SingleWriter = false
        });

        // 启动消费者线程(后台守护线程)。
        _consumerThread = new Thread(ConsumeLoop)
        {
            IsBackground = true,
            Name = "LeveledFileLogConsumer"
        };
        _consumerThread.Start();
    }

    /// <summary>
    /// 创建日志器实例(每个 ILogger<T> 分类一个)。
    /// </summary>
    /// <param name="categoryName">日志分类(T 类型全名)。</param>
    /// <returns>分级文件日志器。</returns>
    public ILogger CreateLogger(string categoryName)
        => new LeveledFileLogger(categoryName, this);

    /// <summary>
    /// 入队一条日志(写入方调用,不阻塞)。
    /// </summary>
    /// <param name="entry">日志条目。</param>
    internal void Enqueue(LogEntry entry)
    {
        if (!_stopped)
        {
            _queue.Writer.TryWrite(entry);
        }
    }

    /// <summary>
    /// 消费者主循环:批量出队 → 按日期/等级路由 → 写入文件 → 定时刷盘。
    /// </summary>
    private void ConsumeLoop()
    {
        try
        {
            // 批量缓冲区:攒批后统一写入(减少锁竞争与 IO 次数)。
            var batch = new List<LogEntry>(64);
            var reader = _queue.Reader;

            while (true)
            {
                batch.Clear();

                // 条件等待:队列空时挂起线程,写入或关闭后恢复。
                bool hasData = reader.WaitToReadAsync().AsTask().GetAwaiter().GetResult();
                if (!hasData && reader.Completion.IsCompleted)
                {
                    // 队列已关闭:写空剩余项后退出。
                    while (reader.TryRead(out LogEntry? entry))
                    {
                        batch.Add(entry);
                    }
                    FlushBatch(batch);
                    break;
                }

                // 尽量取空当前队列(批量处理,提升吞吐)。
                while (batch.Count < 256 && reader.TryRead(out LogEntry? item))
                {
                    batch.Add(item);
                }
                if (batch.Count > 0)
                {
                    FlushBatch(batch);
                }
                else
                {
                    // 队列短暂为空:让出 CPU。
                    Thread.Sleep(1);
                }
            }
        }
        catch (Exception ex)
        {
            // 消费者异常兜底:尝试把异常写入控制台(文件日志已不可用)。
            Console.Error.WriteLine($"[LeveledFileLog] 消费者线程异常: {ex}");
        }
        finally
        {
            // 退出前刷盘全部写入器。
            foreach (LogFileWriter writer in _writers.Values)
            {
                writer.Flush();
                writer.Dispose();
            }
            _writers.Clear();
        }
    }

    /// <summary>
    /// 批量落盘一批日志条目。
    /// </summary>
    /// <param name="batch">日志条目列表。</param>
    private void FlushBatch(List<LogEntry> batch)
    {
        // 日期切换检查:新的一天 → 清空写入器缓存(旧文件写入器关闭,新目录生效)。
        string dateKey = DateTime.Now.ToString("yyyy-MM-dd");
        if (!string.Equals(dateKey, _currentDateKey, StringComparison.Ordinal))
        {
            foreach (LogFileWriter writer in _writers.Values)
            {
                writer.Flush();
                writer.Dispose();
            }
            _writers.Clear();
            _currentDateKey = dateKey;
            // 预创建当日全部等级文件(贴合"按日期文件夹、按等级分文件"的目录结构约定)。
            EnsureBaseFiles(dateKey);
        }

        foreach (LogEntry entry in batch)
        {
            // 路由:Logs/{yyyy-MM-dd}/app-{level}.log。
            string filePath = Path.Combine(_options.RootPath, dateKey, FileLogOptions.FileNameForLevel(entry.Level));
            // 获取(或创建)对应写入器:ConcurrentDictionary 保证线程安全。
            LogFileWriter writer = _writers.GetOrAdd(filePath, path => new LogFileWriter(path, _options));
            writer.WriteLine(entry.FormatLine());
        }

        // 定时刷盘:未达条数阈值时由此处保证最终落盘(周期 200ms)。
        foreach (LogFileWriter writer in _writers.Values)
        {
            writer.Flush();
        }
    }

    /// <summary>
    /// 预创建当日 4 个等级文件(app-info/app-error/app-debug/app-warn),
    /// 并写入一行文件头注释,保证目录结构完整、直观。
    /// </summary>
    /// <param name="dateKey">日期键(yyyy-MM-dd)。</param>
    private void EnsureBaseFiles(string dateKey)
    {
        if (!_options.Enabled)
        {
            return;
        }
        string[] levelFiles =
        {
            "app-info.log", "app-error.log", "app-debug.log", "app-warn.log"
        };
        foreach (string fileName in levelFiles)
        {
            string filePath = Path.Combine(_options.RootPath, dateKey, fileName);
            // GetOrAdd 同时完成创建与注册(幂等,多次调用安全)。
            _writers.GetOrAdd(filePath, path =>
            {
                var writer = new LogFileWriter(path, _options);
                writer.WriteLine($"# 分级日志文件:{fileName}(JewelryWorkflow 自研分级日期文件日志)");
                return writer;
            });
        }
    }

    /// <summary>
    /// 释放资源:关闭队列并等待消费者线程退出。
    /// </summary>
    public void Dispose()
    {
        _stopped = true;
        _queue.Writer.TryComplete();
        // 等待消费者线程完成收尾(上限 2 秒,避免长时间阻塞进程退出)。
        if (_consumerThread.IsAlive && !_consumerThread.Join(TimeSpan.FromSeconds(2)))
        {
            Console.Error.WriteLine("[LeveledFileLog] 消费者线程未能在 2 秒内退出。");
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogEntry.cs

 */

using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Infrastructure.Logging;

/// <summary>
/// 日志条目(进入日志队列的最小单元)。
/// <para>由 <see cref="LeveledFileLogger"/> 创建,经无界 Channel 交给
/// <see cref="LeveledFileLoggerProvider"/> 的消费者线程批量落盘。</para>
/// </summary>
internal sealed class LogEntry
{
    /// <summary>
    /// 日志时间(本地时间)。
    /// </summary>
    public DateTime Time { get; init; }

    /// <summary>
    /// 日志等级。
    /// </summary>
    public LogLevel Level { get; init; }

    /// <summary>
    /// 日志分类(通常是 ILogger<T> 的泛型类型全名)。
    /// </summary>
    public string Category { get; init; } = string.Empty;

    /// <summary>
    /// 格式化后的日志消息正文(含结构化参数展开)。
    /// </summary>
    public string Message { get; init; } = string.Empty;

    /// <summary>
    /// 异常对象(可为 null)。
    /// </summary>
    public Exception? Exception { get; init; }

    /// <summary>
    /// 事件编号(可为 null)。
    /// </summary>
    public EventId? EventId { get; init; }

    /// <summary>
    /// 等级缩写(与控制台输出保持一致)。
    /// </summary>
    /// <param name="level">日志等级。</param>
    /// <returns>缩写字符串。</returns>
    public static string LevelShortName(LogLevel level) => level switch
    {
        LogLevel.Trace => "TRC",
        LogLevel.Debug => "DBG",
        LogLevel.Information => "INF",
        LogLevel.Warning => "WRN",
        LogLevel.Error => "ERR",
        LogLevel.Critical => "CRT",
        _ => "???"
    };

    /// <summary>
    /// 输出与 Microsoft.Extensions.Logging.Console 一致格式的日志行。
    /// </summary>
    /// <returns>完整日志行(不含换行)。</returns>
    public string FormatLine()
    {
        // 时间戳 + 等级缩写 + 分类 + 消息 + 异常。
        string line = $"{Time:yyyy-MM-dd HH:mm:ss.fff} [{LevelShortName(Level)}] [{Category}] {Message}";
        if (Exception is not null)
        {
            line += $"{Environment.NewLine}    异常: {Exception}";
        }
        return line;
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogFileWriter.cs

 */

using System.Text;

namespace JewelryWorkflow.Infrastructure.Logging;

/// <summary>
/// 单个日志文件写入器。
/// <para>线程安全设计:内部持有独立的 <see cref="StreamWriter"/> 与写锁,
/// 只允许消费者线程通过 <see cref="WriteLine"/> 写入,配合批量刷盘策略
/// (达到条数阈值或时间间隔时调用 <see cref="Flush"/>)减少磁盘 IO。</para>
/// </summary>
internal sealed class LogFileWriter : IDisposable
{
    // 写锁:保证同一文件的串行写入(消费者线程单线程写入,此处为双重保险)。
    private readonly object _writeLock = new();

    // 底层文本写入器(UTF-8 无 BOM,追加模式,关闭自动刷盘)。
    private StreamWriter? _writer;

    // 累计未刷盘的行数(达到阈值触发 Flush)。
    private int _pendingCount;

    /// <summary>
    /// 文件绝对路径(含日期目录与等级文件名,如 Logs\2026-09-14\app-info.log)。
    /// </summary>
    public string FilePath { get; }

    /// <summary>
    /// 配置(根目录、刷盘阈值、最大文件字节数)。
    /// </summary>
    public FileLogOptions Options { get; }

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="filePath">文件绝对路径。</param>
    /// <param name="options">配置。</param>
    public LogFileWriter(string filePath, FileLogOptions options)
    {
        FilePath = filePath;
        Options = options;
    }

    /// <summary>
    /// 写入一行日志(消费者线程调用;内部维护 StreamWriter 并累积刷盘计数)。
    /// </summary>
    /// <param name="line">日志行(含换行符)。</param>
    public void WriteLine(string line)
    {
        // 惰性创建写入器:确保日期目录存在,避免"目录不存在"异常。
        if (_writer is null)
        {
            string? directory = Path.GetDirectoryName(FilePath);
            if (!string.IsNullOrEmpty(directory))
            {
                Directory.CreateDirectory(directory);
            }
            _writer = new StreamWriter(
                new FileStream(FilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite),
                new UTF8Encoding(encoderShouldEmitUTF8Identifier: false))
            {
                AutoFlush = false
            };
        }

        lock (_writeLock)
        {
            _writer.WriteLine(line);
            _pendingCount++;
            // 达到条数阈值:立即刷盘(批量写入)。
            if (_pendingCount >= Options.FlushThreshold)
            {
                _writer.Flush();
                _pendingCount = 0;
            }
            // 文件超限:归档轮转(app-info.log → app-info.log.1,保留旧文件)。
            if (_writer.BaseStream.Length > Options.MaxFileBytes)
            {
                Rotate();
            }
        }
    }

    /// <summary>
    /// 强制刷盘(定时器调用,把残余缓冲写入磁盘)。
    /// </summary>
    public void Flush()
    {
        lock (_writeLock)
        {
            if (_writer is not null && _pendingCount > 0)
            {
                _writer.Flush();
                _pendingCount = 0;
            }
        }
    }

    /// <summary>
    /// 文件超限归档:把当前文件改名为 .1,新建空文件继续写入。
    /// </summary>
    private void Rotate()
    {
        try
        {
            _writer?.Dispose();
            _writer = null;
            string archive = $"{FilePath}.1";
            File.Move(FilePath, archive, overwrite: true);
        }
        catch (IOException)
        {
            // 归档失败(如文件被占用):忽略,继续写入当前文件。
        }
    }

    /// <summary>
    /// 释放资源(关闭写入器并刷盘)。
    /// </summary>
    public void Dispose()
    {
        lock (_writeLock)
        {
            _writer?.Flush();
            _writer?.Dispose();
            _writer = null;
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LoggingExtensions.cs

 */

using Karambolo.Extensions.Logging.File;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Infrastructure.Logging;

/// <summary>
/// 日志扩展方法:向 <see cref="ILoggingBuilder"/> 注册分级日期文件日志与 Karambolo 综合日志。
/// </summary>
public static class LoggingExtensions
{
    /// <summary>
    /// 注册分级日期文件日志(自研:Logs/yyyy-MM-dd/app-{info,error,debug,warn}.log)。
    /// <para>说明:因 Karambolo 按"单文件模板"切分,无法直接实现"日期文件夹 × 等级文件"
    /// 的嵌套结构,故自研 <see cref="LeveledFileLoggerProvider"/> 精确满足该目录需求;
    /// Karambolo 作为点名库另行注册为综合日志通道(见 <see cref="AddKaramboloCombinedFile"/>)。</para>
    /// </summary>
    /// <param name="builder">日志构建器。</param>
    /// <param name="configure">配置委托(可选,覆盖默认值)。</param>
    /// <returns>日志构建器(链式调用)。</returns>
    public static ILoggingBuilder AddLeveledFile(this ILoggingBuilder builder, Action<FileLogOptions>? configure = null)
    {
        // 配置绑定(支持 appsettings.json 的 "Logging:LeveledFile" 节)。
        if (configure is not null)
        {
            builder.Services.Configure(configure);
        }

        // Provider 注册为单例(一个消费者线程 + 一个队列,全局共享)。
        builder.Services.TryAddSingleton<LeveledFileLoggerProvider>();
        builder.Services.AddSingleton<ILoggerProvider>(sp => sp.GetRequiredService<LeveledFileLoggerProvider>());
        return builder;
    }

    /// <summary>
    /// 注册 Karambolo 综合文件日志(Logs/app-combined-2026-09-14.log,按日切分)。
    /// <para>作为分级日志的补充通道,记录全量日志(便于按时间整体检索)。
    /// Karambolo 3.4.0 的文件路径模板使用尖括号占位符:
    /// - <date:yyyy-MM-dd>:当前日期(按日切分文件名);
    /// - <counter:000>:滚动计数器(文件超限轮转时递增,可省略)。</para>
    /// </summary>
    /// <param name="builder">日志构建器。</param>
    /// <returns>日志构建器(链式调用)。</returns>
    public static ILoggingBuilder AddKaramboloCombinedFile(this ILoggingBuilder builder)
    {
        // Karambolo 官方扩展:RootPath 指定根目录,Files 指定文件模板(<date:yyyy-MM-dd> 自动按日切分)。
        builder.AddFile(options =>
        {
            string root = Path.Combine(Environment.CurrentDirectory, "Logs");
            // Karambolo 的 RootPath 内部使用 PhysicalFileProvider,要求目录已存在,故先创建。
            Directory.CreateDirectory(root);
            options.RootPath = root;
            options.Files = new[]
            {
                new LogFileOptions
                {
                    // <date:yyyy-MM-dd> = 2026-09-14;带 counter 使 MaxFileSize 大小滚动生效。
                    Path = "app-combined-<date:yyyy-MM-dd>-<counter>.log",
                    CounterFormat = "000",
                    MaxFileSize = 5L * 1024 * 1024  // 单文件 5MB 滚动(需 counter 占位符配合)。
                }
            };
        });
        return builder;
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : InMemoryRepository.cs

 */

using System.Collections.Concurrent;
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;

namespace JewelryWorkflow.Infrastructure.Repositories;

/// <summary>
/// 线程安全的内存仓储(泛型实现 IRepository<TKey, TEntity>)。
/// <para>基于 <see cref="ConcurrentDictionary{TKey, TValue}"/>:
/// - 高并发读写下线程安全(GetOrAdd / TryGetValue / TryRemove);
/// - 通过 key 提取委托实现泛型 Upsert;
/// - 适用于演示与单机轻量场景;生产环境可无缝替换为 EF Core/Dapper 实现(依赖倒置)。</para>
/// </summary>
/// <typeparam name="TKey">主键类型。</typeparam>
/// <typeparam name="TEntity">实体类型。</typeparam>
public sealed class InMemoryRepository<TKey, TEntity> : IRepository<TKey, TEntity>
    where TKey : notnull
    where TEntity : class
{
    /// <summary>
    /// 底层存储(ConcurrentDictionary:原子读改写)。
    /// </summary>
    private readonly ConcurrentDictionary<TKey, TEntity> _store = new();

    /// <summary>
    /// 主键提取委托(由构造方提供,用于 Save 时定位主键)。
    /// </summary>
    private readonly Func<TEntity, TKey> _keySelector;

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="keySelector">主键提取委托。</param>
    public InMemoryRepository(Func<TEntity, TKey> keySelector)
    {
        _keySelector = keySelector;
    }

    /// <summary>
    /// 按主键查询。
    /// </summary>
    /// <param name="key">主键。</param>
    /// <returns>实体或 null。</returns>
    public Task<TEntity?> GetByIdAsync(TKey key)
    {
        _store.TryGetValue(key, out TEntity? entity);
        return Task.FromResult(entity);
    }

    /// <summary>
    /// 保存(Upsert:存在则覆盖,不存在则新增)。
    /// </summary>
    /// <param name="entity">实体。</param>
    /// <returns>保存结果。</returns>
    public Task<Result> SaveAsync(TEntity entity)
    {
        if (entity is null)
        {
            return Task.FromResult(Result.Fail("实体不能为 null。", "ENTITY_NULL"));
        }
        TKey key = _keySelector(entity);
        _store[key] = entity; // ConcurrentDictionary 索引器:原子 Upsert。
        return Task.FromResult(Result.Ok());
    }

    /// <summary>
    /// 按主键删除。
    /// </summary>
    /// <param name="key">主键。</param>
    /// <returns>是否删除成功。</returns>
    public Task<bool> DeleteAsync(TKey key)
        => Task.FromResult(_store.TryRemove(key, out _));

    /// <summary>
    /// 查询全部实体(返回快照集合,外部修改不影响内部存储)。
    /// </summary>
    /// <returns>实体集合。</returns>
    public Task<IReadOnlyList<TEntity>> GetAllAsync()
        => Task.FromResult<IReadOnlyList<TEntity>>(_store.Values.ToArray());
}

  

/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : CircuitBreaker.cs

 */
using JewelryWorkflow.Domain.Common;

namespace JewelryWorkflow.Application.Adapters;

/// <summary>
/// 熔断器(Circuit Breaker)。
/// <para>状态机:关闭(Closed) → 打开(Open) → 半开(HalfOpen) → 关闭/打开。
/// - 关闭:正常放行请求,连续失败达阈值后进入打开;
/// - 打开:快速失败(不发起真实调用),熔断时间过后进入半开;
/// - 半开:允许少量探测请求,成功则关闭,失败则重新打开。
/// 目的:外部服务不可用时快速失败并保护下游,避免级联雪崩。</para>
/// </summary>
public sealed class CircuitBreaker
{
    // 状态机锁:所有状态切换必须持有该锁,保证多线程安全。
    private readonly object _lock = new();

    // 熔断器状态枚举(私有,避免暴露内部细节)。
    private enum BreakerState { Closed, Open, HalfOpen }

    /// <summary>
    /// 熔断器名称(用于日志)。
    /// </summary>
    public string Name { get; }

    /// <summary>
    /// 连续失败多少次后打开熔断器。
    /// </summary>
    public int FailureThreshold { get; }

    /// <summary>
    /// 熔断打开持续时长(毫秒),过后进入半开探测。
    /// </summary>
    public int OpenDurationMilliseconds { get; }

    /// <summary>
    /// 半开状态下,连续成功多少次后恢复关闭。
    /// </summary>
    public int HalfOpenSuccessThreshold { get; }

    // 当前状态。
    private BreakerState _state = BreakerState.Closed;

    // 连续失败计数。
    private int _consecutiveFailures;

    // 连续成功计数(半开探测用)。
    private int _consecutiveSuccesses;

    // 打开状态的开始时间戳(用于判定是否可进入半开)。
    private long _openSinceTicks;

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="name">熔断器名称。</param>
    /// <param name="failureThreshold">失败阈值(默认 3)。</param>
    /// <param name="openDurationMilliseconds">熔断时长毫秒(默认 10000)。</param>
    /// <param name="halfOpenSuccessThreshold">半开恢复阈值(默认 1)。</param>
    public CircuitBreaker(string name, int failureThreshold = 3, int openDurationMilliseconds = 10_000, int halfOpenSuccessThreshold = 1)
    {
        Name = name;
        FailureThreshold = Math.Max(1, failureThreshold);
        OpenDurationMilliseconds = Math.Max(100, openDurationMilliseconds);
        HalfOpenSuccessThreshold = Math.Max(1, halfOpenSuccessThreshold);
    }

    /// <summary>
    /// 当前是否允许发起真实调用(熔断打开时不允许)。
    /// </summary>
    public bool IsOpen
    {
        get
        {
            lock (_lock)
            {
                // 打开状态下,若已超过熔断时长则自动转半开(允许探测)。
                if (_state == BreakerState.Open)
                {
                    long elapsed = DateTime.UtcNow.Ticks - _openSinceTicks;
                    if (elapsed >= OpenDurationMilliseconds * TimeSpan.TicksPerMillisecond)
                    {
                        _state = BreakerState.HalfOpen;
                        _consecutiveSuccesses = 0;
                    }
                }
                return _state == BreakerState.Open;
            }
        }
    }

    /// <summary>
    /// 带熔断保护的异步调用:熔断打开时快速失败,不执行真实操作。
    /// </summary>
    /// <typeparam name="T">返回值类型。</typeparam>
    /// <param name="operation">真实操作。</param>
    /// <returns>调用结果(熔断打开时返回失败结果,不抛异常)。</returns>
    public async Task<Result<T>> ExecuteAsync<T>(Func<Task<Result<T>>> operation)
    {
        // 1) 熔断检查:打开则快速失败。
        if (IsOpen)
        {
            return Result<T>.Fail($"熔断器【{Name}】处于打开状态,请求被快速拒绝。", "CIRCUIT_OPEN");
        }

        // 2) 执行真实操作并记录结果。
        Result<T> result;
        try
        {
            result = await operation().ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            // 异常视为失败,并计入熔断统计。
            RecordFailure();
            return Result<T>.Fail($"外部服务【{Name}】调用异常:{ex.Message}", "ADAPTER_EXCEPTION");
        }

        // 3) 按业务结果记录成功/失败。
        if (result.IsSuccess)
        {
            RecordSuccess();
        }
        else
        {
            RecordFailure();
        }
        return result;
    }

    /// <summary>
    /// 记录一次成功:关闭态清空失败计数;半开态累计成功,达到阈值恢复关闭。
    /// </summary>
    private void RecordSuccess()
    {
        lock (_lock)
        {
            if (_state == BreakerState.HalfOpen)
            {
                _consecutiveSuccesses++;
                if (_consecutiveSuccesses >= HalfOpenSuccessThreshold)
                {
                    // 半开探测成功:恢复关闭,清空全部计数。
                    _state = BreakerState.Closed;
                    _consecutiveFailures = 0;
                    _consecutiveSuccesses = 0;
                }
            }
            else if (_state == BreakerState.Closed)
            {
                // 关闭态成功:重置失败计数。
                _consecutiveFailures = 0;
            }
        }
    }

    /// <summary>
    /// 记录一次失败:关闭态累计失败,达阈值打开;半开态失败立即重新打开。
    /// </summary>
    private void RecordFailure()
    {
        lock (_lock)
        {
            switch (_state)
            {
                case BreakerState.Closed:
                    _consecutiveFailures++;
                    if (_consecutiveFailures >= FailureThreshold)
                    {
                        // 连续失败达阈值:打开熔断器。
                        _state = BreakerState.Open;
                        _openSinceTicks = DateTime.UtcNow.Ticks;
                    }
                    break;
                case BreakerState.HalfOpen:
                    // 半开探测失败:立即重新打开并重置计时。
                    _state = BreakerState.Open;
                    _openSinceTicks = DateTime.UtcNow.Ticks;
                    break;
                case BreakerState.Open:
                    // 已打开:无需处理(IsOpen 会周期性转入半开)。
                    break;
            }
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : GemLabAdapter.cs

 */
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Adapters;

/// <summary>
/// 宝石/贵金属检测机构适配器(对接第三方检测实验室)。
/// <para>用于质检环节获取权威检测数据(实测成色、重量),
/// 同样具备重试 + 熔断弹性,模拟检测平台偶发抖动场景。</para>
/// </summary>
public sealed class GemLabAdapter : ResilientAdapterBase<
    GemLabAdapter.LabRequest, GemLabAdapter.LabResponse>
{
    /// <summary>
    /// 请求 DTO:送检入参。
    /// </summary>
    public sealed class LabRequest
    {
        /// <summary>送检样品编号(工单号)。</summary>
        public string SampleNo { get; set; } = string.Empty;

        /// <summary>原料/成品类型。</summary>
        public string MaterialType { get; set; } = string.Empty;

        /// <summary>申报成色。</summary>
        public string DeclaredPurity { get; set; } = string.Empty;
    }

    /// <summary>
    /// 响应 DTO:检测结果。
    /// </summary>
    public sealed class LabResponse
    {
        /// <summary>实测成色。</summary>
        public string MeasuredPurity { get; set; } = string.Empty;

        /// <summary>实测重量(克)。</summary>
        public decimal MeasuredWeightGram { get; set; }

        /// <summary>检测报告编号。</summary>
        public string ReportNo { get; set; } = string.Empty;
    }

    /// <summary>
    /// 故障注入模式(用于演示,生产环境可移除)。
    /// </summary>
    public enum FailureMode
    {
        /// <summary>正常:始终成功。</summary>
        None,

        /// <summary>瞬时故障:前 1 次失败,之后恢复(演示重试成功)。</summary>
        Transient
    }

    /// <summary>
    /// 当前故障模式。
    /// </summary>
    public FailureMode Mode { get; set; } = FailureMode.None;

    // 调用次数计数。
    private int _callCount;

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="logger">标准日志器(DI 注入)。</param>
    public GemLabAdapter(ILogger<GemLabAdapter> logger)
        : base(logger, retryPolicy: new RetryPolicy(maxRetry: 2, baseDelayMilliseconds: 80), breaker: new CircuitBreaker("检测机构", failureThreshold: 3, openDurationMilliseconds: 8000))
    {
    }

    /// <summary>
    /// 适配器名称。
    /// </summary>
    public override string AdapterName => "宝石检测机构";

    /// <summary>
    /// 真实调用检测机构服务(模拟网络延迟与故障注入)。
    /// </summary>
    /// <param name="request">送检请求。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>检测响应。</returns>
    protected override async Task<LabResponse> InvokeCoreAsync(LabRequest request, CancellationToken cancellationToken)
    {
        // 模拟检测平台网络耗时(40 毫秒)。
        await Task.Delay(40, cancellationToken);

        // 原子自增调用次数。
        int call = Interlocked.Increment(ref _callCount);

        // 瞬时故障:第一次抛异常,第二次起恢复。
        if (Mode == FailureMode.Transient && call == 1)
        {
            throw new IOException("检测平台网络抖动(模拟瞬时故障)。");
        }

        // 返回权威检测数据。
        return new LabResponse
        {
            MeasuredPurity = request.DeclaredPurity,
            MeasuredWeightGram = 18.5m, // 模拟实测重量(克)
            ReportNo = $"LAB-{request.SampleNo}-{DateTime.Now:yyyyMMdd}"
        };
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ResilientAdapterBase.cs

 */
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Adapters;

/// <summary>
/// 弹性适配器基类(组合重试 + 熔断)。
/// <para>子类只需实现 <see cref="InvokeCoreAsync"/>(真实的外部调用),
/// 基类统一提供:熔断前置检查 → 指数退避重试 → 异常/失败结果标准化转换,
/// 并统一输出结构化日志。符合"适配器职责单一、完全可扩展"的企业级要求。</para>
/// </summary>
/// <typeparam name="TRequest">请求类型。</typeparam>
/// <typeparam name="TResponse">响应类型。</typeparam>
public abstract class ResilientAdapterBase<TRequest, TResponse> : IResilientAdapter<TRequest, TResponse>
{
    /// <summary>
    /// 熔断器(进程内单例,保护同一外部服务)。
    /// </summary>
    protected CircuitBreaker Breaker { get; }

    /// <summary>
    /// 重试策略。
    /// </summary>
    protected RetryPolicy Retry { get; }

    /// <summary>
    /// 标准日志器(由 DI 注入,控制台与文件统一输出)。
    /// </summary>
    protected ILogger Logger { get; }

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    /// <param name="retryPolicy">重试策略(可自定义)。</param>
    /// <param name="breaker">熔断器(可自定义)。</param>
    protected ResilientAdapterBase(ILogger logger, RetryPolicy? retryPolicy = null, CircuitBreaker? breaker = null)
    {
        Logger = logger;
        Retry = retryPolicy ?? new RetryPolicy();
        Breaker = breaker ?? new CircuitBreaker(AdapterName);
    }

    /// <summary>
    /// 适配器名称(默认取类名,子类可重写为业务名称)。
    /// </summary>
    public virtual string AdapterName => GetType().Name;

    /// <summary>
    /// 弹性调用入口:熔断检查 → 重试执行 → 结果标准化。
    /// </summary>
    /// <param name="request">请求对象。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>调用结果(永不抛异常,失败包装为 Result)。</returns>
    public async Task<Result<TResponse>> CallAsync(TRequest request, CancellationToken cancellationToken)
    {
        // 记录一次外部调用开始(结构化日志)。
        Logger.LogInformation("[适配器: {Adapter}] 开始调用外部服务,请求类型={RequestType}",
            AdapterName, typeof(TRequest).Name);

        // 熔断保护执行。
        return await Breaker.ExecuteAsync(async () =>
        {
            try
            {
                // 重试执行真实调用。
                TResponse response = await Retry.ExecuteAsync(
                    () => InvokeCoreAsync(request, cancellationToken),
                    onRetry: (attempt, ex, delayMs) =>
                        Logger.LogWarning("[适配器: {Adapter}] 调用失败,第 {Attempt} 次重试,等待 {Delay}ms,原因:{Reason}",
                            AdapterName, attempt, delayMs, ex.Message),
                    cancellationToken: cancellationToken);

                // 成功路径。
                Logger.LogInformation("[适配器: {Adapter}] 调用成功,响应类型={ResponseType}", AdapterName, typeof(TResponse).Name);
                return Result<TResponse>.Ok(response);
            }
            catch (OperationCanceledException)
            {
                // 取消:包装为失败结果。
                return Result<TResponse>.Fail("调用被取消。", "CANCELLED");
            }
            catch (Exception ex)
            {
                // 重试耗尽后仍失败:记录错误并返回失败结果(熔断器已在 Breaker 层计数)。
                Logger.LogError(ex, "[适配器: {Adapter}] 调用最终失败(重试耗尽)。", AdapterName);
                return Result<TResponse>.Fail($"外部服务调用失败:{ex.Message}", "ADAPTER_FAILED");
            }
        });
    }

    /// <summary>
    /// 子类实现真实的外部服务调用。
    /// </summary>
    /// <param name="request">请求对象。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>响应对象。</returns>
    protected abstract Task<TResponse> InvokeCoreAsync(TRequest request, CancellationToken cancellationToken);
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : RetryPolicy.cs

 */
using JewelryWorkflow.Domain.Common;

namespace JewelryWorkflow.Application.Adapters;

/// <summary>
/// 重试策略(Retry Policy)。
/// <para>实现指数退避重试:外部服务抖动(瞬时失败)时自动重试,
/// 退避时间按 2^n 指数增长并封顶,避免重试风暴。</para>
/// </summary>
public sealed class RetryPolicy
{
    /// <summary>
    /// 最大重试次数(不含首次尝试)。
    /// </summary>
    public int MaxRetry { get; }

    /// <summary>
    /// 基础退避延迟(毫秒),第 n 次重试延迟 = baseDelay * 2^(n-1)。
    /// </summary>
    public int BaseDelayMilliseconds { get; }

    /// <summary>
    /// 退避延迟上限(毫秒),防止单次等待过长。
    /// </summary>
    public int MaxDelayMilliseconds { get; }

    /// <summary>
    /// 随机抖动比例(0-0.5),避免多线程同时重试造成同步重试风暴。
    /// </summary>
    public double JitterRatio { get; }

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="maxRetry">最大重试次数(默认 3)。</param>
    /// <param name="baseDelayMilliseconds">基础退避毫秒数(默认 200)。</param>
    /// <param name="maxDelayMilliseconds">退避上限毫秒数(默认 3000)。</param>
    /// <param name="jitterRatio">抖动比例(默认 0.3)。</param>
    public RetryPolicy(int maxRetry = 3, int baseDelayMilliseconds = 200, int maxDelayMilliseconds = 3000, double jitterRatio = 0.3)
    {
        MaxRetry = Math.Max(0, maxRetry);
        BaseDelayMilliseconds = Math.Max(10, baseDelayMilliseconds);
        MaxDelayMilliseconds = Math.Max(BaseDelayMilliseconds, maxDelayMilliseconds);
        JitterRatio = Math.Clamp(jitterRatio, 0, 0.5);
    }

    /// <summary>
    /// 带重试地执行异步操作。
    /// </summary>
    /// <typeparam name="T">返回值类型。</typeparam>
    /// <param name="operation">待执行操作(可能抛出异常)。</param>
    /// <param name="onRetry">每次重试前的回调(参数:第几次重试、异常、预计等待毫秒数)。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>操作结果。</returns>
    /// <exception cref="OperationCanceledException">取消时抛出。</exception>
    public async Task<T> ExecuteAsync<T>(
        Func<Task<T>> operation,
        Action<int, Exception, int>? onRetry = null,
        CancellationToken cancellationToken = default)
    {
        // 首次尝试不计入重试次数。
        for (int attempt = 0; ; attempt++)
        {
            try
            {
                // 执行真实操作。
                return await operation().ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                // 用户取消:直接向上抛出,不做重试。
                throw;
            }
            catch (Exception ex) when (attempt < MaxRetry)
            {
                // 计算第 attempt+1 次重试的退避时间:baseDelay * 2^attempt,封顶 maxDelay,叠加抖动。
                int backoff = Math.Min(
                    MaxDelayMilliseconds,
                    BaseDelayMilliseconds * (1 << attempt));
                double jitter = 1.0 + (Random.Shared.NextDouble() * 2 - 1) * JitterRatio;
                int delayMs = (int)Math.Round(backoff * jitter);
                onRetry?.Invoke(attempt + 1, ex, delayMs);
                await Task.Delay(delayMs, cancellationToken).ConfigureAwait(false);
            }
            catch (Exception)
            {
                // 已达最大重试次数:不再重试,直接抛出。
                throw;
            }
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : SupplierInspectionAdapter.cs

 */

using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Adapters;

/// <summary>
/// 供应商资质核验适配器(对接第三方供应商征信/质检机构服务)。
/// <para>演示外部服务适配器的"重试 + 熔断"弹性:
/// 支持故障注入模式(None=正常 / Transient=瞬时故障几次后恢复 / Broken=持续不可用),
/// 配合 <see cref="RetryPolicy"/> 与 <see cref="CircuitBreaker"/> 展示重试成功与熔断快速失败。</para>
/// </summary>
public sealed class SupplierInspectionAdapter : ResilientAdapterBase<
    SupplierInspectionAdapter.InspectionRequest, SupplierInspectionAdapter.InspectionResponse>
{
    /// <summary>
    /// 请求 DTO:供应商核验入参。
    /// </summary>
    public sealed class InspectionRequest
    {
        /// <summary>供应商名称。</summary>
        public string SupplierName { get; set; } = string.Empty;

        /// <summary>原料质检证书编号。</summary>
        public string CertificateNo { get; set; } = string.Empty;

        /// <summary>原料类型。</summary>
        public string MaterialType { get; set; } = string.Empty;

        /// <summary>原料重量(克)。</summary>
        public decimal WeightGram { get; set; }
    }

    /// <summary>
    /// 响应 DTO:供应商核验结果。
    /// </summary>
    public sealed class InspectionResponse
    {
        /// <summary>是否核验通过。</summary>
        public bool Passed { get; set; }

        /// <summary>核验备注。</summary>
        public string Remark { get; set; } = string.Empty;
    }

    /// <summary>
    /// 故障注入模式(用于演示,生产环境可移除)。
    /// </summary>
    public enum FailureMode
    {
        /// <summary>正常:始终成功。</summary>
        None,

        /// <summary>瞬时故障:前 2 次失败,之后恢复(演示重试成功)。</summary>
        Transient,

        /// <summary>持续故障:始终失败(演示熔断打开)。</summary>
        Broken
    }

    /// <summary>
    /// 当前故障模式(演示中可在运行时切换)。
    /// </summary>
    public FailureMode Mode { get; set; } = FailureMode.None;

    // 调用次数计数(跨线程安全,用于 Transient 模式判定)。
    private int _callCount;

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="logger">标准日志器(DI 注入)。</param>
    public SupplierInspectionAdapter(ILogger<SupplierInspectionAdapter> logger)
        : base(logger, retryPolicy: new RetryPolicy(maxRetry: 3, baseDelayMilliseconds: 100), breaker: new CircuitBreaker("供应商核验", failureThreshold: 2, openDurationMilliseconds: 8000))
    {
    }

    /// <summary>
    /// 适配器名称。
    /// </summary>
    public override string AdapterName => "供应商资质核验";

    /// <summary>
    /// 真实调用供应商核验服务(模拟网络延迟与故障注入)。
    /// </summary>
    /// <param name="request">核验请求。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>核验响应。</returns>
    protected override async Task<InspectionResponse> InvokeCoreAsync(InspectionRequest request, CancellationToken cancellationToken)
    {
        // 模拟外部服务网络耗时(30 毫秒)。
        await Task.Delay(30, cancellationToken);

        // 原子自增调用次数(多线程安全)。
        int call = Interlocked.Increment(ref _callCount);

        // 按故障模式注入失败。
        switch (Mode)
        {
            case FailureMode.Transient when call <= 2:
                // 前两次抛"超时"模拟瞬时抖动,第三次起恢复正常。
                throw new TimeoutException("供应商服务响应超时(模拟瞬时故障)。");
            case FailureMode.Broken:
                // 持续抛异常,触发熔断器累计失败并打开。
                throw new HttpRequestException("供应商服务不可用(模拟持续故障)。");
            default:
                // 核验通过:返回证书核验结果。
                return new InspectionResponse
                {
                    Passed = true,
                    Remark = $"证书【{request.CertificateNo}】核验通过,供应商【{request.SupplierName}】资质有效。"
                };
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : BusinessService.cs

 */
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 业务服务(支持环节:客户跟单与商务确认)。
/// <para>职责:校验业务输入 → 生成业务跟单实体(客户等级、商务条款、意向度)→ 写回上下文。</para>
/// </summary>
public sealed class BusinessService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<BusinessService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public BusinessService(ILogger<BusinessService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "业务跟单";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Business;

    /// <summary>
    /// 执行业务跟单。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        BusinessRequestDto? dto = context.Business;
        if (dto is null)
        {
            return Result.Fail("缺少业务输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:客户={Customer} 等级={Level} 跟单员={Manager}",
            StepName, context.OrderId, context.Order.CustomerName, dto.CustomerLevel, dto.AccountManager);

        // 2) 模拟客户沟通与条款确认。
        await Task.Delay(Random.Shared.Next(50, 130), cancellationToken);

        // 3) 生成业务跟单实体。
        context.BusinessResult = new BusinessOrder
        {
            BusinessNo = $"BIZ-{context.OrderId}",
            CustomerLevel = dto.CustomerLevel,
            Terms = dto.Terms,
            AccountManager = dto.AccountManager,
            IntentionScore = dto.IntentionScore,
            IsConfirmed = true
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:商务条款已确认,意向度={Score}",
            StepName, context.OrderId, dto.IntentionScore);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : DesignService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 设计制图服务(第 2 环节)。
/// <para>职责:校验设计输入 → 生成设计图纸实体(含工艺要求、审核通过标记)→ 写回上下文。</para>
/// </summary>
public sealed class DesignService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<DesignService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public DesignService(ILogger<DesignService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "设计制图";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.DesignDrawing;

    /// <summary>
    /// 执行设计制图。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        DesignRequestDto? dto = context.Design;
        if (dto is null)
        {
            return Result.Fail("缺少设计制图输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:款式={Style} 设计师={Designer}",
            StepName, context.OrderId, dto.StyleName, dto.DesignerName);

        // 2) 生成设计图纸实体(首次版本 v1,模拟设计审核通过)。
        context.DesignResult = new DesignDrawing
        {
            DrawingNo = $"DRW-{context.OrderId}",
            StyleName = dto.StyleName,
            Version = 1,
            DesignerName = dto.DesignerName,
            CraftRequirement = dto.CraftRequirement,
            IsApproved = true,
            ApprovedBy = "设计总监",
            DesignedAt = DateTime.Now
        };

        // 3) 模拟设计工时(体现并发处理)。
        await Task.Delay(Random.Shared.Next(80, 200), cancellationToken);

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:图纸={DrawingNo} 已审核通过",
            StepName, context.OrderId, context.DesignResult.DrawingNo);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : FinanceService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 财务服务(支持环节:财务结算)。
/// <para>职责:校验财务输入 → 生成财务结算单实体(采购付款/销售收款/毛利/发票)→ 写回上下文。</para>
/// </summary>
public sealed class FinanceService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<FinanceService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public FinanceService(ILogger<FinanceService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "财务结算";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Finance;

    /// <summary>
    /// 执行财务结算。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        FinanceRequestDto? dto = context.Finance;
        if (dto is null)
        {
            return Result.Fail("缺少财务输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:采购付款={Purchase} 销售收款={Sales}",
            StepName, context.OrderId, dto.PurchasePayment, dto.SalesReceipt);

        // 2) 模拟财务核算。
        await Task.Delay(Random.Shared.Next(60, 140), cancellationToken);

        // 3) 生成结算单:毛利 = 销售收款 - 采购付款;需要开票则生成发票号。
        decimal grossProfit = dto.SalesReceipt - dto.PurchasePayment;
        context.FinanceResult = new FinanceInvoice
        {
            SettlementNo = $"FIN-{context.OrderId}",
            PurchasePayment = dto.PurchasePayment,
            SalesReceipt = dto.SalesReceipt,
            GrossProfit = grossProfit,
            InvoiceNo = dto.NeedInvoice ? $"INV-{context.OrderId}-{DateTime.Now:yyyyMMdd}" : string.Empty,
            IsSettled = true,
            SettledAt = DateTime.Now
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:毛利={GrossProfit}元 发票={InvoiceNo}",
            StepName, context.OrderId, grossProfit, context.FinanceResult.InvoiceNo);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : HrService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 人事行政服务(支持环节:行政协同)。
/// <para>职责:校验人事输入 → 生成人事行政记录实体(经办员工、部门、行政事务)→ 写回上下文。</para>
/// </summary>
public sealed class HrService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<HrService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public HrService(ILogger<HrService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "人事行政";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.HrAdmin;

    /// <summary>
    /// 执行人事行政协同。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        HrRequestDto? dto = context.HrAdmin;
        if (dto is null)
        {
            return Result.Fail("缺少人事行政输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:经办={Employee}({Dept}) 事务={Task}",
            StepName, context.OrderId, dto.EmployeeName, dto.Department, dto.AdminTask);

        // 2) 模拟行政事务处理。
        await Task.Delay(Random.Shared.Next(40, 110), cancellationToken);

        // 3) 生成人事行政记录实体。
        context.HrResult = new HrRecord
        {
            HrNo = $"HR-{context.OrderId}",
            EmployeeNo = dto.EmployeeNo,
            EmployeeName = dto.EmployeeName,
            Department = dto.Department,
            AdminTask = dto.AdminTask,
            IsCompleted = true
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:行政事务已办结",
            StepName, context.OrderId);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ItService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// IT 服务(支持环节:信息系统与权限协同)。
/// <para>职责:校验 IT 输入 → 生成 IT 记录实体(系统单据、设备资产、权限任务)→ 写回上下文。</para>
/// </summary>
public sealed class ItService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<ItService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public ItService(ILogger<ItService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "IT协同";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.InformationTechnology;

    /// <summary>
    /// 执行 IT 协同。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        ItRequestDto? dto = context.InformationTechnology;
        if (dto is null)
        {
            return Result.Fail("缺少 IT 输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:系统={System} 权限任务={Task}",
            StepName, context.OrderId, dto.SystemName, dto.PermissionTask);

        // 2) 模拟系统单据创建与权限开通。
        await Task.Delay(Random.Shared.Next(40, 110), cancellationToken);

        // 3) 生成 IT 记录实体。
        context.ItResult = new ItAsset
        {
            ItNo = $"IT-{context.OrderId}",
            SystemName = dto.SystemName,
            SystemDocNo = $"{dto.SystemName}-{context.OrderId}",
            AssetNo = dto.AssetNo,
            PermissionTask = dto.PermissionTask,
            IsCompleted = true
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:单据={DocNo} 权限已开通",
            StepName, context.OrderId, context.ItResult.SystemDocNo);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : LogisticsService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 物流服务(第 6 环节,生产主线收尾)。
/// <para>职责:校验物流输入 → 生成物流运单实体(承运商、收件信息、发货)→ 写回上下文。</para>
/// </summary>
public sealed class LogisticsService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<LogisticsService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public LogisticsService(ILogger<LogisticsService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "物流";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Logistics;

    /// <summary>
    /// 执行物流发货。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO 与上游包装单。
        LogisticsRequestDto? dto = context.Logistics;
        PackageInfo? pkg = context.PackagingResult;
        if (dto is null || pkg is null)
        {
            return Result.Fail("缺少物流输入或上游包装单。", "PRECONDITION_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:承运商={Carrier} 收件人={Receiver}",
            StepName, context.OrderId, dto.CarrierName, dto.ReceiverName);

        // 2) 模拟运单创建与发货。
        await Task.Delay(Random.Shared.Next(50, 130), cancellationToken);

        // 3) 生成物流运单并写回上下文。
        context.LogisticsResult = new LogisticsWaybill
        {
            WaybillNo = $"WB-{context.OrderId}",
            PackageNo = pkg.PackageNo,
            CarrierName = dto.CarrierName,
            ReceiverName = dto.ReceiverName,
            ReceiverAddress = dto.ReceiverAddress,
            IsShipped = true,
            ShippedAt = DateTime.Now,
            TrackingStatus = "运输中"
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:运单={WaybillNo} 已发货",
            StepName, context.OrderId, context.LogisticsResult.WaybillNo);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MarketingService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 营销推广服务(支持环节:市场推广)。
/// <para>职责:校验营销输入 → 生成营销活动实体(渠道、预算、曝光预估)→ 写回上下文。</para>
/// </summary>
public sealed class MarketingService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<MarketingService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public MarketingService(ILogger<MarketingService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "营销推广";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Marketing;

    /// <summary>
    /// 执行营销推广。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        MarketingRequestDto? dto = context.Marketing;
        if (dto is null)
        {
            return Result.Fail("缺少营销推广输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:活动={Campaign} 渠道={Channel} 预算={Budget}",
            StepName, context.OrderId, dto.CampaignName, dto.Channel, dto.Budget);

        // 2) 模拟活动配置与上线。
        await Task.Delay(Random.Shared.Next(50, 130), cancellationToken);

        // 3) 生成营销活动实体(曝光量按预算 × 100 预估)。
        context.MarketingResult = new MarketingCampaign
        {
            CampaignNo = $"MKT-{context.OrderId}",
            CampaignName = dto.CampaignName,
            Channel = dto.Channel,
            Budget = dto.Budget,
            EstimatedImpressions = (long)(dto.Budget * 100),
            IsLaunched = true,
            LaunchedAt = DateTime.Now
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:活动={CampaignNo} 已上线,预估曝光={Impressions}",
            StepName, context.OrderId, context.MarketingResult.CampaignNo, context.MarketingResult.EstimatedImpressions);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : MaterialProcurementService.cs

 */

using JewelryWorkflow.Application.Adapters;
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 原料采购核验服务(第 1 环节:生产主线入口)。
/// <para>职责:校验原料采购请求 → 调用供应商资质核验适配器(重试+熔断)→
/// 生成原料批次实体(合格入库/不合格退货)→ 写回工作流上下文。</para>
/// </summary>
public sealed class MaterialProcurementService : IWorkflowStep
{
    // 标准日志器(DI 注入:控制台与文件统一输出)。
    private readonly ILogger<MaterialProcurementService> _logger;

    // 供应商资质核验适配器(弹性:重试+熔断)。
    private readonly SupplierInspectionAdapter _inspectionAdapter;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    /// <param name="inspectionAdapter">供应商核验适配器。</param>
    public MaterialProcurementService(ILogger<MaterialProcurementService> logger, SupplierInspectionAdapter inspectionAdapter)
    {
        _logger = logger;
        _inspectionAdapter = inspectionAdapter;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "原料采购核验";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.MaterialProcurement;

    /// <summary>
    /// 执行原料采购核验。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        MaterialProcurementDto? dto = context.Procurement;
        if (dto is null)
        {
            return Result.Fail("缺少原料采购核验输入 DTO。", "DTO_MISSING");
        }
        Guard.NotNull(context.Order, nameof(context.Order));
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:{Type} {Weight}g 供应商={Supplier}",
            StepName, context.OrderId, dto.MaterialType, dto.WeightGram, dto.SupplierName);

        // 2) 调用供应商资质核验适配器(自动重试 + 熔断保护)。
        var inspection = await _inspectionAdapter.CallAsync(
            new SupplierInspectionAdapter.InspectionRequest
            {
                SupplierName = dto.SupplierName,
                CertificateNo = dto.CertificateNo,
                MaterialType = dto.MaterialType,
                WeightGram = dto.WeightGram
            }, cancellationToken);

        // 3) 核验失败:原料批次标记不合格退货,环节失败(阻断下游)。
        if (!inspection.IsSuccess)
        {
            context.MaterialBatchResult = new MaterialBatch
            {
                BatchNo = $"MB-{context.OrderId}",
                MaterialType = dto.MaterialType,
                WeightGram = dto.WeightGram,
                Purity = dto.Purity,
                SupplierName = dto.SupplierName,
                CertificateNo = dto.CertificateNo,
                Status = MaterialStatus.Rejected,
                VerifyRemark = inspection.ErrorMessage ?? string.Empty
            };
            _logger.LogError("【{Stage}】订单#{OrderId} 原料核验失败:{Reason}",
                StepName, context.OrderId, inspection.ErrorMessage);
            return Result.Fail(inspection.ErrorMessage ?? "原料核验失败。", inspection.ErrorCode);
        }

        // 4) 核验通过:生成合格原料批次并写回上下文。
        context.MaterialBatchResult = new MaterialBatch
        {
            BatchNo = $"MB-{context.OrderId}",
            MaterialType = dto.MaterialType,
            WeightGram = dto.WeightGram,
            Purity = dto.Purity,
            SupplierName = dto.SupplierName,
            CertificateNo = dto.CertificateNo,
            PurchasePrice = dto.Budget,
            Status = MaterialStatus.Approved,
            VerifyRemark = inspection.Data!.Remark
        };

        // 5) 模拟业务处理耗时(体现多线程并发流水线)。
        await Task.Delay(Random.Shared.Next(60, 160), cancellationToken);

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:批次={BatchNo} 状态=合格入库",
            StepName, context.OrderId, context.MaterialBatchResult.BatchNo);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PackagingService.cs

 */

using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 包装服务(第 5 环节)。
/// <para>职责:校验包装输入 → 生成包装信息实体(包装类型、防伪标识、装箱)→ 写回上下文。</para>
/// </summary>
public sealed class PackagingService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<PackagingService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public PackagingService(ILogger<PackagingService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "包装";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Packaging;

    /// <summary>
    /// 执行包装。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO 与上游质检报告。
        PackagingRequestDto? dto = context.Packaging;
        QualityReport? quality = context.QualityResult;
        if (dto is null || quality is null)
        {
            return Result.Fail("缺少包装输入或上游质检报告。", "PRECONDITION_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:类型={Type} 防伪={AntiFake}",
            StepName, context.OrderId, dto.PackageType, dto.HasAntiFakeTag);

        // 2) 模拟包装作业。
        await Task.Delay(Random.Shared.Next(50, 120), cancellationToken);

        // 3) 生成包装信息并写回上下文。
        context.PackagingResult = new PackageInfo
        {
            PackageNo = $"PKG-{context.OrderId}",
            QualityReportNo = quality.ReportNo,
            PackageType = dto.PackageType,
            HasAntiFakeTag = dto.HasAntiFakeTag,
            BoxCount = dto.BoxCount,
            PackagedAt = DateTime.Now
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:包装单={PackageNo}",
            StepName, context.OrderId, context.PackagingResult.PackageNo);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ProductionService.cs

 */
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 加工生产服务(第 3 环节)。
/// <para>职责:校验生产输入 → 依据工艺路线与原料批次生成生产工单实体(含损耗核算)→ 写回上下文。</para>
/// </summary>
public sealed class ProductionService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<ProductionService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public ProductionService(ILogger<ProductionService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "加工生产";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Production;

    /// <summary>
    /// 执行加工生产。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO 与上游产出。
        ProductionRequestDto? dto = context.Production;
        MaterialBatch? batch = context.MaterialBatchResult;
        if (dto is null || batch is null)
        {
            return Result.Fail("缺少生产输入或上游原料批次。", "PRECONDITION_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:工艺={Route} 目标重量={Weight}g",
            StepName, context.OrderId, dto.ProcessRoute, dto.ExpectedWeightGram);

        // 2) 模拟工艺执行(倒模/执模/镶石/抛光)。
        await Task.Delay(Random.Shared.Next(120, 260), cancellationToken);

        // 3) 生成生产工单:产出重量按 2% 加工损耗核算。
        decimal outputWeight = dto.ExpectedWeightGram * 0.98m;
        context.ProductionResult = new ProductionOrder
        {
            WorkOrderNo = $"WO-{context.OrderId}",
            DrawingNo = context.DesignResult?.DrawingNo ?? string.Empty,
            MaterialBatchNo = batch.BatchNo,
            ProcessRoute = dto.ProcessRoute,
            InputWeightGram = batch.WeightGram,
            OutputWeightGram = outputWeight,
            LossRatePercent = 2.0m,
            IsFinished = true,
            FinishedAt = DateTime.Now
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:工单={WorkOrderNo} 产出={Output}g 损耗率=2%",
            StepName, context.OrderId, context.ProductionResult.WorkOrderNo, outputWeight);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : QualityService.cs

 */

using JewelryWorkflow.Application.Adapters;
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 质检服务(第 4 环节,质量把关)。
/// <para>职责:调用检测机构适配器获取权威检测数据 → 按工艺评分评定质检等级 →
/// 低于最低放行等级则判为不合格(次品返工/废品报废)→ 写回上下文。</para>
/// </summary>
public sealed class QualityService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<QualityService> _logger;

    // 宝石检测机构适配器(弹性:重试+熔断)。
    private readonly GemLabAdapter _gemLabAdapter;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    /// <param name="gemLabAdapter">检测机构适配器。</param>
    public QualityService(ILogger<QualityService> logger, GemLabAdapter gemLabAdapter)
    {
        _logger = logger;
        _gemLabAdapter = gemLabAdapter;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "质检";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.QualityInspection;

    /// <summary>
    /// 执行质检。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO 与上游产出。
        QualityInspectionDto? dto = context.Inspection;
        ProductionOrder? workOrder = context.ProductionResult;
        if (dto is null || workOrder is null)
        {
            return Result.Fail("缺少质检输入或上游生产工单。", "PRECONDITION_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:质检员={Inspector} 最低放行等级={Grade}",
            StepName, context.OrderId, dto.InspectorName, dto.MinimumPassGrade);

        // 2) 调用检测机构适配器获取权威检测数据(自动重试 + 熔断保护)。
        var lab = await _gemLabAdapter.CallAsync(
            new GemLabAdapter.LabRequest
            {
                SampleNo = workOrder.WorkOrderNo,
                MaterialType = context.MaterialBatchResult?.MaterialType ?? "贵金属",
                DeclaredPurity = context.MaterialBatchResult?.Purity ?? "999"
            }, cancellationToken);

        // 3) 检测机构不可用:质检失败(阻断下游,进入失败分支)。
        if (!lab.IsSuccess)
        {
            _logger.LogError("【{Stage}】订单#{OrderId} 检测机构调用失败:{Reason}",
                StepName, context.OrderId, lab.ErrorMessage);
            return Result.Fail(lab.ErrorMessage ?? "检测机构调用失败。", lab.ErrorCode);
        }

        // 4) 模拟质检耗时。
        await Task.Delay(Random.Shared.Next(60, 150), cancellationToken);

        // 5) 评定质检等级:工艺评分随机 85-100,90 分以上优等,其余合格。
        int craftScore = Random.Shared.Next(85, 101);
        QualityGrade grade = craftScore >= 90 ? QualityGrade.Excellent : QualityGrade.Qualified;

        // 6) 低于最低放行等级:判定不合格(本演示中最低为合格,故合格以上放行)。
        bool passed = grade >= dto.MinimumPassGrade;

        context.QualityResult = new QualityReport
        {
            ReportNo = $"QC-{context.OrderId}",
            WorkOrderNo = workOrder.WorkOrderNo,
            InspectorName = dto.InspectorName,
            MeasuredPurity = lab.Data!.MeasuredPurity,
            MeasuredWeightGram = lab.Data.MeasuredWeightGram,
            CraftScore = craftScore,
            Grade = grade,
            IsPassed = passed,
            InspectedAt = DateTime.Now
        };

        if (!passed)
        {
            _logger.LogWarning("【{Stage}】订单#{OrderId} 质检未通过:等级={Grade} 低于要求={Minimum}",
                StepName, context.OrderId, grade, dto.MinimumPassGrade);
            return Result.Fail($"质检等级 {grade} 低于放行要求 {dto.MinimumPassGrade}。", "QUALITY_REJECTED");
        }

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:报告={ReportNo} 等级={Grade} 评分={Score}",
            StepName, context.OrderId, context.QualityResult.ReportNo, grade, craftScore);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : TrainingService.cs

 */
using JewelryWorkflow.Domain.Common;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Services;

/// <summary>
/// 培训服务(支持环节:员工培训协同)。
/// <para>职责:校验培训输入 → 生成培训记录实体(课程、学时、考核)→ 写回上下文。</para>
/// </summary>
public sealed class TrainingService : IWorkflowStep
{
    // 标准日志器(DI 注入)。
    private readonly ILogger<TrainingService> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="logger">标准日志器。</param>
    public TrainingService(ILogger<TrainingService> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 步骤名称。
    /// </summary>
    public string StepName => "培训";

    /// <summary>
    /// 环节枚举。
    /// </summary>
    public WorkflowStage Stage => WorkflowStage.Training;

    /// <summary>
    /// 执行培训协同。
    /// </summary>
    /// <param name="context">订单工作流上下文。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>执行结果。</returns>
    public async Task<Result> ExecuteAsync(WorkflowContext context, CancellationToken cancellationToken)
    {
        // 1) 校验输入 DTO。
        TrainingRequestDto? dto = context.Training;
        if (dto is null)
        {
            return Result.Fail("缺少培训输入 DTO。", "DTO_MISSING");
        }
        _logger.LogInformation("【{Stage}】订单#{OrderId} 开始:课程={Course} 学员={Trainee} 讲师={Lecturer}",
            StepName, context.OrderId, dto.CourseName, dto.TraineeName, dto.LecturerName);

        // 2) 模拟培训执行与考核。
        await Task.Delay(Random.Shared.Next(40, 110), cancellationToken);

        // 3) 生成培训记录实体(模拟考核通过)。
        context.TrainingResult = new TrainingRecord
        {
            TrainingNo = $"TRN-{context.OrderId}",
            CourseName = dto.CourseName,
            TraineeName = dto.TraineeName,
            LecturerName = dto.LecturerName,
            Hours = dto.Hours,
            IsPassed = true
        };

        _logger.LogInformation("【{Stage}】订单#{OrderId} 完成:学时={Hours}h 考核通过",
            StepName, context.OrderId, dto.Hours);
        return Result.Ok();
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ConditionVariable.cs

 */

namespace JewelryWorkflow.Application.Workflows;

/// <summary>
/// 条件变量(Condition Variable Pattern)核心实现。
/// <para>基于 .NET 的 <see cref="Monitor"/>(Enter/Wait/PulseAll)实现经典条件变量语义:
/// - <see cref="Signal"/>:发出信号并唤醒所有等待线程(PulseAll);
/// - <see cref="Wait()"/>:阻塞当前线程直到收到信号;
/// - <see cref="Wait(TimeSpan)"/>:带超时的等待,防止永久阻塞。
/// 用途:珠宝业务流程流水线中,上游环节完成后 Signal 下游环节,下游环节 Wait 后继续,
/// 实现"前序未完成,后序不启动"的严格依赖编排。</para>
/// </summary>
public sealed class ConditionVariable
{
    // 状态保护锁:所有等待与通知都必须在持有该锁时进行(Monitor 语义要求)。
    private readonly object _gate = new();

    // 信号位:true 表示已有未消费的信号;false 表示等待者需要继续阻塞。
    private bool _signaled;

    /// <summary>
    /// 发出信号:唤醒所有正在等待的线程。
    /// <para>典型用法:生产者完成生产后调用,通知消费者可以继续。</para>
    /// </summary>
    public void Signal()
    {
        lock (_gate)
        {
            _signaled = true;
            // PulseAll 唤醒所有等待线程(比 Pulse 更安全,避免"唤醒丢失")。
            Monitor.PulseAll(_gate);
        }
    }

    /// <summary>
    /// 无条件等待:阻塞当前线程,直到收到信号。
    /// <para>典型用法:消费者在条件不满足时阻塞,收到信号后继续。</para>
    /// </summary>
    public void Wait()
    {
        lock (_gate)
        {
            // 使用 while 循环防"虚假唤醒":即使被唤醒,只要信号未置位就继续等待。
            while (!_signaled)
            {
                Monitor.Wait(_gate);
            }
            // 消费信号:本次唤醒对应一次 Signal。
            _signaled = false;
        }
    }

    /// <summary>
    /// 带超时的等待:阻塞当前线程,直到收到信号或超时。
    /// </summary>
    /// <param name="timeout">最大等待时长。</param>
    /// <returns>true 表示在超时前收到信号;false 表示等待超时。</returns>
    public bool Wait(TimeSpan timeout)
    {
        lock (_gate)
        {
            // 记录等待截止时间(支持循环等待中的超时判定)。
            DateTime deadline = DateTime.UtcNow + timeout;
            while (!_signaled)
            {
                // 计算剩余可等待时间。
                TimeSpan remaining = deadline - DateTime.UtcNow;
                if (remaining <= TimeSpan.Zero)
                {
                    // 超时且仍未收到信号 → 返回失败。
                    return false;
                }
                // Monitor.Wait 支持超时参数,超时后自动重新获取锁返回。
                Monitor.Wait(_gate, remaining);
            }
            _signaled = false;
            return true;
        }
    }

    /// <summary>
    /// 重置信号位(用于批次开始前清理历史信号,避免批次间串扰)。
    /// </summary>
    public void Reset()
    {
        lock (_gate)
        {
            _signaled = false;
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : ConditionVariablePipeline.cs

 */

using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Workflows;

/// <summary>
/// 条件变量流水线引擎(IWorkflowEngine 实现)。
/// <para>编排生产主线环节为一条有界流水线:
/// - 每个环节一个 <see cref="PipelineNode"/>(有界队列 + 专用工作线程),环节间并行;
/// - 整批完成通知使用 <see cref="ConditionVariable"/>(Monitor.Wait/PulseAll 条件变量模式):
///   末节点每完成一个订单就累加完成计数,达到总数时 Signal,
///   主线程 Wait 等待整批完成(带超时保护,防止死等)。
/// - 具备背压:上游环节产出过快时,下游有界队列会阻塞写入,实现全链路流控。
/// 适用于"前序环节完成才能执行后序环节"的严格依赖编排,且支持多订单高并发吞吐。</para>
/// </summary>
public sealed class ConditionVariablePipeline : IWorkflowEngine
{
    /// <summary>
    /// 生产主线环节步骤集合(按执行顺序,由 DI 注入)。
    /// </summary>
    private readonly IReadOnlyList<IWorkflowStep> _steps;

    /// <summary>
    /// 每个节点的输入队列容量(并发上限,由宿主配置)。
    /// </summary>
    private readonly int _nodeCapacity;

    /// <summary>
    /// 标准日志器(DI 注入)。
    /// </summary>
    private readonly ILogger<ConditionVariablePipeline> _logger;

    /// <summary>
    /// 整批完成条件变量(主线程等待所有订单流过全部环节)。
    /// </summary>
    private readonly ConditionVariable _allDone = new();

    // 整批统计(Interlocked 原子更新,多线程安全)。
    private int _expectedTotal;     // 本批订单总数。
    private int _completedCount;    // 已完成的订单数。
    private int _successCount;      // 成功订单数。
    private int _failureCount;      // 失败订单数。

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="steps">生产主线环节步骤(有序集合)。</param>
    /// <param name="nodeCapacity">每节点队列容量(默认 16)。</param>
    /// <param name="logger">标准日志器。</param>
    public ConditionVariablePipeline(IEnumerable<IWorkflowStep> steps, int nodeCapacity, ILogger<ConditionVariablePipeline> logger)
    {
        _steps = steps.ToArray();
        _nodeCapacity = Math.Max(1, nodeCapacity);
        _logger = logger;
        if (_steps.Count == 0)
        {
            throw new ArgumentException("流水线至少需要一个环节步骤。", nameof(steps));
        }
    }

    /// <summary>
    /// 将一批订单上下文送入流水线并等待全部完成。
    /// </summary>
    /// <param name="contexts">订单上下文集合。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>完成统计。</returns>
    public async Task<WorkflowRunSummary> RunBatchAsync(IReadOnlyList<WorkflowContext> contexts, CancellationToken cancellationToken)
    {
        Guard_Contexts(contexts);

        // 记录批次开始时间(用于总耗时统计)。
        var sw = System.Diagnostics.Stopwatch.StartNew();
        _expectedTotal = contexts.Count;
        Interlocked.Exchange(ref _completedCount, 0);
        Interlocked.Exchange(ref _successCount, 0);
        Interlocked.Exchange(ref _failureCount, 0);

        // 1) 构建节点链:前一节点指向后一节点,末节点挂完成回调。
        PipelineNode? head = null;
        PipelineNode? prev = null;
        foreach (IWorkflowStep step in _steps)
        {
            var node = new PipelineNode(step, _nodeCapacity, next: null, OnOrderCompleted, _logger);
            if (head is null)
            {
                head = node;
            }
            else
            {
                prev!.SetNext(node);
            }
            prev = node;
        }

        // 2) 启动全部环节工作线程。
        var nodes = new List<PipelineNode>();
        for (var n = head; n is not null; n = n.Next)
        {
            n.Start();
            nodes.Add(n);
        }

        // 3) 重置完成信号并投递全部订单到首节点。
        // 首节点在节点链构建后必然非空(_steps 已校验非空),此处显式断言以消除可空警告。
        if (head is null)
        {
            throw new InvalidOperationException("流水线节点链构建失败:首节点为空。");
        }
        _allDone.Reset();
        _logger.LogInformation("【流水线】本批 {Count} 个订单开始投递,环节={Steps}",
            contexts.Count, string.Join(" → ", _steps.Select(s => s.StepName)));

        foreach (WorkflowContext context in contexts)
        {
            // 有界队列背压:写入方在队列满时自动阻塞,控制进入速率。
            await head.Input.WriteAsync(context, cancellationToken);
        }
        // 投递完成:关闭首节点输入,触发全链级联退出。
        head.CompleteInput();

        // 4) 条件变量等待整批完成(带超时保护,防止某个环节死锁导致永久阻塞)。
        bool finished = _allDone.Wait(TimeSpan.FromSeconds(120));
        sw.Stop();

        // 5) 汇总统计并输出。
        var summary = new WorkflowRunSummary
        {
            Total = _expectedTotal,
            SuccessCount = Volatile.Read(ref _successCount),
            FailureCount = Volatile.Read(ref _failureCount),
            ElapsedMilliseconds = sw.ElapsedMilliseconds
        };

        if (!finished)
        {
            // 超时:记录错误(完成数不足,可能有环节异常)。
            _logger.LogError("【流水线】整批等待超时:已完成 {Completed}/{Total},请检查环节线程状态。",
                Volatile.Read(ref _completedCount), _expectedTotal);
        }
        else
        {
            _logger.LogInformation("【流水线】整批完成:{Summary}", summary);
        }
        return summary;
    }

    /// <summary>
    /// 末节点完成回调(由流水线工作线程调用,条件变量信号在此触发)。
    /// </summary>
    /// <param name="context">订单上下文。</param>
    /// <param name="success">订单是否成功。</param>
    private void OnOrderCompleted(WorkflowContext context, bool success)
    {
        // 原子更新统计。
        if (success)
        {
            Interlocked.Increment(ref _successCount);
            context.MarkCompleted();
        }
        else
        {
            Interlocked.Increment(ref _failureCount);
        }
        int completed = Interlocked.Increment(ref _completedCount);

        _logger.LogInformation("【流水线】订单#{OrderId} 出流水线:{Result}({Completed}/{Total})",
            context.OrderId, success ? "成功" : "失败", completed, _expectedTotal);

        // 整批全部完成 → 条件变量发出信号,唤醒主线程。
        if (completed >= _expectedTotal)
        {
            _allDone.Signal();
        }
    }

    /// <summary>
    /// 校验批次输入。
    /// </summary>
    /// <param name="contexts">订单上下文集合。</param>
    private static void Guard_Contexts(IReadOnlyList<WorkflowContext> contexts)
    {
        if (contexts is null || contexts.Count == 0)
        {
            throw new ArgumentException("批次订单上下文不能为空。", nameof(contexts));
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : PipelineNode.cs

 */

using System.Threading.Channels;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Workflows;

/// <summary>
/// 流水线节点(生产主线上的一个环节)。
/// <para>每个节点 = 一个业务环节步骤 + 一个有界输入队列(Channel)+ 一个专用工作线程。
/// - Channel 提供异步条件队列语义(队列空时消费者线程自动阻塞等待,即"条件等待");
/// - 有界容量提供背压(上游过快时写入阻塞),防止无界堆积;
/// - 单工作线程保证"环节内串行、环节间并行"的流水线并发模型。
/// 上游节点处理完成后将上下文转发给下游节点的输入队列,实现环节依赖编排。</para>
/// </summary>
internal sealed class PipelineNode
{
    /// <summary>
    /// 本节点承载的业务环节步骤。
    /// </summary>
    private readonly IWorkflowStep _step;

    /// <summary>
    /// 输入队列(有界 Channel,容量由引擎统一配置)。
    /// </summary>
    private readonly Channel<WorkflowContext> _input;

    /// <summary>
    /// 下游节点(为 null 表示本节点是末节点;构建链时通过 <see cref="SetNext"/> 连接)。
    /// </summary>
    private PipelineNode? _next;

    /// <summary>
    /// 末节点完成回调(参数:上下文、是否成功)。
    /// </summary>
    private readonly Action<WorkflowContext, bool> _onCompleted;

    /// <summary>
    /// 标准日志器(DI 注入)。
    /// </summary>
    private readonly ILogger _logger;

    /// <summary>
    /// 本节点专用工作线程(条件变量模式的消费者线程,Monitor/Channel 条件等待)。
    /// </summary>
    private readonly Thread _worker;

    /// <summary>
    /// 构造函数。
    /// </summary>
    /// <param name="step">业务环节步骤。</param>
    /// <param name="capacity">输入队列容量。</param>
    /// <param name="next">下游节点。</param>
    /// <param name="onCompleted">末节点完成回调。</param>
    /// <param name="logger">标准日志器。</param>
    public PipelineNode(IWorkflowStep step, int capacity, PipelineNode? next, Action<WorkflowContext, bool> onCompleted, ILogger logger)
    {
        _step = step;
        _next = next;
        _onCompleted = onCompleted;
        _logger = logger;

        // 有界 Channel:FullMode.Wait 表示满时写入方阻塞等待(背压),SingleReader 优化单消费者性能。
        _input = Channel.CreateBounded<WorkflowContext>(new BoundedChannelOptions(Math.Max(1, capacity))
        {
            FullMode = BoundedChannelFullMode.Wait,
            SingleReader = true,
            SingleWriter = false
        });

        // 每个环节一个专用后台线程(真实的多线程流水线)。
        _worker = new Thread(RunLoop)
        {
            IsBackground = true,
            Name = $"Pipeline-{step.StepName}"
        };
    }

    /// <summary>
    /// 输入队列写入端(上游节点/引擎向本节点投递订单上下文)。
    /// </summary>
    public ChannelWriter<WorkflowContext> Input => _input.Writer;

    /// <summary>
    /// 下游节点(为 null 表示末节点)。
    /// </summary>
    public PipelineNode? Next => _next;

    /// <summary>
    /// 连接下游节点(仅在启动前由引擎构建链时调用,运行期只读,无并发问题)。
    /// </summary>
    /// <param name="next">下游节点。</param>
    public void SetNext(PipelineNode next) => _next = next;

    /// <summary>
    /// 启动本节点工作线程。
    /// </summary>
    public void Start() => _worker.Start();

    /// <summary>
    /// 关闭输入队列(引擎投递完成后调用;本节点消费完剩余项后级联关闭下游)。
    /// </summary>
    public void CompleteInput() => _input.Writer.TryComplete();

    /// <summary>
    /// 工作线程主循环:条件等待输入 → 处理 → 转发下游/完成回调。
    /// </summary>
    private void RunLoop()
    {
        try
        {
            // 条件等待:WaitToReadAsync 在队列空时挂起当前线程(条件变量语义),
            // 上游写入或队列被 Complete 后恢复。
            while (true)
            {
                bool hasData;
                try
                {
                    hasData = _input.Reader.WaitToReadAsync().AsTask().GetAwaiter().GetResult();
                }
                catch
                {
                    // 队列异常关闭:结束循环。
                    break;
                }
                if (!hasData)
                {
                    // 队列已关闭且无剩余数据:退出。
                    break;
                }
                // 批量取走当前队列中的全部上下文(提升吞吐)。
                while (_input.Reader.TryRead(out WorkflowContext? context))
                {
                    Process(context);
                }
            }
        }
        finally
        {
            // 本节点消费完输入后,级联关闭下游输入,保证全链 worker 优雅退出。
            _next?.CompleteInput();
        }
    }

    /// <summary>
    /// 处理单个订单上下文。
    /// </summary>
    /// <param name="context">订单上下文。</param>
    private void Process(WorkflowContext context)
    {
        bool success = true;

        // 若上游环节已失败(失败快速通道),本环节不再执行业务,直接转发。
        if (string.IsNullOrEmpty(context.FailureMessage))
        {
            try
            {
                // 在专用线程上同步等待异步业务执行(线程内串行,天然线程安全)。
                var result = _step.ExecuteAsync(context, CancellationToken.None).GetAwaiter().GetResult();
                if (!result.IsSuccess)
                {
                    // 环节业务失败:标记订单失败(阻断语义:失败订单不再继续执行业务环节)。
                    context.MarkFailed(_step.Stage, result.ErrorMessage ?? "未知错误");
                    _logger.LogWarning("【{Stage}】订单#{OrderId} 环节失败:{Reason}",
                        _step.StepName, context.OrderId, result.ErrorMessage);
                    success = false;
                }
            }
            catch (Exception ex)
            {
                // 未预期异常:同样标记失败,避免线程崩溃。
                context.MarkFailed(_step.Stage, ex.Message);
                _logger.LogError(ex, "【{Stage}】订单#{OrderId} 环节异常。", _step.StepName, context.OrderId);
                success = false;
            }
        }

        if (_next is not null)
        {
            // 非末节点:转发给下游(TryWrite;因容量为 Wait 模式,多数情况直接写入)。
            while (!_next.Input.TryWrite(context))
            {
                // 下游队列满(背压):短暂让出 CPU 后重试,直到写入成功。
                Thread.Yield();
            }
        }
        else
        {
            // 末节点:订单最终成败以整链失败标记为准(任一环节失败即订单失败;
            // 下游环节经由"失败快速通道"跳过执行,不覆盖失败状态)。
            _onCompleted(context, string.IsNullOrEmpty(context.FailureMessage));
        }
    }
}
/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式

# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : SupportWorkflowRunner.cs

 */

using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Application.Workflows;

/// <summary>
/// 支持流程并行执行器(财务/营销推广/业务/人事行政/IT/培训)。
/// <para>生产主线(6 个环节)完成后,对每个订单并行执行 6 个支持环节:
/// - 为每个"订单 × 环节"组合提交并行任务,使用 SemaphoreSlim 限制最大并发度;
/// - 每个支持环节读取订单快照(<see cref="WorkflowContext.Snapshot"/>,线程安全只读),
///   执行完成后将产出实体复制回原上下文(不同环节写不同属性,天然安全);
/// - 支持环节失败仅记录警告,不阻断其他环节(职责独立)。</para>
/// </summary>
public sealed class SupportWorkflowRunner
{
    /// <summary>
    /// 支持环节步骤集合(6 个,由 DI 注入)。
    /// </summary>
    private readonly IReadOnlyList<IWorkflowStep> _supportSteps;

    /// <summary>
    /// 最大并发度(同时执行的环节任务数上限)。
    /// </summary>
    private readonly int _maxConcurrency;

    /// <summary>
    /// 标准日志器(DI 注入)。
    /// </summary>
    private readonly ILogger<SupportWorkflowRunner> _logger;

    /// <summary>
    /// 构造函数(依赖注入)。
    /// </summary>
    /// <param name="supportSteps">支持环节步骤集合。</param>
    /// <param name="maxConcurrency">最大并发度(默认 8)。</param>
    /// <param name="logger">标准日志器。</param>
    public SupportWorkflowRunner(IEnumerable<IWorkflowStep> supportSteps, int maxConcurrency, ILogger<SupportWorkflowRunner> logger)
    {
        _supportSteps = supportSteps.ToArray();
        _maxConcurrency = Math.Max(1, maxConcurrency);
        _logger = logger;
    }

    /// <summary>
    /// 对一批订单并行执行全部支持环节。
    /// </summary>
    /// <param name="contexts">订单上下文集合(生产主线已完成的订单)。</param>
    /// <param name="cancellationToken">取消令牌。</param>
    /// <returns>成功执行的环节任务数。</returns>
    public async Task<int> RunForOrdersAsync(IReadOnlyList<WorkflowContext> contexts, CancellationToken cancellationToken)
    {
        if (contexts is null || contexts.Count == 0)
        {
            return 0;
        }
        _logger.LogInformation("【支持流程】开始为 {Orders} 个订单并行执行 {Steps} 个支持环节(并发上限 {Max})",
            contexts.Count, string.Join("、", _supportSteps.Select(s => s.StepName)), _maxConcurrency);

        // 并发度信号量(限制同时运行的环节任务数,避免线程池过载)。
        using var semaphore = new SemaphoreSlim(_maxConcurrency);
        var tasks = new List<Task>();
        int successCount = 0;

        foreach (WorkflowContext context in contexts)
        {
            // 每个订单一份只读快照(避免多环节并发写同一上下文造成竞态)。
            WorkflowContext snapshot = context.Snapshot();
            foreach (IWorkflowStep step in _supportSteps)
            {
                // 为每个"订单 × 环节"提交一个并行任务。
                tasks.Add(Task.Run(async () =>
                {
                    await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
                    try
                    {
                        // 执行支持环节(快照只读,产出挂到快照上)。
                        var result = await step.ExecuteAsync(snapshot, cancellationToken).ConfigureAwait(false);
                        if (result.IsSuccess)
                        {
                            // 将产出实体复制回原上下文(不同环节写不同属性,安全)。
                            CopyResult(context, snapshot, step.Stage);
                            Interlocked.Increment(ref successCount);
                            _logger.LogInformation("【支持流程】订单#{OrderId} 环节[{Step}]完成",
                                context.OrderId, step.StepName);
                        }
                        else
                        {
                            // 支持环节失败:仅记录警告,不阻断其他环节。
                            _logger.LogWarning("【支持流程】订单#{OrderId} 环节[{Step}]未完成:{Reason}",
                                context.OrderId, step.StepName, result.ErrorMessage);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        // 取消:静默退出。
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "【支持流程】订单#{OrderId} 环节[{Step}]异常。",
                            context.OrderId, step.StepName);
                    }
                    finally
                    {
                        semaphore.Release();
                    }
                }, cancellationToken));
            }
        }

        // 等待全部支持环节任务完成。
        await Task.WhenAll(tasks).ConfigureAwait(false);
        _logger.LogInformation("【支持流程】全部完成:成功执行 {Success} 个环节任务", Volatile.Read(ref successCount));
        return Volatile.Read(ref successCount);
    }

    /// <summary>
    /// 按环节类型把快照上的产出实体复制回原上下文。
    /// </summary>
    /// <param name="target">原上下文。</param>
    /// <param name="source">快照上下文。</param>
    /// <param name="stage">环节枚举。</param>
    private static void CopyResult(WorkflowContext target, WorkflowContext source, WorkflowStage stage)
    {
        switch (stage)
        {
            case WorkflowStage.Finance:
                target.FinanceResult = source.FinanceResult;
                break;
            case WorkflowStage.Marketing:
                target.MarketingResult = source.MarketingResult;
                break;
            case WorkflowStage.Business:
                target.BusinessResult = source.BusinessResult;
                break;
            case WorkflowStage.HrAdmin:
                target.HrResult = source.HrResult;
                break;
            case WorkflowStage.InformationTechnology:
                target.ItResult = source.ItResult;
                break;
            case WorkflowStage.Training:
                target.TrainingResult = source.TrainingResult;
                break;
        }
    }
}

  

调用:

/*
 
 # encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Condition Variable  Pattern 条件变量模式 Synchronization Patterns 同步型模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : vs2026 c# .net 10
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/09/05 22:16 
# User      :  geovindu
# Product   : Visual Studio 2026
# Project   : CSharpDesignPattern
# File      : Program.cs

 */

using JewelryWorkflow.Application.Adapters;
using JewelryWorkflow.Application.Services;
using JewelryWorkflow.Application.Workflows;
using JewelryWorkflow.Domain.Contracts;
using JewelryWorkflow.Domain.Dtos;
using JewelryWorkflow.Domain.Entities;
using JewelryWorkflow.Infrastructure.Logging;
using JewelryWorkflow.Infrastructure.Repositories;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace JewelryWorkflow.Host;

/// <summary>
/// 程序入口(宿主层)。
/// <para>演示流程:
/// 1. 构建通用主机(HostBuilder):装配配置、标准日志(控制台 + 分级日期文件 + Karambolo 综合文件)、
///    依赖注入全部服务(12 个业务环节服务、2 个弹性适配器、条件变量流水线引擎、支持流程执行器、内存仓储);
/// 2. 三阶段演示珠宝行业全程业务流程:
///    - 阶段一【正常流程】:5 个订单跑通"原料采购核验 → 设计制图 → 加工生产 → 质检 → 包装 → 物流"主线,
///      随后 6 个支持环节(财务/营销/业务/人事/IT/培训)并行执行;
///    - 阶段二【重试演示】:供应商核验适配器注入瞬时故障(前 2 次失败),观察指数退避重试后成功;
///    - 阶段三【熔断演示】:供应商核验适配器注入持续故障,观察连续失败后熔断器打开、
///      后续订单快速失败(CIRCUIT_OPEN);
/// 3. 输出汇总并打印日志目录结构(Logs/yyyy-MM-dd/app-{等级}.log)。</para>
/// </summary>
public static class Program
{
    // ===== 辅助说明 =====
    // 因静态类不能作为泛型参数,日志分类使用下方标记类型:ILogger<JewelryWorkflowHostMarker>,
    // 控制台与文件输出分类显示为 "JewelryWorkflow.Host.JewelryWorkflowHostMarker"。
    /// <summary>
    /// 程序主入口。
    /// </summary>
    /// <param name="args">命令行参数。</param>
    /// <returns>退出码(0 成功)。</returns>
    public static async Task<int> Main(string[] args)
    {
        // ========== 1. 构建通用主机 ==========
        using IHost host = BuildHost(args);
        await host.StartAsync();

        // 从 DI 解析日志器与核心服务。
        ILogger<JewelryWorkflowHostMarker> logger = host.Services.GetRequiredService<ILogger<JewelryWorkflowHostMarker>>();
        IWorkflowEngine pipeline = host.Services.GetRequiredService<IWorkflowEngine>();
        SupportWorkflowRunner supportRunner = host.Services.GetRequiredService<SupportWorkflowRunner>();
        SupplierInspectionAdapter supplierAdapter = host.Services.GetRequiredService<SupplierInspectionAdapter>();
        InMemoryRepository<long, JewelryOrder> orderRepo = host.Services.GetRequiredService<InMemoryRepository<long, JewelryOrder>>();

        logger.LogInformation("========== 珠宝行业企业级全程业务流程演示启动 ==========");
        logger.LogInformation("生产主线:原料采购核验 → 设计制图 → 加工生产 → 质检 → 包装 → 物流(条件变量流水线)");
        logger.LogInformation("支持环节:财务 / 营销推广 / 业务 / 人事行政 / IT / 培训(并行执行)");

        try
        {
            // ========== 2. 阶段一:正常流程(适配器无故障) ==========
            logger.LogInformation("【阶段一】正常流程:提交 5 个订单(无外部故障)");
            supplierAdapter.Mode = SupplierInspectionAdapter.FailureMode.None;
            await RunPipelinePhase(pipeline, supportRunner, orderRepo, logger, BuildOrders(1, 5));

            // ========== 3. 阶段二:重试演示(瞬时故障 2 次后恢复) ==========
            logger.LogInformation("【阶段二】重试演示:供应商核验服务瞬时抖动(前 2 次失败,第 3 次成功)");
            supplierAdapter.Mode = SupplierInspectionAdapter.FailureMode.Transient;
            await RunPipelinePhase(pipeline, supportRunner, orderRepo, logger, BuildOrders(6, 2));

            // ========== 4. 阶段三:熔断演示(持续故障 → 熔断打开 → 快速失败) ==========
            logger.LogInformation("【阶段三】熔断演示:供应商核验服务持续不可用(观察熔断打开与快速失败)");
            supplierAdapter.Mode = SupplierInspectionAdapter.FailureMode.Broken;
            await RunPipelinePhase(pipeline, supportRunner, orderRepo, logger, BuildOrders(8, 3));

            // ========== 5. 汇总与日志结构展示 ==========
            await PrintSummaryAsync(logger, orderRepo);
        }
        catch (Exception ex)
        {
            // 全局兜底:任何未预期异常都走标准日志。
            logger.LogError(ex, "演示执行过程中发生未预期异常。");
            return 1;
        }
        finally
        {
            // 优雅停止主机(触发各日志 Provider 的 Dispose,确保文件刷盘)。
            await host.StopAsync();
            logger.LogInformation("========== 演示结束 ==========");
        }

        // 等待消费者线程把最终日志刷盘(分级文件日志 200ms 定时刷盘 + Dispose 强刷)。
        await Task.Delay(500);
        return 0;
    }

    /// <summary>
    /// 构建通用主机:配置、日志、依赖注入。
    /// </summary>
    /// <param name="args">命令行参数。</param>
    /// <returns>主机实例。</returns>
    private static IHost BuildHost(string[] args)
    {
        return Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
            // 加载 appsettings.json(复制到输出目录)。
            .ConfigureAppConfiguration((context, config) =>
            {
                config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
            })
            // 标准日志装配:控制台 + 分级日期文件 + Karambolo 综合文件。
            .ConfigureLogging((context, logging) =>
            {
                logging.ClearProviders();
                // 1) 控制台输出(Microsoft.Extensions.Logging.Console)。
                logging.AddConsole();
                // 2) 分级日期文件日志(自研:Logs/yyyy-MM-dd/app-{info,error,debug,warn}.log)。
                logging.AddLeveledFile(options =>
                {
                    IConfigurationSection section = context.Configuration.GetSection("Logging:LeveledFile");
                    options.RootPath = section["RootPath"] ?? "Logs";
                    options.Enabled = section.GetValue("Enabled", true);
                    options.FlushIntervalMilliseconds = section.GetValue("FlushIntervalMilliseconds", 200);
                    options.FlushThreshold = section.GetValue("FlushThreshold", 50);
                    options.MaxFileBytes = section.GetValue("MaxFileBytes", 5L * 1024 * 1024);
                });
                // 3) Karambolo 综合文件日志(Logs/app-combined-{yyyy-MM-dd}.log)。
                logging.AddKaramboloCombinedFile();
                // 全局最小等级(Trace 全部记录;控制台按此输出)。
                logging.SetMinimumLevel(LogLevel.Trace);
            })
            // 依赖注入装配。
            .ConfigureServices((context, services) =>
            {
                IConfigurationSection wf = context.Configuration.GetSection("Workflow");
                int nodeCapacity = wf.GetValue("PipelineNodeCapacity", 16);
                int supportMax = wf.GetValue("SupportMaxConcurrency", 8);

                // —— 弹性适配器(单例:熔断器状态跨调用共享,才能演示熔断效果)——
                services.AddSingleton<SupplierInspectionAdapter>();
                services.AddSingleton<GemLabAdapter>();

                // —— 12 个业务环节服务(注入 ILogger<T> 与适配器)——
                services.AddSingleton<MaterialProcurementService>();
                services.AddSingleton<DesignService>();
                services.AddSingleton<ProductionService>();
                services.AddSingleton<QualityService>();
                services.AddSingleton<PackagingService>();
                services.AddSingleton<LogisticsService>();
                services.AddSingleton<FinanceService>();
                services.AddSingleton<MarketingService>();
                services.AddSingleton<BusinessService>();
                services.AddSingleton<HrService>();
                services.AddSingleton<ItService>();
                services.AddSingleton<TrainingService>();

                // —— 条件变量流水线引擎(单例:装配生产主线 6 环节)——
                services.AddSingleton<IWorkflowEngine>(sp =>
                    new ConditionVariablePipeline(MainSteps(sp), nodeCapacity,
                        sp.GetRequiredService<ILogger<ConditionVariablePipeline>>()));

                // —— 支持流程并行执行器(装配支持环节 6 环节)——
                services.AddSingleton(sp =>
                    new SupportWorkflowRunner(SupportSteps(sp), supportMax,
                        sp.GetRequiredService<ILogger<SupportWorkflowRunner>>()));

                // —— 线程安全内存仓储(演示:保存完成的订单)——
                services.AddSingleton(_ => new InMemoryRepository<long, JewelryOrder>(o => o.OrderId));
            })
            .Build();
    }

    /// <summary>
    /// 生产主线步骤集合(按执行顺序)。
    /// </summary>
    /// <param name="sp">服务提供器。</param>
    /// <returns>主线环节步骤数组。</returns>
    private static IReadOnlyList<IWorkflowStep> MainSteps(IServiceProvider sp)
        => new IWorkflowStep[]
        {
            sp.GetRequiredService<MaterialProcurementService>(),
            sp.GetRequiredService<DesignService>(),
            sp.GetRequiredService<ProductionService>(),
            sp.GetRequiredService<QualityService>(),
            sp.GetRequiredService<PackagingService>(),
            sp.GetRequiredService<LogisticsService>()
        };

    /// <summary>
    /// 支持环节步骤集合(并行执行)。
    /// </summary>
    /// <param name="sp">服务提供器。</param>
    /// <returns>支持环节步骤数组。</returns>
    private static IReadOnlyList<IWorkflowStep> SupportSteps(IServiceProvider sp)
        => new IWorkflowStep[]
        {
            sp.GetRequiredService<FinanceService>(),
            sp.GetRequiredService<MarketingService>(),
            sp.GetRequiredService<BusinessService>(),
            sp.GetRequiredService<HrService>(),
            sp.GetRequiredService<ItService>(),
            sp.GetRequiredService<TrainingService>()
        };

    /// <summary>
    /// 构造一批订单上下文(每个订单包含主订单 + 12 个环节输入 DTO)。
    /// </summary>
    /// <param name="startId">起始订单编号。</param>
    /// <param name="count">订单数量。</param>
    /// <returns>订单上下文列表。</returns>
    private static IReadOnlyList<WorkflowContext> BuildOrders(int startId, int count)
    {
        var contexts = new List<WorkflowContext>(count);
        for (int i = 0; i < count; i++)
        {
            long id = startId + i;
            var order = new JewelryOrder
            {
                OrderId = id,
                CustomerName = $"客户{id}",
                ProductDescription = $"18K金镶钻戒指 #{id}",
                OrderAmount = 15000 + id * 1000,
                CreatedAt = DateTime.Now
            };
            var ctx = new WorkflowContext(id, order)
            {
                // 原料采购核验输入。
                Procurement = new MaterialProcurementDto
                {
                    MaterialType = "18K金",
                    WeightGram = 18.5m,
                    Purity = "750",
                    SupplierName = $"金料供应商{id % 3 + 1}",
                    CertificateNo = $"CERT-{id}",
                    Budget = 6000 + id * 200
                },
                // 设计制图输入。
                Design = new DesignRequestDto
                {
                    StyleName = $"经典六爪款 {id}",
                    DesignerName = "设计师A",
                    CraftRequirement = "爪镶;抛光;内圈刻字"
                },
                // 加工生产输入。
                Production = new ProductionRequestDto
                {
                    ProcessRoute = "倒模;执模;镶石;抛光",
                    ExpectedWeightGram = 18.5m
                },
                // 质检输入。
                Inspection = new QualityInspectionDto
                {
                    InspectorName = "质检员B",
                    MinimumPassGrade = JewelryWorkflow.Domain.Enums.QualityGrade.Qualified
                },
                // 包装输入。
                Packaging = new PackagingRequestDto
                {
                    PackageType = "礼盒装",
                    HasAntiFakeTag = true,
                    BoxCount = 1
                },
                // 物流输入。
                Logistics = new LogisticsRequestDto
                {
                    CarrierName = "顺丰速运",
                    ReceiverName = $"收件人{id}",
                    ReceiverAddress = $"深圳市罗湖区水贝珠宝园 {id} 号"
                },
                // 财务输入。
                Finance = new FinanceRequestDto
                {
                    PurchasePayment = 6000 + id * 200,
                    SalesReceipt = 15000 + id * 1000,
                    NeedInvoice = true
                },
                // 营销推广输入。
                Marketing = new MarketingRequestDto
                {
                    CampaignName = $"新品首发 {id}",
                    Channel = "抖音电商",
                    Budget = 2000
                },
                // 业务输入。
                Business = new BusinessRequestDto
                {
                    CustomerLevel = id % 2 == 0 ? "VIP" : "普通",
                    Terms = "预付 30%,尾款发货前结清",
                    AccountManager = "跟单员C",
                    IntentionScore = 80 + (int)(id % 10)
                },
                // 人事行政输入。
                HrAdmin = new HrRequestDto
                {
                    EmployeeNo = $"E{100 + id}",
                    EmployeeName = "员工D",
                    Department = "销售部",
                    AdminTask = "为订单盖章用印"
                },
                // IT 输入。
                InformationTechnology = new ItRequestDto
                {
                    SystemName = "ERP",
                    PermissionTask = "开通订单查看权限"
                },
                // 培训输入。
                Training = new TrainingRequestDto
                {
                    CourseName = "珠宝销售话术训练",
                    TraineeName = "员工D",
                    LecturerName = "讲师E",
                    Hours = 4
                }
            };
            contexts.Add(ctx);
        }
        return contexts;
    }

    /// <summary>
    /// 运行一个阶段:主线流水线 + 支持流程并行执行 + 结果入仓储。
    /// </summary>
    /// <param name="pipeline">条件变量流水线引擎。</param>
    /// <param name="supportRunner">支持流程执行器。</param>
    /// <param name="orderRepo">订单仓储。</param>
    /// <param name="logger">日志器。</param>
    /// <param name="contexts">订单上下文。</param>
    private static async Task RunPipelinePhase(
        IWorkflowEngine pipeline,
        SupportWorkflowRunner supportRunner,
        InMemoryRepository<long, JewelryOrder> orderRepo,
        ILogger<JewelryWorkflowHostMarker> logger,
        IReadOnlyList<WorkflowContext> contexts)
    {
        // 1) 主线流水线(条件变量协调 6 个生产环节)。
        WorkflowRunSummary summary = await pipeline.RunBatchAsync(contexts, CancellationToken.None);
        logger.LogInformation("阶段主线汇总:{Summary}", summary);

        // 2) 支持流程并行执行(财务/营销/业务/人事/IT/培训)。
        int supportOk = await supportRunner.RunForOrdersAsync(contexts, CancellationToken.None);
        logger.LogInformation("阶段支持流程汇总:成功执行 {SupportOk} 个环节任务", supportOk);

        // 3) 把订单实体保存到内存仓储(演示仓储线程安全写)。
        foreach (WorkflowContext ctx in contexts)
        {
            await orderRepo.SaveAsync(ctx.Order);
        }
    }

    /// <summary>
    /// 打印各订单最终结果表与日志目录结构。
    /// </summary>
    /// <param name="logger">日志器。</param>
    /// <param name="orderRepo">订单仓储。</param>
    private static async Task PrintSummaryAsync(ILogger<JewelryWorkflowHostMarker> logger, InMemoryRepository<long, JewelryOrder> orderRepo)
    {
        logger.LogInformation("========== 订单结果汇总 ==========");
        IReadOnlyList<JewelryOrder> orders = await orderRepo.GetAllAsync();
        foreach (JewelryOrder o in orders.OrderBy(x => x.OrderId))
        {
            // 控制台与文件统一输出(同一 ILogger 实例)。
            logger.LogInformation("订单#{OrderId} [{Status}] 客户={Customer} 商品={Product} 金额={Amount}元 完成={CompletedAt}",
                o.OrderId, o.Status, o.CustomerName, o.ProductDescription, o.OrderAmount,
                o.CompletedAt?.ToString("HH:mm:ss") ?? "-");
        }
        logger.LogInformation("========== 日志文件结构(Logs 目录) ==========");
        ListLogTree("Logs", 0, logger);
    }

    /// <summary>
    /// 递归打印日志目录树(验证"按日期分文件夹、按等级分文件")。
    /// </summary>
    /// <param name="path">目录路径。</param>
    /// <param name="depth">递归深度。</param>
    /// <param name="logger">日志器。</param>
    private static void ListLogTree(string path, int depth, ILogger<JewelryWorkflowHostMarker> logger)
    {
        string indent = new string(' ', depth * 2);
        if (Directory.Exists(path))
        {
            foreach (string dir in Directory.GetDirectories(path))
            {
                logger.LogInformation("{Indent}📁 {Dir}", indent, Path.GetFileName(dir));
                ListLogTree(dir, depth + 1, logger);
            }
            foreach (string file in Directory.GetFiles(path))
            {
                logger.LogInformation("{Indent}📄 {File} ({Size} 字节)", indent, Path.GetFileName(file), new FileInfo(file).Length);
            }
        }
        else
        {
            logger.LogWarning("日志目录不存在:{Path}(可能尚未产生日志)", path);
        }
    }
}

/// <summary>
/// 宿主日志标记类型(供 <see cref="ILogger{T}"/> 作为泛型参数使用)。
/// </summary>
public sealed class JewelryWorkflowHostMarker
{
}

  

输出:

image

 

posted @ 2026-09-15 22:01  ®Geovin Du Dream Park™  阅读(11)  评论(0)    收藏  举报