You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
11 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// ============================================================================
// 【文件说明】HwProductInfoDetailService.cs - 产品信息明细服务类
// ============================================================================
// 这个服务类负责处理产品信息明细的业务逻辑,包括:
// - 产品明细的 CRUD 操作
// - 树形结构(父子关系)管理
// - 祖先路径Ancestors自动计算
//
// 【业务背景】
// 产品信息明细用于管理产品的详细配置项,支持多级树形结构。
// 例如:产品 -> 版本 -> 配置项 -> 子配置项
//
// 【与 Java Spring Boot 的对比】
// Java Spring Boot:
// @Service
// public class HwProductInfoDetailServiceImpl implements HwProductInfoDetailService { ... }
//
// ASP.NET Core + Furion:
// public class HwProductInfoDetailService : ITransient { ... }
// ============================================================================
namespace Admin.NET.Plugin.HwPortal;
/// <summary>
/// 产品信息明细服务类。
/// <para>
/// 【服务职责】
/// 1. 管理产品明细的增删改查
/// 2. 自动计算和维护树形结构的祖先路径Ancestors
/// 3. 处理空字符串规范化
/// </para>
/// <para>
/// 【树形结构说明】
/// - ParentId父节点ID0表示顶级节点
/// - Ancestors祖先路径格式为"0,1,2"表示从根到父节点的路径
///
/// 示例:
/// 产品AID=1, ParentId=0, Ancestors="0"
/// └── 版本BID=2, ParentId=1, Ancestors="0,1"
/// └── 配置CID=3, ParentId=2, Ancestors="0,1,2"
/// </para>
/// </summary>
public class HwProductInfoDetailService : ITransient
{
/// <summary>
/// MyBatis 映射器名称(保留用于回滚)。
/// </summary>
private const string Mapper = "HwProductInfoDetailMapper";
/// <summary>
/// MyBatis 执行器(保留用于回滚)。
/// </summary>
private readonly HwPortalMyBatisExecutor _executor;
/// <summary>
/// SqlSugar 数据访问对象。
/// </summary>
private readonly ISqlSugarClient _db;
/// <summary>
/// 构造函数(依赖注入)。
/// </summary>
/// <param name="executor">MyBatis 执行器</param>
/// <param name="db">SqlSugar 数据访问对象</param>
public HwProductInfoDetailService(HwPortalMyBatisExecutor executor, ISqlSugarClient db)
{
_executor = executor;
_db = db;
}
/// <summary>
/// 根据明细ID查询产品明细信息。
/// </summary>
/// <param name="productInfoDetailId">明细ID</param>
/// <returns>产品明细实体</returns>
public async Task<HwProductInfoDetail> SelectHwProductInfoDetailByProductInfoDetailId(long productInfoDetailId)
{
// 回滚到 XML 方案时可直接恢复:
// return await _executor.QuerySingleAsync<HwProductInfoDetail>(Mapper, "selectHwProductInfoDetailByProductInfoDetailId", new { productInfoDetailId });
return await _db.Queryable<HwProductInfoDetail>()
.Where(item => item.ProductInfoDetailId == productInfoDetailId)
.FirstAsync();
}
/// <summary>
/// 查询产品明细列表。
/// <para>
/// 【动态查询条件】
/// 支持按父ID、产品ID、配置模式、标题、描述、排序号、图片、祖先路径等条件筛选。
/// 所有条件都是可选的,有值时才添加到 WHERE 子句。
/// </para>
/// </summary>
/// <param name="input">查询条件</param>
/// <returns>产品明细列表</returns>
public async Task<List<HwProductInfoDetail>> SelectHwProductInfoDetailList(HwProductInfoDetail input)
{
HwProductInfoDetail query = input ?? new HwProductInfoDetail();
// 回滚到 XML 方案时可直接恢复:
// return await _executor.QueryListAsync<HwProductInfoDetail>(Mapper, "selectHwProductInfoDetailList", query);
return await _db.Queryable<HwProductInfoDetail>()
.WhereIF(query.ParentId.HasValue, item => item.ParentId == query.ParentId)
.WhereIF(query.ProductInfoId.HasValue, item => item.ProductInfoId == query.ProductInfoId)
.WhereIF(!string.IsNullOrWhiteSpace(query.ConfigModal), item => item.ConfigModal == query.ConfigModal)
.WhereIF(!string.IsNullOrWhiteSpace(query.ProductInfoDetailTitle), item => item.ProductInfoDetailTitle.Contains(query.ProductInfoDetailTitle))
.WhereIF(!string.IsNullOrWhiteSpace(query.ProductInfoDetailDesc), item => item.ProductInfoDetailDesc.Contains(query.ProductInfoDetailDesc))
.WhereIF(query.ProductInfoDetailOrder.HasValue, item => item.ProductInfoDetailOrder == query.ProductInfoDetailOrder)
.WhereIF(!string.IsNullOrWhiteSpace(query.ProductInfoDetailPic), item => item.ProductInfoDetailPic == query.ProductInfoDetailPic)
.WhereIF(!string.IsNullOrWhiteSpace(query.Ancestors), item => item.Ancestors == query.Ancestors)
.ToListAsync();
}
/// <summary>
/// 新增产品明细信息。
/// <para>
/// 【树形结构处理】
/// 1. 如果没有指定父ID或父ID为0设置为顶级节点ParentId=0, Ancestors="0"
/// 2. 如果指定了父ID查询父节点的祖先路径拼接成新的祖先路径
///
/// 示例:
/// 父节点Ancestors="0,1",当前 ParentId=2
/// 新节点Ancestors="0,1,2"
/// </para>
/// <para>
/// 【空字符串规范化】
/// 将标题、描述、祖先路径的空字符串转为 null与 XML 方案保持一致。
/// </para>
/// </summary>
/// <param name="input">产品明细数据</param>
/// <returns>影响行数</returns>
public async Task<int> InsertHwProductInfoDetail(HwProductInfoDetail input)
{
// 【树形结构处理】
// 如果没有父ID或父ID为0设置为顶级节点
if (!input.ParentId.HasValue || input.ParentId == 0)
{
input.ParentId = 0;
input.Ancestors = "0";
}
else
{
// 查询父节点的祖先路径,拼接成新的祖先路径
HwProductInfoDetail info = await SelectHwProductInfoDetailByProductInfoDetailId(input.ParentId.Value);
input.Ancestors = $"{info?.Ancestors},{input.ParentId}";
}
// 【数据规范化】
// 将空字符串转为 null与 XML 方案保持一致
input.ProductInfoDetailTitle = NormalizeEmptyToNull(input.ProductInfoDetailTitle);
input.ProductInfoDetailDesc = NormalizeEmptyToNull(input.ProductInfoDetailDesc);
input.Ancestors = NormalizeEmptyToNull(input.Ancestors);
// 【审计字段】
input.CreateTime = HwPortalContextHelper.Now();
input.CreateBy = HwPortalContextHelper.CurrentUserName();
// 回滚到 XML 方案时可直接恢复:
// long identity = await _executor.InsertReturnIdentityAsync(Mapper, "insertHwProductInfoDetail", input);
HwProductInfoDetail entity = await _db.Insertable(input).ExecuteReturnEntityAsync();
input.ProductInfoDetailId = entity.ProductInfoDetailId;
return input.ProductInfoDetailId > 0 ? 1 : 0;
}
/// <summary>
/// 更新产品明细信息。
/// <para>
/// 【字段级更新策略】
/// 1. 先查询现有记录
/// 2. 对非空字段进行更新
/// 3. 空字符串也视为有效值
/// </para>
/// </summary>
/// <param name="input">更新的数据</param>
/// <returns>影响行数</returns>
public async Task<int> UpdateHwProductInfoDetail(HwProductInfoDetail input)
{
// 【审计字段】
input.UpdateTime = HwPortalContextHelper.Now();
// 回滚到 XML 方案时可直接恢复:
// return await _executor.ExecuteAsync(Mapper, "updateHwProductInfoDetail", input);
HwProductInfoDetail current = await SelectHwProductInfoDetailByProductInfoDetailId(input.ProductInfoDetailId ?? 0);
if (current == null)
{
return 0;
}
// 【父ID】
if (input.ParentId.HasValue)
{
current.ParentId = input.ParentId;
}
// 【产品ID】
if (input.ProductInfoId.HasValue)
{
current.ProductInfoId = input.ProductInfoId;
}
// 【配置模式】
if (input.ConfigModal != null)
{
current.ConfigModal = input.ConfigModal;
}
// 【标题】
if (!string.IsNullOrWhiteSpace(input.ProductInfoDetailTitle))
{
current.ProductInfoDetailTitle = input.ProductInfoDetailTitle;
}
// 【描述】
if (!string.IsNullOrWhiteSpace(input.ProductInfoDetailDesc))
{
current.ProductInfoDetailDesc = input.ProductInfoDetailDesc;
}
// 【排序号】
if (input.ProductInfoDetailOrder.HasValue)
{
current.ProductInfoDetailOrder = input.ProductInfoDetailOrder;
}
// 【图片】
if (input.ProductInfoDetailPic != null)
{
current.ProductInfoDetailPic = input.ProductInfoDetailPic;
}
// 【祖先路径】
if (!string.IsNullOrWhiteSpace(input.Ancestors))
{
current.Ancestors = input.Ancestors;
}
// 【审计字段】
if (input.CreateTime.HasValue)
{
current.CreateTime = input.CreateTime;
}
if (input.CreateBy != null)
{
current.CreateBy = input.CreateBy;
}
current.UpdateTime = input.UpdateTime;
if (input.UpdateBy != null)
{
current.UpdateBy = input.UpdateBy;
}
return await _db.Updateable(current).ExecuteCommandAsync();
}
/// <summary>
/// 批量删除产品明细信息。
/// </summary>
/// <param name="productInfoDetailIds">明细ID数组</param>
/// <returns>影响行数</returns>
public async Task<int> DeleteHwProductInfoDetailByProductInfoDetailIds(long[] productInfoDetailIds)
{
// 回滚到 XML 方案时可直接恢复:
// return await _executor.ExecuteAsync(Mapper, "deleteHwProductInfoDetailByProductInfoDetailIds", new { array = productInfoDetailIds });
return await _db.Deleteable<HwProductInfoDetail>()
.In(productInfoDetailIds)
.ExecuteCommandAsync();
}
/// <summary>
/// 将空字符串规范化转为 null。
/// <para>
/// 【辅助方法】
/// 用于保持与 XML 方案的数据一致性。
/// 原 XML 中 &lt;if&gt; 标签会跳过空字符串,
/// 这里主动将空字符串转为 null达到同样效果。
/// </para>
/// </summary>
/// <param name="value">输入字符串</param>
/// <returns>null 或原值</returns>
private static string NormalizeEmptyToNull(string value)
{
return string.IsNullOrWhiteSpace(value) ? null : value;
}
}