From c914975bffe90f808a05dba2c53d4a750e8403c0 Mon Sep 17 00:00:00 2001
From: sunpengfei <i@angelzzz.com>
Date: 星期三, 06 八月 2025 18:17:08 +0800
Subject: [PATCH] feat:企业开发

---
 FlexJobApi.Core/Utils/DbUtils/DbUtils.cs |  273 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 266 insertions(+), 7 deletions(-)

diff --git a/FlexJobApi.Core/Utils/DbUtils/DbUtils.cs b/FlexJobApi.Core/Utils/DbUtils/DbUtils.cs
index ecaf344..e37e10c 100644
--- a/FlexJobApi.Core/Utils/DbUtils/DbUtils.cs
+++ b/FlexJobApi.Core/Utils/DbUtils/DbUtils.cs
@@ -1,4 +1,5 @@
-锘縰sing Furion;
+锘縰sing Consul.Filtering;
+using Furion;
 using Furion.DatabaseAccessor;
 using Furion.DistributedIDGenerator;
 using Furion.FriendlyException;
@@ -16,6 +17,7 @@
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using System.Timers;
 
 namespace FlexJobApi.Core
 {
@@ -25,6 +27,253 @@
     public static class DbUtils
     {
         /// <summary>
+        /// 鑾峰彇鏍戝舰鏁版嵁璺緞
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <param name="parentId"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task<string> GetTreeDataPath<TEntity>(
+             Guid? parentId,
+            CancellationToken cancellationToken = default)
+            where TEntity : CommonEntity, ITreeData<TEntity>, new()
+        {
+            var rep = Db.GetRepository<TEntity>();
+            if (parentId.HasValue)
+            {
+                var parent = await rep.AsQueryable().AsNoTracking()
+                    .Where(it => it.Id == parentId)
+                    .Select(it => new
+                    {
+                        it.Path,
+                        it.Code
+                    })
+                    .FirstOrDefaultAsync(cancellationToken);
+                var summary = typeof(TEntity).GetSummary();
+                if (parent == null) throw Oops.Oh(EnumErrorCodeType.s404, $"涓婄骇{summary}");
+                return $"{parent.Path}{parent.Code}/";
+            }
+            else
+            {
+                return "/";
+            }
+        }
+
+        /// <summary>
+        /// 鏇存柊鏍戝舰鏁版嵁涓嬬骇璺緞
+        /// </summary>
+        /// <param name="oldPath"></param>
+        /// <param name="newPath"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task UpdateTreeDataChildrenPath<TEntity>(
+            string oldPath,
+            string newPath,
+            CancellationToken cancellationToken)
+            where TEntity : CommonEntity, ITreeData<TEntity>, new()
+        {
+            var rep = Db.GetRepository<TEntity>();
+            var models = await rep.AsQueryable()
+                .Where(it => it.Path.StartsWith(oldPath))
+                .ToListAsync(cancellationToken);
+            if (models.IsNotNull())
+            {
+                foreach (var model in models)
+                {
+                    model.Path = model.Path.Replace(oldPath, newPath);
+                }
+                await rep.UpdateAsync(models);
+            }
+        }
+
+        /// <summary>
+        /// 鏌ヨ閫夋嫨鍣ㄦ暟鎹�
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <typeparam name="TValue"></typeparam>
+        /// <typeparam name="TData"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="getValue"></param>
+        /// <param name="getLabel"></param>
+        /// <param name="query"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task<List<SelectQueryResultOption<TValue, TData>>> GetSelect<TEntity, TValue, TData>(
+            this SelectQuery<TValue, TData> request,
+            Func<TData, TValue> getValue,
+            Func<TData, string> getLabel,
+            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
+            CancellationToken cancellationToken = default)
+            where TEntity : CommonEntity, new()
+        {
+            var rep = Db.GetRepository<TEntity>();
+            var q = rep.AsQueryable().AsNoTracking();
+            if (query != null) q = query(q);
+            else q = q.OrderBy(it => it.Sort).ThenBy(it => it.CreatedTime);
+            var models = await q
+                .ProjectToType<TData>()
+                .ToListAsync(cancellationToken);
+            var options = new List<SelectQueryResultOption<TValue, TData>>();
+            foreach (var model in models)
+            {
+                var option = new SelectQueryResultOption<TValue, TData>();
+                option.Data = model;
+                option.Value = getValue(model);
+                option.Label = getLabel(model);
+                options.Add(option);
+            }
+            return options;
+        }
+
+        /// <summary>
+        /// 鏌ヨ鍒嗛〉鍒楄〃鏁版嵁
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <typeparam name="TItem"></typeparam>
+        /// <param name="page"></param>
+        /// <param name="query"></param>
+        /// <param name="selector"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task<PagedListQueryResult<TItem>> GetPagedListAsync<TEntity, TItem>(
+            this PagedListQueryPageModel page,
+            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
+            Expression<Func<TEntity, TItem>> selector = null,
+            CancellationToken cancellationToken = default)
+            where TEntity : CommonEntity, new()
+            where TItem : class, new()
+        {
+            var rep = Db.GetRepository<TEntity>();
+            var q = rep.AsQueryable().AsNoTracking();
+            if (query != null) q = query(q);
+            else q = q.OrderBy(it => it.Sort).ThenBy(it => it.CreatedTime);
+            q = q.OrderBy(page.OrderInput);
+            var s = selector == null
+                ? q.ProjectToType<TItem>()
+                : q.Select(selector);
+            var pagedList = await s.ToPagedListAsync(page.Page, page.Rows, cancellationToken);
+            var result = new PagedListQueryResult<TItem>();
+            result.PageModel = page.Adapt<PagedListQueryResultPageModel>();
+            result.PageModel.TotalCount = pagedList.TotalCount;
+            result.PageModel.TotalPage = pagedList.TotalPages;
+            result.Data = pagedList.Items.ToList();
+            return result;
+        }
+
+        /// <summary>
+        /// 鏌ヨ鍒嗛〉鍒楄〃鏁版嵁
+        /// </summary>
+        /// <typeparam name="TItem"></typeparam>
+        /// <param name="page"></param>
+        /// <param name="q"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task<PagedListQueryResult<TItem>> GetPagedListAsync<TItem>(
+            this PagedListQueryPageModel page,
+            IQueryable<TItem> q,
+            CancellationToken cancellationToken = default)
+            where TItem : class, new()
+        {
+            q = q.OrderBy(page.OrderInput);
+            var pagedList = await q.ToPagedListAsync(page.Page, page.Rows, cancellationToken);
+            var result = new PagedListQueryResult<TItem>();
+            result.PageModel = page.Adapt<PagedListQueryResultPageModel>();
+            result.PageModel.TotalCount = pagedList.TotalCount;
+            result.PageModel.TotalPage = pagedList.TotalPages;
+            result.Data = pagedList.Items.ToList();
+            return result;
+        }
+
+        /// <summary>
+        /// 鎺掑簭
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="q"></param>
+        /// <param name="orders"></param>
+        /// <returns></returns>
+        public static IQueryable<T> OrderBy<T>(
+            this IQueryable<T> q,
+            List<PagedListQueryPageModelOrderInput> orders)
+        {
+            if (orders.IsNull()) return q;
+
+            var entityType = typeof(T);
+            int index = 0;
+
+            var props = entityType.GetProperties();
+            foreach (var order in orders)
+            {
+                if (string.IsNullOrEmpty(order.Property)) continue;
+
+                // 鑾峰彇鎺掑簭瀛楁鐨勫睘鎬т俊鎭�
+                var propertyInfo = props.FirstOrDefault(it => it.Name.Equals(order.Property, StringComparison.OrdinalIgnoreCase));
+                if (propertyInfo == null) throw Oops.Oh(EnumErrorCodeType.s404, $"璇ユ帓搴忓瓧娈祘order.Property}");
+
+                // 鍒涘缓琛ㄨ揪寮忔爲
+                var parameter = Expression.Parameter(entityType, "x");
+                var propertyAccess = Expression.Property(parameter, propertyInfo);
+                var lambda = Expression.Lambda(propertyAccess, parameter);
+
+                string methodName;
+                if (index == 0)
+                {
+                    // 棣栨鎺掑簭
+                    methodName = order.Order == EnumPagedListOrder.Asc
+                        ? "OrderBy"
+                        : "OrderByDescending";
+                }
+                else
+                {
+                    // 浜屾鍙婁互鍚庢帓搴�
+                    methodName = order.Order == EnumPagedListOrder.Asc
+                        ? "ThenBy"
+                        : "ThenByDescending";
+                }
+
+                // 璋冪敤鐩稿簲鐨勬帓搴忔柟娉�
+                var resultExpression = Expression.Call(
+                    typeof(Queryable),
+                    methodName,
+                    [entityType, propertyInfo.PropertyType],
+                    q.Expression,
+                    Expression.Quote(lambda)
+                );
+
+                q = q.Provider.CreateQuery<T>(resultExpression);
+                index++;
+            }
+
+            return q;
+        }
+
+        /// <summary>
+        /// 璁剧疆鏄惁绂佺敤
+        /// </summary>
+        /// <typeparam name="TEntity"></typeparam>
+        /// <param name="request"></param>
+        /// <param name="query"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task<int> SetIsDisabled<TEntity>(
+            this SetIsDisabledCommand request,
+            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
+            CancellationToken cancellationToken = default)
+            where TEntity : CommonEntity, IIsDisabled, new()
+        {
+            var rep = Db.GetRepository<TEntity>();
+            var q = rep.AsQueryable();
+            if (query != null) q = query(q);
+            var entities = await q
+                .Where(it => request.Ids.Contains(it.Id) && it.IsDisabled != request.IsDisabled)
+                .ToListAsync();
+            foreach (var entity in entities)
+            {
+                entity.IsDisabled = request.IsDisabled;
+            }
+            return entities.Count;
+        }
+
+        /// <summary>
         /// 鍒犻櫎鏁版嵁
         /// </summary>
         /// <typeparam name="TEntity"></typeparam>
@@ -32,7 +281,10 @@
         /// <param name="query"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public static async Task<int> DeleteData<TEntity>(this DeleteDataCommand request, Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null, CancellationToken cancellationToken = default)
+        public static async Task<int> DeleteData<TEntity>(
+            this DeleteDataCommand request, Func<IQueryable<TEntity>,
+            IQueryable<TEntity>> query = null,
+            CancellationToken cancellationToken = default)
             where TEntity : CommonEntity, new()
         {
             var rep = Db.GetRepository<TEntity>();
@@ -53,29 +305,36 @@
         /// <typeparam name="TRequest"></typeparam>
         /// <param name="request"></param>
         /// <param name="checkExist"></param>
+        /// <param name="update"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public static async Task<Guid> SaveData<TEntity, TRequest>(this TRequest request, Func<IQueryable<TEntity>, TEntity, TRequest, bool> checkExist = null, CancellationToken cancellationToken = default)
+        public static async Task<Guid> SaveData<TEntity, TRequest>(
+            this TRequest request,
+            Expression<Func<TEntity, bool>> checkExist = null,
+            Action<TEntity> update = null,
+            CancellationToken cancellationToken = default)
             where TEntity : CommonEntity, new()
             where TRequest : SaveDataCommand, new()
         {
             var xmlDoc = await XmlDocUtils.GetXmlDocAsync();
             var summary = await typeof(TEntity).GetSummary(xmlDoc);
             var rep = Db.GetRepository<TEntity>();
+            if (checkExist != null && await rep.AsQueryable().AsNoTracking().AnyAsync(checkExist))
+                throw Oops.Oh(EnumErrorCodeType.s405, $"璇summary ?? "淇℃伅"}");
             if (request.Id.HasValue)
             {
                 var entity = await rep.AsQueryable().FirstOrDefaultAsync(it => it.Id == request.Id, cancellationToken);
                 if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, $"璇summary ?? "淇℃伅"}");
-                if (checkExist != null && checkExist(rep.AsQueryable().AsNoTracking(), entity, request)) throw Oops.Oh(EnumErrorCodeType.s405, $"璇summary ?? "淇℃伅"}");
-                request.Adapt(entity);
+                if (update != null) update(entity);
+                else request.Adapt(entity);
                 await rep.UpdateAsync(entity);
                 return entity.Id;
             }
             else
             {
                 var entity = new TEntity();
-                if (checkExist != null && checkExist(rep.AsQueryable().AsNoTracking(), entity, request)) throw Oops.Oh(EnumErrorCodeType.s405, $"璇summary ?? "淇℃伅"}");
-                request.Adapt(entity);
+                if (update != null) update(entity);
+                else request.Adapt(entity);
                 await rep.InsertAsync(entity);
                 return entity.Id;
             }

--
Gitblit v1.9.1