文件内容 EventQuickActionHandler.cs 9 KB 8923 字符
using Microsoft.Extensions.Logging;
using PasteApeart.Application.Contracts;
using PasteApeart.Handler.Extensions;
using PasteApeart.Helper;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;

namespace PasteApeart.Handler.common
{
    /// <summary>
    /// EventHanlder直接执行的帮助类
    /// </summary>
    public class EventQuickActionHandler : IEventQuickActionHandler
    {
        private readonly ILogger<EventQuickActionHandler> _logger;
        private readonly IEventActionHandler _actionHandler;
        private readonly Type[] _dtoTypeArray;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="actionHandler"></param>
        /// <param name="dtoTypeArray">EventModel的模型集合</param>
        public EventQuickActionHandler(ILogger<EventQuickActionHandler> logger, IEventActionHandler actionHandler, Type[] dtoTypeArray = null)
        {
            _logger = logger;
            _actionHandler = actionHandler;
            if (dtoTypeArray != null)
            {
                _dtoTypeArray = dtoTypeArray;
            }
        }

        /// <summary>
        /// 读取AddDto的数据模型
        /// </summary>
        /// <returns></returns>
        public VoloModelInfo ReadAddModel(string model_name)
        {
            if (string.IsNullOrEmpty(model_name))
            {
                throw new PasteArgsException(nameof(model_name));// PasteCodeException("");
            }
            if (_dtoTypeArray?.Any() != true)
            {
                throw new PasteArgsException("构造函数中需要先引入EventModel集合");
            }
            //AbsAutoFundEventModel AbsEventModel
            //var typeArray = typeof(UserInfoDto).Assembly.GetTypes();
            var find = _dtoTypeArray.FirstOrDefault(x => x.Name == model_name);
            if (find == null)
            {
                throw new PasteCodeException($"没有找到这样的对象{model_name}");
            }
            if (!typeof(IEventModel).IsAssignableFrom(find))
            {
                throw new PasteCodeException("对象必须继承于IEventModel");
            }

            var _model = BuilderHelper.DynamicReadTypeProperty(find, false);

            foreach (var item in _model.Properties)
            {
                if (string.Equals(item.Name, "eventName", StringComparison.OrdinalIgnoreCase))
                {
                    item.Value = model_name;
                }

                if (item.DataType == "String")
                {
                    if (item.Attributes == null)
                    {
                        item.Attributes = new List<VoloModelAttribute> { new VoloModelAttribute { Name = "text" } };
                    }
                    else
                    {
                        if (!item.Attributes.Any(x => x.Name == "maxlength"))
                        {
                            item.Attributes.Add(new VoloModelAttribute { Name = "text" });
                        }
                    }
                }
            }
            return _model;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PastePagedResult<QuickHandlerPropertyInfo>> PageAsync(InputSearchBase input)
        {
            var result = new PastePagedResult<QuickHandlerPropertyInfo>();

            //var typeArray = typeof(UserInfoDto).Assembly.GetTypes();

            if (_dtoTypeArray?.Any() != true)
            {
                throw new PasteArgsException("构造函数中需要先引入EventModel集合");
            }

            // 获取所有继承于 IEventModel 的非抽象类
            var eventModelTypes = _dtoTypeArray
                .Where(t => typeof(IEventModel).IsAssignableFrom(t)
                            && t.IsClass
                            && !t.IsAbstract)
                .PasteWhereIf(!string.IsNullOrEmpty(input.word), x => x.Name.Contains(input.word))
                .ToList();

            if (eventModelTypes?.Any() != true)
            {
                return null;
            }
            result.TotalCount = eventModelTypes.Count;
            var datas = eventModelTypes.OrderBy(x => x.Name).Skip(input.size * (input.page - 1)).Take(input.size).ToList();

            var modelList = new List<QuickHandlerPropertyInfo>();

            foreach (var type in datas)
            {
                // 获取类上的 XML 注释
                var xmlComment = GetXmlComment(type);

                var code = type.Name;                    // 类名作为 Code
                var name = ExtractName(xmlComment);      // summary 中空格之前的部分
                var desc = ExtractDesc(xmlComment);      // summary 中空格之后的部分

                // 字段个数(这里按属性数量统计,如需包含字段可自行调整)
                var fieldCount = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Length;
                // 若需要同时统计字段:

                modelList.Add(new QuickHandlerPropertyInfo
                {
                    Code = code,
                    Name = name,
                    Desc = desc,
                    FieldCount = fieldCount,
                    //Type = type
                });
            }
            result.Items = modelList; // 视 VoloModelInfo 的实际结构赋值
            return result;
        }

        /// <summary>
        /// 读取类型上的 XML Summary 注释
        /// </summary>
        private string GetXmlComment(Type type)
        {
            try
            {
                var member = type.Assembly.GetType(type.FullName ?? type.Name);
                if (member == null)
                {
                    _logger.LogWarning($"没有找到这样的类型:{type.FullName} {type.Name}");
                    return string.Empty;
                }

                // 使用反射读取 XML 文档(需要确保 XML 文件已生成并加载)
                var xmlDoc = GetXmlDocument(type.Assembly);
                if (xmlDoc == null)
                {
                    _logger.LogWarning($"没有读取到文档:{type.Assembly.GetName().Name}.xml");
                    return string.Empty;
                }

                var memberName = $"T:{type.FullName}";
                var node = xmlDoc.SelectSingleNode($"/doc/members/member[@name='{memberName}']/summary");
                if (node == null)
                {
                    _logger.LogWarning($"没有找到这个节点 {memberName}/summary");
                }
                return node?.InnerText?.Trim() ?? string.Empty;
            }
            catch (Exception exl)
            {
                _logger.LogException(exl);
                return string.Empty;
            }
        }

        /// <summary>
        /// 缓存复用
        /// </summary>
        private static readonly Dictionary<string, XmlDocument> _xmlDocCache = new();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        private XmlDocument GetXmlDocument(Assembly assembly)
        {
            var location = assembly.Location;
            if (_xmlDocCache.TryGetValue(location, out var cached))
                return cached;

            try
            {

                var xmlPath = Path.ChangeExtension(location, ".xml");
                if (!System.IO.File.Exists(xmlPath))
                {
                    _logger.LogWarning($"找不到文件 {xmlPath}");
                    return null;
                }

                var doc = new XmlDocument();
                doc.Load(xmlPath);
                _xmlDocCache[location] = doc;
                return doc;
            }
            catch (Exception exl)
            {
                _logger.LogException(exl);
                return null;
            }
        }

        /// <summary>
        /// 提取 summary 中第一个空格之前的内容作为 Name
        /// </summary>
        private string ExtractName(string comment)
        {
            if (string.IsNullOrWhiteSpace(comment)) return string.Empty;

            // 去掉换行、多余空白
            comment = Regex.Replace(comment, @"\s+", " ").Trim();
            var index = comment.IndexOf(' ');
            return index > 0 ? comment.Substring(0, index) : comment;
        }

        /// <summary>
        /// 提取 summary 中空格之后的内容作为 Desc
        /// </summary>
        private string ExtractDesc(string comment)
        {
            if (string.IsNullOrWhiteSpace(comment)) return string.Empty;

            comment = Regex.Replace(comment, @"\s+", " ").Trim();
            var index = comment.IndexOf(' ');
            return index > 0 && index + 1 < comment.Length
                ? comment.Substring(index + 1).Trim()
                : string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="postBodyStr"></param>
        /// <returns></returns>
        public async Task<string> CreateItemAsync(string postBodyStr)
        {
            await _actionHandler.ActionMessageAsync(postBodyStr);
            return "执行完成";
        }
    }
}
​ ​