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.

348 lines
14 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.

// ============================================================================
// 【文件说明】HwPortalConfigService.cs - 门户配置服务类
// ============================================================================
// 这个服务类负责处理门户配置的业务逻辑,包括:
// - 门户配置的 CRUD 操作
// - 关联查询(配置 + 配置类型)
// - 空字符串规范化处理
//
// 【业务背景】
// 门户配置模块用于管理网站首页的各种配置项,如轮播图、推荐内容等。
// 支持关联查询配置类型信息。
//
// 【与 Java Spring Boot 的对比】
// Java Spring Boot:
// @Service
// public class HwPortalConfigServiceImpl implements HwPortalConfigService { ... }
//
// ASP.NET Core + Furion:
// public class HwPortalConfigService : ITransient { ... }
// ============================================================================
namespace Admin.NET.Plugin.HwPortal;
/// <summary>
/// 门户配置服务类。
/// <para>
/// 【服务职责】
/// 1. 管理门户配置的增删改查
/// 2. 支持关联查询配置类型信息
/// 3. 处理空字符串规范化
/// </para>
/// <para>
/// 【特殊类型处理】
/// 当 PortalConfigType 为 "2" 时,使用 JOIN 查询关联 HwPortalConfigType 表,
/// 返回包含配置类型名称等附加信息的结果。
/// </para>
/// </summary>
public class HwPortalConfigService : ITransient
{
/// <summary>
/// MyBatis 映射器名称(保留用于回滚)。
/// </summary>
private const string Mapper = "HwPortalConfigMapper";
/// <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 HwPortalConfigService(HwPortalMyBatisExecutor executor, ISqlSugarClient db)
{
_executor = executor;
_db = db;
}
/// <summary>
/// 根据配置ID查询门户配置。
/// </summary>
/// <param name="portalConfigId">配置ID</param>
/// <returns>门户配置实体</returns>
public async Task<HwPortalConfig> SelectHwPortalConfigByPortalConfigId(long portalConfigId)
{
// 回滚到 XML 方案时可直接恢复:
// return await _executor.QuerySingleAsync<HwPortalConfig>(Mapper, "selectHwPortalConfigByPortalConfigId", new { portalConfigId });
return await _db.Queryable<HwPortalConfig>()
.Where(item => item.PortalConfigId == portalConfigId)
.FirstAsync();
}
/// <summary>
/// 查询门户配置列表。
/// <para>
/// 【特殊类型处理】
/// 当 PortalConfigType 为 "2"HwPortalConstants.PortalConfigTypeTwo
/// 使用 BuildPortalConfigJoinQuery 方法进行 JOIN 查询,
/// 返回包含配置类型名称等附加信息的结果。
/// </para>
/// <para>
/// 【动态查询条件】
/// 支持按配置类型、类型ID、标题、排序号、描述、按钮名、路由地址、图片等条件筛选。
/// </para>
/// </summary>
/// <param name="input">查询条件</param>
/// <returns>门户配置列表</returns>
public async Task<List<HwPortalConfig>> SelectHwPortalConfigList(HwPortalConfig input)
{
HwPortalConfig query = input ?? new HwPortalConfig();
// 【特殊类型处理】
// 当配置类型为 "2" 时,使用 JOIN 查询关联配置类型表
if (string.Equals(HwPortalConstants.PortalConfigTypeTwo, query.PortalConfigType, StringComparison.Ordinal))
{
// 回滚到 XML 方案时可直接恢复:
// return await _executor.QueryListAsync<HwPortalConfig>(Mapper, "selectHwPortalConfigList2", query);
return await BuildPortalConfigJoinQuery(query).ToListAsync();
}
// 【普通查询】
// 回滚到 XML 方案时可直接恢复:
// return await _executor.QueryListAsync<HwPortalConfig>(Mapper, "selectHwPortalConfigList", query);
return await _db.Queryable<HwPortalConfig>()
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigType), item => item.PortalConfigType == query.PortalConfigType)
.WhereIF(query.PortalConfigTypeId.HasValue, item => item.PortalConfigTypeId == query.PortalConfigTypeId)
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigTitle), item => item.PortalConfigTitle.Contains(query.PortalConfigTitle))
.WhereIF(query.PortalConfigOrder.HasValue, item => item.PortalConfigOrder == query.PortalConfigOrder)
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigDesc), item => item.PortalConfigDesc == query.PortalConfigDesc)
.WhereIF(!string.IsNullOrWhiteSpace(query.ButtonName), item => item.ButtonName.Contains(query.ButtonName))
.WhereIF(!string.IsNullOrWhiteSpace(query.RouterAddress), item => item.RouterAddress == query.RouterAddress)
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigPic), item => item.PortalConfigPic == query.PortalConfigPic)
.ToListAsync();
}
/// <summary>
/// 新增门户配置。
/// <para>
/// 【空字符串规范化】
/// Why这里只把原 XML 会忽略的空串字段转成 null
/// 其它字段继续保留调用方原值,避免语义漂移。
/// </para>
/// </summary>
/// <param name="input">门户配置数据</param>
/// <returns>影响行数</returns>
public async Task<int> InsertHwPortalConfig(HwPortalConfig input)
{
// 【数据规范化】
// 将空字符串转为 null与 XML 方案保持一致
input.PortalConfigType = NormalizeEmptyToNull(input.PortalConfigType);
input.PortalConfigTitle = NormalizeEmptyToNull(input.PortalConfigTitle);
input.PortalConfigPic = NormalizeEmptyToNull(input.PortalConfigPic);
// 【审计字段】
input.CreateTime = HwPortalContextHelper.Now();
// 回滚到 XML 方案时可直接恢复:
// long identity = await _executor.InsertReturnIdentityAsync(Mapper, "insertHwPortalConfig", input);
HwPortalConfig entity = await _db.Insertable(input).ExecuteReturnEntityAsync();
input.PortalConfigId = entity.PortalConfigId;
return input.PortalConfigId > 0 ? 1 : 0;
}
/// <summary>
/// 更新门户配置。
/// <para>
/// 【字段级更新策略】
/// 只更新输入对象中不为 null 或不为空的字段。
/// </para>
/// </summary>
/// <param name="input">更新的数据</param>
/// <returns>影响行数</returns>
public async Task<int> UpdateHwPortalConfig(HwPortalConfig input)
{
// 【审计字段】
input.UpdateTime = HwPortalContextHelper.Now();
// 回滚到 XML 方案时可直接恢复:
// return await _executor.ExecuteAsync(Mapper, "updateHwPortalConfig", input);
HwPortalConfig current = await SelectHwPortalConfigByPortalConfigId(input.PortalConfigId ?? 0);
if (current == null)
{
return 0;
}
// 【配置类型】
if (!string.IsNullOrWhiteSpace(input.PortalConfigType))
{
current.PortalConfigType = input.PortalConfigType;
}
// 【类型ID】
if (input.PortalConfigTypeId.HasValue)
{
current.PortalConfigTypeId = input.PortalConfigTypeId;
}
// 【标题】
if (!string.IsNullOrWhiteSpace(input.PortalConfigTitle))
{
current.PortalConfigTitle = input.PortalConfigTitle;
}
// 【排序号】
if (input.PortalConfigOrder.HasValue)
{
current.PortalConfigOrder = input.PortalConfigOrder;
}
// 【描述】
if (input.PortalConfigDesc != null)
{
current.PortalConfigDesc = input.PortalConfigDesc;
}
// 【按钮名】
if (input.ButtonName != null)
{
current.ButtonName = input.ButtonName;
}
// 【路由地址】
if (input.RouterAddress != null)
{
current.RouterAddress = input.RouterAddress;
}
// 【图片】
if (!string.IsNullOrWhiteSpace(input.PortalConfigPic))
{
current.PortalConfigPic = input.PortalConfigPic;
}
// 【审计字段】
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="portalConfigIds">配置ID数组</param>
/// <returns>影响行数</returns>
public async Task<int> DeleteHwPortalConfigByPortalConfigIds(long[] portalConfigIds)
{
// 回滚到 XML 方案时可直接恢复:
// return await _executor.ExecuteAsync(Mapper, "deleteHwPortalConfigByPortalConfigIds", new { array = portalConfigIds });
return await _db.Deleteable<HwPortalConfig>()
.In(portalConfigIds)
.ExecuteCommandAsync();
}
/// <summary>
/// 查询门户配置关联列表JOIN查询
/// <para>
/// 【关联查询】
/// 使用 BuildPortalConfigJoinQuery 方法进行 JOIN 查询,
/// 返回包含配置类型信息的完整结果。
/// </para>
/// </summary>
/// <param name="input">查询条件</param>
/// <returns>门户配置列表(含类型信息)</returns>
public async Task<List<HwPortalConfig>> SelectHwPortalConfigJoinList(HwPortalConfig input)
{
HwPortalConfig query = input ?? new HwPortalConfig();
// 回滚到 XML 方案时可直接恢复:
// return await _executor.QueryListAsync<HwPortalConfig>(Mapper, "selectHwPortalConfigJoinList", query);
return await BuildPortalConfigJoinQuery(query).ToListAsync();
}
/// <summary>
/// 构建门户配置 JOIN 查询。
/// <para>
/// 【SqlSugar JOIN 查询】
/// 使用 SqlSugar 的 Queryable 进行左连接Left Join查询
/// 关联 HwPortalConfigType 表获取配置类型信息。
/// </para>
/// <para>
/// 【字段投影】
/// Why这里统一把关联侧字段一起投影出来避免 provider 对条件投影翻译不稳定。
/// 对不需要这些字段的调用方来说,多出冗余属性不会改变行为,但能明显降低切换风险。
/// </para>
/// </summary>
/// <param name="query">查询条件</param>
/// <returns>JOIN 查询对象</returns>
private ISugarQueryable<HwPortalConfig> BuildPortalConfigJoinQuery(HwPortalConfig query)
{
return _db.Queryable<HwPortalConfig, HwPortalConfigType>((config, configType) =>
new JoinQueryInfos(JoinType.Left, config.PortalConfigTypeId == configType.ConfigTypeId))
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigType), (config, _) => config.PortalConfigType == query.PortalConfigType)
.WhereIF(query.PortalConfigTypeId.HasValue, (config, _) => config.PortalConfigTypeId == query.PortalConfigTypeId)
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigTitle), (config, _) => config.PortalConfigTitle.Contains(query.PortalConfigTitle))
.WhereIF(query.PortalConfigOrder.HasValue, (config, _) => config.PortalConfigOrder == query.PortalConfigOrder)
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigDesc), (config, _) => config.PortalConfigDesc == query.PortalConfigDesc)
.WhereIF(!string.IsNullOrWhiteSpace(query.ButtonName), (config, _) => config.ButtonName.Contains(query.ButtonName))
.WhereIF(!string.IsNullOrWhiteSpace(query.RouterAddress), (config, _) => config.RouterAddress == query.RouterAddress)
.WhereIF(!string.IsNullOrWhiteSpace(query.PortalConfigPic), (config, _) => config.PortalConfigPic == query.PortalConfigPic)
.Select((config, configType) => new HwPortalConfig
{
// 【主表字段】
PortalConfigId = config.PortalConfigId,
PortalConfigType = config.PortalConfigType,
PortalConfigTypeId = config.PortalConfigTypeId,
PortalConfigTitle = config.PortalConfigTitle,
PortalConfigOrder = config.PortalConfigOrder,
PortalConfigDesc = config.PortalConfigDesc,
ButtonName = config.ButtonName,
RouterAddress = config.RouterAddress,
PortalConfigPic = config.PortalConfigPic,
CreateTime = config.CreateTime,
CreateBy = config.CreateBy,
UpdateTime = config.UpdateTime,
UpdateBy = config.UpdateBy,
// 【关联表字段】
ConfigTypeName = configType.ConfigTypeName,
// 【冗余字段】
// Why这里统一把关联侧字段一起投影出来避免 provider 对条件投影翻译不稳定。
// 对不需要这些字段的调用方来说,多出冗余属性不会改变行为,但能明显降低切换风险。
HomeConfigTypePic = configType.HomeConfigTypePic,
HomeConfigTypeIcon = configType.ConfigTypeIcon,
HomeConfigTypeName = configType.HomeConfigTypeName,
HomeConfigTypeClassfication = configType.ConfigTypeClassfication,
ParentId = configType.ParentId,
Ancestors = configType.Ancestors
});
}
/// <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;
}
}