Lyyyi 1 周之前
父节点
当前提交
4e022dd55f

+ 3 - 2
OASystem/EntitySync/Program.cs

@@ -178,7 +178,8 @@ db.CodeFirst.SetStringDefaultLength(50).BackupTable().InitTables(new Type[]
     //typeof(Grp_VisaProcessSteps_Log),//流程节点 
     //typeof(Grp_ProcessLog),//流程节点 
     //typeof(Grp_FeeEntryAcknowledge),//团组费用录入通知记录表 
-    typeof(Res_OverseaVehicle),//境外用车信息 
-    typeof(Res_OverseaVehicleTypePrice),//境外用车类型价格信息     
+    //typeof(Res_OverseaVehicle),//境外用车信息 
+    //typeof(Res_OverseaVehicleTypePrice),//境外用车类型价格信息   
+    typeof(Pm_CompanyDailyKpi),//财务部绩效考核   
 });
 Console.WriteLine("数据库结构同步完成!");

+ 10 - 36
OASystem/OASystem.Api/Controllers/FinancialController.cs

@@ -3,6 +3,7 @@ using Aspose.Words;
 using EyeSoft.Extensions;
 using EyeSoft.IO;
 using FluentValidation;
+using Humanizer;
 using NPOI.SS.UserModel;
 using NPOI.XSSF.UserModel;
 using OASystem.API.OAMethodLib;
@@ -7175,50 +7176,23 @@ Group by PriceType ", dto.diId);
                 return Ok(jw);
             }
 
-            // 构建搜索条件
-            var searchFields = new List<string>
-            {
-                "TeamName",
-            };
-
-            var searchConfig = new SearchConfig
-            {
-                EnableExactMatch = true,
-                EnablePrefixMatch = true,
-                EnableFuzzySearch = true,
-                EnableCharSearch = true,
-                RequireAllWords = true,
-                RequireAllChars = false,
-                EnableSmartSplitting = true,
-                MinSplitLength = 4,
-                RequireAllWordsForSplit = false
-            };
-
-            // 使用智能混合搜索模式
-            var (searchCondition, searchParameters) = AdvancedSearchHelper.BuildSugarSearchCondition(
-                searchTerm: teamName,
-                searchFields: searchFields,
-                prefix: "search_",
-                searchMode: SearchMode.AutoDetect,
-                combinationMode: CombinationMode.SmartMix,
-                config: searchConfig
-            );
-
             // 主查询
             var query = _sqlSugar.Queryable<Grp_DelegationInfo>()
                 .Where(x => x.IsDel == 0 &&
                         x.VisitDate >= _beginDt &&
                         x.VisitDate <= _endDt);
 
-            // 如果存在搜索条件,添加到查询中
-            if (!string.IsNullOrEmpty(searchCondition))
+            if (!string.IsNullOrEmpty(teamName))
             {
-                query = query.Where(searchCondition, searchParameters.ToArray());
-            }
-            else if (!string.IsNullOrEmpty(teamName))
-            {
-                // 如果搜索条件构建失败但有搜索词,使用简单包含匹配
                 query = query.Where(x => x.TeamName.Contains(teamName));
+                var keywords = teamName.Trim()
+                    .Split(new[] { ' ', ',', ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+                foreach (var keyword in keywords.Where(k => !string.IsNullOrWhiteSpace(k)))
+                {
+                    query = query.Where(x => x.TeamName.Contains(keyword.Trim()));
+                    
+                }
             }
 
             var _groupDatas = query

+ 30 - 27
OASystem/OASystem.Api/Controllers/GroupsController.cs

@@ -6550,36 +6550,40 @@ FROM
                 // 搜索条件
                 if (!string.IsNullOrEmpty(dto.SearchCriteria))
                 {
-                    var searchFields = new List<string>
-                    {
-                        "ssd.Name",
-                        "TeamName",
-                        "ClientName",
-                        "su.CnName"
-                    };
+                    // 将搜索词按空格分割为多个关键字(支持多关键字检索)
+                    var keywords = dto.SearchCriteria.Split(new[] { ' ', ',', ',' }, StringSplitOptions.RemoveEmptyEntries);
 
-                    // 使用更宽松的配置
-                    var config = new SearchConfig
+                    if (keywords.Length > 0)
                     {
-                        EnableSmartSplitting = true,
-                        RequireAllWordsForSplit = false,
-                        MinSplitLength = 4
-                    };
+                        var searchConditions = new List<string>();
 
-                    // 使用智能混合模式
-                    var (searchCondition, searchParams) = AdvancedSearchHelper.BuildEnhancedSearchCondition(
-                        dto.SearchCriteria,
-                        searchFields,
-                        "search_groupFee_",
-                        SearchMode.AutoDetect,
-                        CombinationMode.SmartMix,
-                        config  // 传入配置
-                    );
+                        foreach (var keyword in keywords)
+                        {
+                            if (!string.IsNullOrWhiteSpace(keyword))
+                            {
+                                // 对每个关键字构建多字段检索条件
+                                var keywordConditions = new List<string>
+                                    {
+                                        $"ssd.Name LIKE '%{keyword}%'",
+                                        $"gdi.TeamName LIKE '%{keyword}%'",
+                                        $"gdi.ClientName LIKE '%{keyword}%'",
+                                        $"su.CnName LIKE '%{keyword}%'",
+                                        $"gdi.SalesQuoteNo LIKE '%{keyword}%'",
+                                        $"gdi.TourCode LIKE '%{keyword}%'",
+                                        $"gdi.ClientUnit LIKE '%{keyword}%'",
+                                        $"ssd1.Name LIKE '%{keyword}%'"
+                                    };
+
+                                // 将多个字段条件用 OR 连接
+                                searchConditions.Add($"({string.Join(" OR ", keywordConditions)})");
+                            }
+                        }
 
-                    if (!string.IsNullOrEmpty(searchCondition))
-                    {
-                        sqlWhere += $" AND ({searchCondition})";
-                        parameters.AddRange(searchParams);
+                        // 将多个关键字条件用 AND 连接(实现多关键字AND搜索)
+                        if (searchConditions.Count > 0)
+                        {
+                            sqlWhere += $" AND ({string.Join(" AND ", searchConditions)})";
+                        }
                     }
                 }
 
@@ -6605,7 +6609,6 @@ FROM
 
                 RefAsync<int> total = 0;
                 var _DelegationList = await _sqlSugar.SqlQueryable<DelegationListView>(sql)
-                    .AddParameters(parameters.ToArray())
                     .ToPageListAsync(dto.PageIndex, dto.PageSize, total);
 
                 var _view = new

+ 53 - 6
OASystem/OASystem.Api/Controllers/PersonnelModuleController.cs

@@ -1,5 +1,4 @@
 using Aspose.Cells;
-using Dm.util;
 using FluentValidation;
 using Markdig;
 using Microsoft.AspNetCore.SignalR;
@@ -11,8 +10,6 @@ using OASystem.API.OAMethodLib.QiYeWeChatAPI;
 using OASystem.API.OAMethodLib.QiYeWeChatAPI.AppNotice;
 using OASystem.Domain.Dtos.Groups;
 using OASystem.Domain.Dtos.PersonnelModule;
-using OASystem.Domain.Dtos.Statistics;
-using OASystem.Domain.Entities;
 using OASystem.Domain.Entities.Groups;
 using OASystem.Domain.Entities.PersonnelModule;
 using OASystem.Domain.ViewModels.PersonnelModule;
@@ -20,7 +17,6 @@ using OASystem.Domain.ViewModels.QiYeWeChat;
 using OASystem.Domain.ViewModels.Statistics;
 using OASystem.Infrastructure.Repositories.Groups;
 using OASystem.Infrastructure.Repositories.PersonnelModule;
-using Org.BouncyCastle.Asn1.Tsp;
 using System.Data;
 using System.Diagnostics;
 using System.Globalization;
@@ -53,6 +49,8 @@ namespace OASystem.API.Controllers
         private readonly string url;
         private readonly string path;
 
+        private readonly CompanyDailyKpiRepository _companyDailyKyiRep;
+
         /// <summary>
         /// 初始化
         /// </summary>
@@ -67,6 +65,7 @@ namespace OASystem.API.Controllers
         /// <param name="otherPaymentRep"></param>
         /// <param name="feeAuditRep"></param>
         /// <param name="deepSeekService"></param>
+        /// <param name="companyDailyKyiRep"></param>
         /// <param name="logger"></param>
         public PersonnelModuleController(
             IHubContext<ChatHub, IChatClient> hubContext,
@@ -80,6 +79,7 @@ namespace OASystem.API.Controllers
             DecreasePaymentsRepository otherPaymentRep,
             FeeAuditRepository feeAuditRep,
             IDeepSeekService deepSeekService,
+            CompanyDailyKpiRepository companyDailyKyiRep,
             ILogger<PersonnelModuleController> logger
             )
         {
@@ -104,6 +104,7 @@ namespace OASystem.API.Controllers
             _otherPaymentRep = otherPaymentRep;
             _feeAuditRep = feeAuditRep;
             _deepSeekService = deepSeekService;
+            _companyDailyKyiRep = companyDailyKyiRep;
             _logger = logger;
         }
 
@@ -1087,6 +1088,17 @@ namespace OASystem.API.Controllers
                 whereSql += string.Format(@" And ta.TaskName Like '%{0}%' ", dto.TaskName);
             }
 
+            //人员名称
+            string taskUserWhereSql = string.Empty;
+            if (dto.TaskUserId > 0)
+            {
+                var taskUserInfo = await _sqlSugar.Queryable<Sys_Users>().FirstAsync(x => x.IsDel == 0 && x.Id == dto.TaskUserId);
+                if (taskUserInfo != null)
+                {
+                    taskUserWhereSql = $" AND [Participant] like '%{taskUserInfo.CnName}%'";
+                }
+            }
+
             #endregion
 
             var currUserInfo = await _sqlSugar.Queryable<Sys_Users>().FirstAsync(x => x.Id == dto.UserId);
@@ -1163,8 +1175,7 @@ From
       ta.IsDel = 0 {0}
   ) As temp
 WHERE
-  [CreateUserName] like '%{1}%'
-  OR [Participant] like '%{2}%' ", whereSql, currUserName, currUserName);
+  [CreateUserName] like '%{1}%' {2}", whereSql, currUserName, taskUserWhereSql);
 
             RefAsync<int> total = 0;
             var _view = await _sqlSugar.SqlQueryable<TaskListView>(pageSql)
@@ -5065,5 +5076,41 @@ ORDER BY MonthNumber, CollectionDays";
 
         #endregion
 
+        #region 公司部门日常绩效
+
+
+        /// <summary>
+        /// 绩效数据
+        /// </summary>
+        /// <param name="depName">
+        /// <param name="jobName">
+        /// 模板部门类型 
+        /// 0 全部 1 财务 2 策划 
+        /// </param>
+        /// <returns></returns>
+        [HttpGet]
+        public async Task<IActionResult> KpiInfo(string depName,string jobName)
+        {
+            var info = await _companyDailyKyiRep.KpiTemplateDataAsync(depName, jobName);
+            return Ok(JsonView(info.Item3));
+        }
+
+
+        #region 财务部
+
+        /// <summary>
+        /// 财务部 日常绩效 初始化数据
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet]
+        public async Task<IActionResult> FinanceKpiInit()
+        {
+            return Ok(await _companyDailyKyiRep.FinanceInit());
+        }
+
+        #endregion
+
+        #endregion
+
     }
 }

+ 103 - 101
OASystem/OASystem.Api/Controllers/StatisticsController.cs

@@ -70,40 +70,72 @@ namespace OASystem.API.Controllers
         #region 团组报表
 
         /// <summary>
-        ///  团组报表
-        ///  Items 
+        /// 团组报表
         /// </summary>
-        /// <param name="dto">团组列表请求dto</param>
+        /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("PostGroupStatementItems")]
         [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
         public async Task<IActionResult> PostGroupStatementItems(GroupStatementItemsDto dto)
         {
-            #region  参数验证
+            #region 参数验证
             if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
             if (dto.PageId < 1) return Ok(JsonView(false, "页面Id为空"));
 
-            PageFunAuthViewBase pageFunAuthView = new PageFunAuthViewBase();
-            #region 页面操作权限验证
-            pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
-
+            var pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
             if (pageFunAuthView.CheckAuth == 0) return Ok(JsonView(false, "您没有查看权限"));
             #endregion
 
-            #endregion
-            if (dto.PortType == 1 || dto.PortType == 2 || dto.PortType == 3) // web/Android/IOS
+            if (dto.PortType < 1 || dto.PortType > 3)
+                return Ok(JsonView(false, "端口类型错误"));
+
+            try
             {
-                // 构建基础查询
-                var query = _sqlSugar.Queryable<Grp_DelegationInfo, Sys_SetData, Sys_SetData, Sys_Users, Fin_ProceedsReceived>(
-                        (gdi, ssd, ssd1, su, pr) => new JoinQueryInfos(
-                            JoinType.Left, gdi.TeamDid == ssd.Id,
-                            JoinType.Left, gdi.TeamLevSId == ssd1.Id,
-                            JoinType.Left, gdi.JietuanOperator == su.Id,
-                            JoinType.Left, gdi.Id == pr.Diid
-                        )
-                    )
-                    .Where((gdi, ssd, ssd1, su, pr) => gdi.IsDel == 0)
-                    .Select((gdi, ssd, ssd1, su, pr) => new GroupStatementItemView
+                // 构建基础查询 - 使用正确的SQLSugar链式调用
+                var query = _sqlSugar.Queryable<Grp_DelegationInfo>()
+                    .LeftJoin<Sys_SetData>((gdi, ssd) => gdi.TeamDid == ssd.Id)
+                    .LeftJoin<Sys_SetData>((gdi, ssd, ssd1) => gdi.TeamLevSId == ssd1.Id)
+                    .LeftJoin<Sys_Users>((gdi, ssd, ssd1, su) => gdi.JietuanOperator == su.Id)
+                    .Where((gdi, ssd, ssd1, su) => gdi.IsDel == 0);
+
+                // 状态筛选
+                if (dto.IsSure == 0)
+                {
+                    query = query.Where((gdi, ssd, ssd1, su) => gdi.IsSure == 0);
+                }
+                else if (dto.IsSure == 1)
+                {
+                    query = query.Where((gdi, ssd, ssd1, su) => gdi.IsSure == 1);
+                }
+
+                // 多字段搜索 - 使用正确的表别名
+                if (!string.IsNullOrWhiteSpace(dto.SearchCriteria))
+                {
+                    var keywords = dto.SearchCriteria.Trim()
+                        .Split(new[] { ' ', ',', ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+                    foreach (var keyword in keywords.Where(k => !string.IsNullOrWhiteSpace(k)))
+                    {
+                        var cleanKeyword = keyword.Trim();
+                        query = query.Where((gdi, ssd, ssd1, su) =>
+                            gdi.TeamName.Contains(cleanKeyword) ||
+                            gdi.ClientName.Contains(cleanKeyword) ||
+                            su.CnName.Contains(cleanKeyword) ||
+                            gdi.TourCode.Contains(cleanKeyword) ||
+                            gdi.ClientUnit.Contains(cleanKeyword) ||
+                            ssd.Name.Contains(cleanKeyword) ||
+                            ssd1.Name.Contains(cleanKeyword)
+                        );
+                    }
+                }
+
+                // 排序
+                query = query.OrderBy((gdi, ssd, ssd1, su) => gdi.VisitDate, OrderByType.Desc);
+
+                // 查询数据
+                var totalCount = new RefAsync<int>(0);
+                var data = await query
+                    .Select((gdi, ssd, ssd1, su) => new
                     {
                         Id = gdi.Id,
                         TourCode = gdi.TourCode,
@@ -115,101 +147,71 @@ namespace OASystem.API.Controllers
                         VisitPNumber = gdi.VisitPNumber,
                         IsSure = gdi.IsSure,
                         TeamTypeId = ssd.Id,
-                        TeamType = ssd.Name,
+                        TeamTypeName = ssd.Name,  // 使用正确的字段名
                         TeamLevId = ssd1.Id,
-                        TeamLev = ssd1.Name,
-                        JietuanOperator = su.CnName,
-                        LastCollectionTime = SqlFunc.AggregateMax(pr.CreateTime)
-                    });
+                        TeamLevName = ssd1.Name,  // 使用正确的字段名
+                        JietuanOperatorName = su.CnName
+                    })
+                    .Distinct()  // 确保数据不重复
+                    .ToPageListAsync(dto.PageIndex, dto.PageSize, totalCount);
 
-                // 完成状态筛选
-                if (dto.IsSure == 0) // 未完成
-                {
-                    query = query.Where(gdi => gdi.IsSure == 0);
-                }
-                else if (dto.IsSure == 1) // 已完成
+                // 如果有数据,单独查询每个团组的最后收款时间
+                if (data.Any())
                 {
-                    query = query.Where(gdi => gdi.IsSure == 1);
-                }
+                    var delegationIds = data.Select(x => x.Id).ToList();
 
-                // 高级搜索处理
-                if (!string.IsNullOrEmpty(dto.SearchCriteria))
-                {
-                    string searchTerm = dto.SearchCriteria;
+                    // 查询每个团组的最新收款时间
+                    var lastCollectionTimes = await _sqlSugar.Queryable<Fin_ProceedsReceived>()
+                        .Where(pr => delegationIds.Contains(pr.Diid))
+                        .GroupBy(pr => pr.Diid)
+                        .Select(pr => new
+                        {
+                            Diid = pr.Diid,
+                            LastTime = SqlFunc.AggregateMax(pr.CreateTime)
+                        })
+                        .ToListAsync();
 
-                    // 搜索字段列表(对应查询中的字段)
-                    var searchFields = new List<string>
-                    {
-                        "TeamName",         // 团队名称
-                        "ClientName",       // 客户名称
-                        "JietuanOperator",  // 接团操作员
-                        "TourCode",         // 团号
-                        "ClientUnit",       // 客户单位
-                        "TeamType",         // 团队类型
-                        "TeamLev"           // 团队级别
-                    };
+                    // 转换为最终的视图模型
+                    var lastCollectionDict = lastCollectionTimes.ToDictionary(x => x.Diid, x => x.LastTime);
 
-                    // 搜索配置
-                    var searchConfig = new SearchConfig
+                    var resultData = data.Select(item => new GroupStatementItemView
                     {
-                        EnableExactMatch = true,
-                        EnablePrefixMatch = true,
-                        EnableFuzzySearch = true,
-                        EnableCharSearch = true,
-                        RequireAllWords = true,
-                        RequireAllChars = false,
-                        EnableSmartSplitting = true,
-                        MinSplitLength = 4
+                        Id = item.Id,
+                        TourCode = item.TourCode,
+                        TeamName = item.TeamName,
+                        ClientName = item.ClientName,
+                        ClientUnit = item.ClientUnit,
+                        VisitDate = item.VisitDate,
+                        VisitDays = item.VisitDays,
+                        VisitPNumber = item.VisitPNumber,
+                        IsSure = item.IsSure,
+                        TeamTypeId = item.TeamTypeId,
+                        TeamType = item.TeamTypeName,  // 映射到正确的属性
+                        TeamLevId = item.TeamLevId,
+                        TeamLev = item.TeamLevName,    // 映射到正确的属性
+                        JietuanOperator = item.JietuanOperatorName,
+                        LastCollectionTime = lastCollectionDict.TryGetValue(item.Id, out var lastTime) ? lastTime : null
+                    }).ToList();
+
+                    var result = new
+                    {
+                        PageFuncAuth = pageFunAuthView,
+                        Data = resultData
                     };
 
-                    // 构建搜索条件
-                    var (searchCondition, searchParameters) = AdvancedSearchHelper.BuildEnhancedSearchCondition(
-                        searchTerm: searchTerm,
-                        searchFields: searchFields,
-                        prefix: "search_groupExcel_",
-                        searchMode: SearchMode.AutoDetect,
-                        combinationMode: CombinationMode.SmartMix,
-                        config: searchConfig
-                    );
-
-                    if (!string.IsNullOrEmpty(searchCondition))
-                    {
-                        // 添加搜索条件和参数
-                        query = query.Where(searchCondition, searchParameters.ToArray());
-                    }
-                    else
-                    {
-                        // 回退到简单搜索
-                        query = query.Where(gdi =>
-                            gdi.TeamName.Contains(searchTerm) ||
-                            gdi.ClientName.Contains(searchTerm) ||
-                            gdi.JietuanOperator.Contains(searchTerm) ||
-                            gdi.TourCode.Contains(searchTerm) ||
-                            gdi.ClientUnit.Contains(searchTerm) ||
-                            gdi.TeamType.Contains(searchTerm) ||
-                            gdi.TeamLev.Contains(searchTerm));
-                    }
+                    return Ok(JsonView(true, "查询成功!", result, totalCount));
                 }
 
-                // 获取总数
-                RefAsync<int> total = 0;
-
-                // 执行分页查询
-                var delegationList = await query
-                    .OrderByDescending(gdi => gdi.VisitDate)
-                    .ToPageListAsync(dto.PageIndex, dto.PageSize, total);
-
-                var _view = new
+                // 没有数据的情况
+                return Ok(JsonView(true, "查询成功!", new
                 {
                     PageFuncAuth = pageFunAuthView,
-                    Data = delegationList
-                };
-                return Ok(JsonView(true, "查询成功!", _view, total));
-
+                    Data = new List<GroupStatementItemView>()
+                }));
             }
-            else
+            catch (Exception ex)
             {
-                return Ok(JsonView(false, "查询失败"));
+                return Ok(JsonView(false, "查询失败:" + ex.Message));
             }
         }
 

+ 7 - 1
OASystem/OASystem.Domain/Dtos/PersonnelModule/TaskAllocationDto.cs

@@ -34,7 +34,7 @@ namespace OASystem.Domain.Dtos.PersonnelModule
         /// 数据类型
         /// 0 全部 1 由我指派 2 指派给我
         /// </summary>
-        public int Type { get; set; }
+        public int Type { get; set; } = 0;
 
         /// <summary>
         /// 任务状态
@@ -46,6 +46,12 @@ namespace OASystem.Domain.Dtos.PersonnelModule
         /// </summary>
         public int TaskType { get; set; } = -1;
 
+        /// <summary>
+        /// userid
+        /// -1 全部 
+        /// </summary>
+        public int TaskUserId { get; set; }
+
         /// <summary>
         /// 任务名称
         /// </summary>

+ 17 - 5
OASystem/OASystem.Domain/Entities/PersonnelModule/FinanceKpi.cs

@@ -7,10 +7,10 @@ using System.Threading.Tasks;
 namespace OASystem.Domain.Entities.PersonnelModule
 {
     /// <summary>
-    /// 财务部绩效考核
+    /// 公司日常绩效考核
     /// </summary>
-    [SugarTable("FinanceKpi", "财务部绩效考核")]
-    public class FinanceKpi : EntityBase
+    [SugarTable("Pm_CompanyDailyKpi", "公司日常绩效考核")]
+    public class Pm_CompanyDailyKpi : EntityBase
     {
         /// <summary>
         /// 月份(yyyy-MM)
@@ -33,14 +33,26 @@ namespace OASystem.Domain.Entities.PersonnelModule
         /// <summary>
         /// 是否失误
         /// </summary>
-        [SugarColumn(ColumnName = "EvalContent", ColumnDescription = "是否失误", IsNullable = true, ColumnDataType = "bit")]
+        [SugarColumn(ColumnName = "IsMistake", ColumnDescription = "是否失误", IsNullable = true, ColumnDataType = "bit")]
         public bool IsMistake { get; set; }
         
         /// <summary>
         /// 失误原因
         /// </summary>
-        [SugarColumn(ColumnName = "EvalContent", ColumnDescription = "考核内容", IsNullable = true, ColumnDataType = "varchar(300)")]
+        [SugarColumn(ColumnName = "MistakeReason", ColumnDescription = "考核内容", IsNullable = true, ColumnDataType = "varchar(300)")]
         public string MistakeReason { get; set; }
 
+        /// <summary>
+        /// 最后修改人
+        /// </summary>
+        [SugarColumn(ColumnName = "LastUpdateUserId", ColumnDescription = "最后修改人", IsNullable = true, ColumnDataType = "int")]
+        public int LastUpdateUserId { get; set; }
+
+        /// <summary>
+        /// 最后修改时间
+        /// </summary>
+        [SugarColumn(ColumnName = "LastUpdateTime", ColumnDescription = "最后修改时间", IsNullable = true, ColumnDataType = "datetime")]
+        public DateTime LastUpdateTime { get; set; }
+
     }
 }

+ 0 - 2
OASystem/OASystem.Domain/Entities/System/Sys_JobPost.cs

@@ -24,9 +24,7 @@ namespace OASystem.Domain.Entities.System
         public string JobName { get; set; }
        
     }
-    #region 附加字段
 
-    #endregion
     public class Sys_JobPostI:Sys_JobPost
     {
         public string CompanyName { get; set; }

+ 73 - 0
OASystem/OASystem.Domain/ViewModels/PersonnelModule/CompanyDailyKpiView.cs

@@ -0,0 +1,73 @@
+namespace OASystem.Domain.ViewModels.PersonnelModule
+{
+    /// <summary>
+    /// 日常考情详情 View
+    /// </summary>
+    public class CompanyDailyKpiView
+    {
+        public int Id { get; set; }
+
+        /// <summary>
+        /// 月份(yyyy-MM)
+        /// </summary>
+        public string Month { get; set; }
+
+        /// <summary>
+        /// 考核人 Id
+        /// </summary>
+        public int EvaluatorId { get; set; }
+
+        /// <summary>
+        /// 考核人
+        /// </summary>
+        public string Evaluator { get; set; }
+
+        /// <summary>
+        /// 考核内容 Id
+        /// </summary>
+        public int EvalContentId { get; set; }
+
+        /// <summary>
+        /// 考核内容 
+        /// </summary>
+        public string EvalContent { get; set; }
+
+        /// <summary>
+        /// 是否失误
+        /// </summary>
+        public bool IsMistake { get; set; }
+
+        /// <summary>
+        /// 失误原因
+        /// </summary>
+        public string MistakeReason { get; set; }
+    }
+
+    /// <summary>
+    /// Kpi 模板类型信息
+    /// </summary>
+    public class KpiTempTypeInfo
+    {
+        public int TypeId { get; set; }
+        public string TypeName { get; set; }
+        public List<KpiTempContentInfo> Contents { get; set; }
+    }
+
+    /// <summary>
+    /// Kpi 模版内容信息
+    /// </summary>
+    public class KpiTempContentInfo
+    {
+        public int KpiId { get; set; }
+        public string KpiContent { get; set; }
+        public string KpiSort { get; set; }
+        public KpiTempContentInfo() { }
+        public KpiTempContentInfo(int id, string content, string sort)
+        {
+            KpiId = id;
+            KpiContent = content;
+            KpiSort = sort;
+        }
+
+    }
+}

+ 381 - 0
OASystem/OASystem.Infrastructure/Repositories/PersonnelModule/CompanyDailyKpiRepository.cs

@@ -0,0 +1,381 @@
+using AutoMapper;
+using OASystem.Domain.Entities.PersonnelModule;
+using OASystem.Domain.ViewModels.PersonnelModule;
+using OASystem.Infrastructure.Repositories.System;
+
+namespace OASystem.Infrastructure.Repositories.PersonnelModule
+{
+    /// <summary>
+    /// 公司日常KPI考核仓储
+    /// </summary>
+    public class CompanyDailyKpiRepository : BaseRepository<Pm_CompanyDailyKpi, Pm_CompanyDailyKpi>
+    {
+        private readonly IMapper _mapper;
+        private JsonView _jv;
+        public CompanyDailyKpiRepository(SqlSugarClient sqlSugar,
+            IMapper mapper,
+            ApprovalProcessRepository approvalProcessRep)
+            : base(sqlSugar)
+        {
+            _mapper = mapper;
+            _jv = new JsonView() { Code = StatusCodes.Status400BadRequest, Msg = "操作失败!" };
+
+        }
+
+        /// <summary>
+        /// 绩效模板数据(保持原方法签名)
+        /// </summary>
+        public async Task<(bool isSuccess, string msg, List<KpiTempTypeInfo> data)> KpiTemplateDataAsync(string depName, string jobName)
+        {
+            var result = new List<KpiTempTypeInfo>();
+            // 获取配置
+            var config = await _sqlSugar.Queryable<Sys_SetDataType>()
+                .Where(x => x.IsDel == 0 && x.Id == 132)
+                .FirstAsync();
+
+            if (config?.Remark == null)
+                return (false, "绩效考核-数据类型ID存储为空", result);
+
+            var typeIds = JsonSerializer.Deserialize<List<int>>(config.Remark);
+            if (typeIds?.Any() != true)
+                return (false, "绩效考核-数据类型ID存储为空", result);
+
+            // 构建查询
+            var query = _sqlSugar.Queryable<Sys_SetData>()
+                .LeftJoin<Sys_SetDataType>((sd, sdt) => sd.STid == sdt.Id)
+                .Where((sd, sdt) => sd.IsDel == 0 && typeIds.Contains(sd.STid));
+
+            // 条件过滤
+            if (!string.IsNullOrWhiteSpace(depName))
+                query = query.Where((sd, sdt) => sdt.Name.Contains(depName));
+
+            if (!string.IsNullOrWhiteSpace(jobName))
+                query = query.Where((sd, sdt) => sdt.Name.Contains(jobName));
+
+            // 查询数据
+            var data = await query
+                .Select((sd, sdt) => new
+                {
+                    KpiTypeId = sd.STid,
+                    KpiTypeName = sdt.Name,
+                    KpiId = sd.Id,
+                    KpiContent = sd.Remark,
+                    KpiSort = sd.Name
+                })
+                .ToListAsync();
+
+            if (data?.Any() != true)
+                return (false, "绩效考核模板信息为空", result);
+
+            // 分组处理
+            result = data
+                .GroupBy(x => new { x.KpiTypeId, x.KpiTypeName })
+                .Select(g => new KpiTempTypeInfo()
+                {
+                    TypeId = g.Key.KpiTypeId,
+                    TypeName = g.Key.KpiTypeName,
+                    Contents = g
+                        .OrderBy(x => int.TryParse(x.KpiSort, out int s) ? s : int.MaxValue)
+                        .ThenBy(x => x.KpiSort)
+                        .Select(x => new KpiTempContentInfo(x.KpiId, x.KpiContent, x.KpiSort))
+                        .ToList()
+                })
+                .Where(g => g.Contents.Any())
+                .OrderBy(g => g.TypeId)
+                .ToList();
+
+            return (true, "操作成功", result);
+        }
+
+        /// <summary>
+        /// 获取部门和岗位
+        /// </summary>
+        public async Task<object> KpiDepartmentsAndJobs()
+        {
+            var config = await _sqlSugar.Queryable<Sys_SetDataType>()
+                .Where(x => x.IsDel == 0 && x.Id == 132)
+                .FirstAsync();
+
+            if (config == null) return new { Success = false, Message = "配置为空" };
+
+            var typeIds = JsonSerializer.Deserialize<List<int>>(config.Remark ?? "[]");
+            if (typeIds == null || typeIds.Count < 1)
+                return new { Success = false, Message = "类型ID为空" };
+
+            var names = await _sqlSugar.Queryable<Sys_SetData>()
+                .LeftJoin<Sys_SetDataType>((sd, sdt) => sd.STid == sdt.Id)
+                .Where((sd, sdt) => sd.IsDel == 0 && typeIds.Contains(sd.STid))
+                .Select((sd, sdt) => sdt.Name)
+                .Distinct()
+                .ToListAsync();
+
+            // 解析部门和岗位
+            var deptJobList = names
+                .Select(name =>
+                {
+                    var clean = name.Split('(')[0].Trim();
+                    string dept, job;
+
+                    if (clean.Contains(" - "))
+                    {
+                        var parts = clean.Split(" - ");
+                        dept = parts[0].EndsWith("部") ? parts[0] : parts[0] + "部";
+                        job = parts.Length > 1 ? parts[1] : "通用";
+                    }
+                    else if (clean.Contains("-"))
+                    {
+                        var parts = clean.Split('-');
+                        dept = parts[0].EndsWith("部") ? parts[0] : parts[0] + "部";
+                        job = parts.Length > 1 ? parts[1] : "通用";
+                    }
+                    else
+                    {
+                        dept = clean.EndsWith("部") ? clean : "未分类";
+                        job = clean.EndsWith("部") ? "通用" : clean;
+                    }
+
+                    return new { Department = dept, Job = job };
+                })
+                .Where(x => x.Department != "未分类")
+                .GroupBy(x => x.Department)
+                .Select(g => new
+                {
+                    Department = g.Key,
+                    Jobs = g.Select(x => x.Job).Distinct().Where(j => j != "通用").OrderBy(j => j).ToList()
+                })
+                .OrderBy(g => g.Department)
+                .ToList();
+
+            return new
+            {
+                Success = true,
+                Departments = deptJobList.Select(g => g.Department).ToList(),
+                DepartmentsWithJobs = deptJobList
+            };
+        }
+
+
+        #region 财务部日常绩效
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        /// <returns></returns>
+        public async Task<JsonView> FinanceInit()
+        {
+            var userInfos = await _sqlSugar.Queryable<Sys_Users>()
+                .LeftJoin<Sys_JobPost>((u, jp) => u.JobPostId == jp.Id)
+                .LeftJoin<Sys_Department>((u, jp, d) => u.DepId == d.Id)
+                .LeftJoin<Sys_Company>((u, jp, d, c) => u.CompanyId == c.Id)
+                .Where((u, jp, d, c) => u.IsDel == 0)
+                .Select((u, jp, d, c) => new
+                {
+                    UserId = u.Id,
+                    u.CompanyId,
+                    c.CompanyName,
+                    u.DepId,
+                    d.DepName,
+                    u.JobPostId,
+                    jp.JobName,
+                    UserName = u.CnName
+                })
+                .OrderBy(u => u.CompanyId)
+                .ToListAsync();
+
+            if (userInfos?.Any() != true)
+            {
+                _jv.Code = StatusCodes.Status200OK;
+                _jv.Msg = $"暂无人员数据";
+                return _jv;
+            }
+
+            //转换为层级结构
+            #region 层级转换 公司 -> 部门 -> 岗位 -> 人员
+            //var result = userInfos
+            //    .GroupBy(u => new { u.CompanyId, u.CompanyName })
+            //    .Select(companyGroup => new
+            //    {
+            //        CompanyId = companyGroup.Key.CompanyId,
+            //        CompanyName = companyGroup.Key.CompanyName,
+            //        Departments = companyGroup
+            //            .GroupBy(u => new { u.DepId, u.DepName })
+            //            .Select(departmentGroup => new
+            //            {
+            //                DepId = departmentGroup.Key.DepId,
+            //                DepartmentName = departmentGroup.Key.DepName,
+            //                JobPosts = departmentGroup
+            //                    .GroupBy(u => new { u.JobPostId, u.JobName })
+            //                    .Select(jobGroup => new
+            //                    {
+            //                        JobPostId = jobGroup.Key.JobPostId,
+            //                        JobName = jobGroup.Key.JobName,
+            //                        Employees = jobGroup
+            //                            .Select(u => new
+            //                            {
+            //                                Id = u.UserId,
+            //                                UserName = u.UserName,
+            //                            })
+            //                            .OrderBy(e => e.UserName)
+            //                            .ToList()
+            //                    })
+            //                    .OrderBy(j => j.JobName)
+            //                    .ToList()
+            //            })
+            //            .OrderBy(d => d.DepartmentName)
+            //            .ToList()
+            //    })
+            //    .OrderBy(c => c.CompanyName)
+            //    .ToList();
+            #endregion
+
+            //转换为层级结构
+            #region 层级转换 公司 -> 部门 -> 人员
+            // 构建树形结构
+            var result = userInfos
+                .GroupBy(u => new { u.CompanyId, u.CompanyName })
+                .Select(companyGroup => new
+                {
+                    CompanyId = companyGroup.Key.CompanyId,
+                    CompanyName = companyGroup.Key.CompanyName,
+                    Departments = companyGroup
+                        .GroupBy(u => new { u.DepId, u.DepName })
+                        .Where(deptGroup => deptGroup.Key.DepId > 0) // 过滤掉无部门的人员
+                        .Select(deptGroup => new
+                        {
+                            DepartmentId = deptGroup.Key.DepId,
+                            DepartmentName = deptGroup.Key.DepName,
+                            Users = deptGroup
+                                .Select(u => new
+                                {
+                                    u.UserId,
+                                    u.UserName,
+                                    u.JobPostId,
+                                    u.JobName
+                                })
+                                .OrderBy(u => u.UserName)
+                                .ToList()
+                        })
+                        .Where(dept => dept.Users.Any())
+                        .OrderBy(dept => dept.DepartmentName)
+                        .ToList(),
+                    // 无部门的人员(直接挂载到公司下)
+                    NoDepartmentUsers = companyGroup
+                        .Where(u => u.DepId <= 0)
+                        .Select(u => new
+                        {
+                            u.UserId,
+                            u.UserName,
+                            u.JobPostId,
+                            u.JobName
+                        })
+                        .OrderBy(u => u.UserName)
+                        .ToList()
+                })
+                .OrderBy(c => c.CompanyName)
+                .ToList();
+            #endregion
+
+            _jv.Code = StatusCodes.Status200OK;
+            _jv.Data = result;
+            _jv.Msg = $"操作成功";
+            return _jv;
+        }
+
+        /// <summary>
+        /// 日常考勤详情
+        /// </summary>
+        /// <param name="month">月份 2025-12</param>
+        /// <param name="userId">考核人</param>
+        /// <returns></returns>
+        public async Task<JsonView> FinanceInfo(string month, int evaluator)
+        {
+            if (string.IsNullOrEmpty(month))
+            {
+                _jv.Msg = $"请选择月份!";
+                return _jv;
+            }
+
+            // 格式:2025-11
+            const string pattern = @"^(\d{4})-(0[1-9]|1[0-2])$";
+            if (!Regex.IsMatch(month, pattern))
+            {
+                _jv.Msg = $"请选择正确的月份!格式:2025-12";
+                return _jv;
+            }
+            var evaluatorInfo = await _sqlSugar.Queryable<Sys_Users>()
+                .LeftJoin<Sys_Company>((u, c) => u.CompanyId == c.Id)
+                .LeftJoin<Sys_Department>((u, c, d) => u.DepId == d.Id)
+                .LeftJoin<Sys_JobPost>((u, c, d, jp) => u.JobPostId == d.Id)
+                .Where((u, c, d, jp) => u.IsDel == 0)
+                .Select((u, c, d, jp) => new
+                {
+                    UserId = u.Id,
+                    u.CompanyId,
+                    c.CompanyName,
+                    u.DepId,
+                    d.DepName,
+                    u.JobPostId,
+                    jp.JobName,
+                    UserName = u.CnName
+                })
+                .FirstAsync();
+            if (evaluatorInfo == null)
+            {
+                _jv.Msg = $"请选择有效的考核人!";
+                return _jv;
+            }
+
+            var info = await _sqlSugar
+                .Queryable<Pm_CompanyDailyKpi>()
+                .LeftJoin<Sys_SetData>((cdk, sd) => cdk.EvalContent == sd.Id)
+                .LeftJoin<Sys_Users>((cdk, sd, u) => cdk.Evaluator == u.Id)
+                .Where((cdk, sd, u) => cdk.IsDel == 0 && cdk.Evaluator == evaluator && cdk.Month.Equals(month))
+                .Select((cdk, sd, u) => new CompanyDailyKpiView()
+                {
+                    Id = cdk.Id,
+                    Month = cdk.Month,
+                    EvaluatorId = cdk.Evaluator,
+                    Evaluator = u.CnName,
+                    EvalContentId = cdk.EvalContent,
+                    EvalContent = sd.Remark,
+                    IsMistake = cdk.IsMistake,
+                    MistakeReason = cdk.MistakeReason
+                })
+                .ToListAsync();
+
+            if (!info.Any())
+            {
+                var tempInfo = await KpiTemplateDataAsync(evaluatorInfo.DepName, evaluatorInfo.JobName);
+                if (!tempInfo.isSuccess)
+                {
+                    _jv.Msg = $"{evaluatorInfo.DepName} - {evaluatorInfo.JobName},未配置日常绩效考核。";
+                    return _jv;
+                }
+
+                tempInfo.data.ForEach(t =>
+                {
+                    t.Contents.ForEach(c =>
+                    {
+                        info.Add(new CompanyDailyKpiView()
+                        {
+                            Month = month,
+                            EvaluatorId = evaluatorInfo.UserId,
+                            Evaluator = evaluatorInfo.UserName,
+                            EvalContentId = c.KpiId,
+                            EvalContent = c.KpiContent,
+                            IsMistake = false,
+                            MistakeReason = string.Empty
+                        });
+                    });
+                });
+
+            }
+            _jv.Code = StatusCodes.Status200OK;
+            _jv.Data = info;
+            _jv.Msg = $"操作成功";
+            return _jv;
+        }
+
+        #endregion
+
+    }
+}

文件差异内容过多而无法显示
+ 0 - 2521
OASystem/OASystem.Infrastructure/Tools/AdvancedSearchHelper.cs