HomeController.cs 7.46 KB
using HHECS.WorkHourStatistics.Dtos;
using HHECS.WorkHourStatistics.Models;
using HHECS.WorkHourStatistics.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using System.Linq.Expressions;
using System.Text;

namespace HHECS.WorkHourStatistics.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly IFreeSql _freeSql;

        /// <summary>
        /// 长沙公司部门根节点Id
        /// </summary>
        private readonly string rootDeptId = "8682240671139790443";

        public HomeController(ILogger<HomeController> logger, IFreeSql freeSql)
        {
            _logger = logger;
            _freeSql = freeSql;
        }

        public IActionResult Index()
        {
            var depts = _freeSql.Queryable<Department>().ToList();
            var root = new TreeDto
            {
                Id = rootDeptId,
                Title = "长沙华恒机器人系统有限公司",
                Spread = true,
                Checked = true
            };

            BuiderTree(root, depts);
            return View(root);
        }

        [HttpPost]
        public IActionResult Index(string person, TreeDto dept, DateTime? startTime, DateTime? endTime, int page, int limit)
        {
            try
            {
                var query = _freeSql.Queryable<WorkRecord>().Where(GetFilter(person, dept, startTime, endTime)).OrderBy(x => x.BaseWorkCard).OrderBy(x => x.Number);
                var result = query.Skip((page - 1) * limit).Take(limit).ToList();

                var numbers = result.Select(x => x.Number).Distinct().ToList();
                var personInfos = _freeSql.Queryable<Person>().Where(x => numbers.Contains(x.Number)).ToList(x => new Person
                {
                    Number = x.Number,
                    Virtual_departmentPath = x.Virtual_departmentPath,
                });

                foreach (var item in result)
                {
                    var departmentPath = personInfos.Where(x => x.Number == item.Number).Select(x => x.Virtual_departmentPath).FirstOrDefault();
                    if (!string.IsNullOrWhiteSpace(departmentPath))
                    {
                        item.DeptName = departmentPath.Split('/').LastOrDefault() ?? string.Empty;
                    }
                }

                return Ok(new
                {
                    code = 0,
                    msg = "",
                    count = query.Count(),
                    data = result,
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 0,
                    msg = ex.Message,
                    count = 0,
                    data = Array.Empty<string>(),
                });
            }
        }

        [HttpPost]
        public IActionResult Export(string person, TreeDto dept, DateTime? startTime, DateTime? endTime)
        {
            try
            {
                var result = _freeSql.Queryable<WorkRecord>().Where(GetFilter(person, dept, startTime, endTime)).OrderBy(x => x.Number).OrderBy(x => x.BaseWorkCard).ToList();
                var numbers = result.Select(x => x.Number).Distinct().ToList();
                var personInfos = _freeSql.Queryable<Person>().Where(x => numbers.Contains(x.Number)).ToList(x => new Person
                {
                    Number = x.Number,
                    Virtual_departmentPath = x.Virtual_departmentPath,
                });

                foreach (var item in result)
                {
                    var departmentPath = personInfos.Where(x => x.Number == item.Number).Select(x => x.Virtual_departmentPath).FirstOrDefault();
                    if (!string.IsNullOrWhiteSpace(departmentPath))
                    {
                        item.DeptName = departmentPath.Split('/').LastOrDefault() ?? string.Empty;
                    }
                }

                var reportData = RepotTool.GetReport(result).Data;
                var time1 = startTime ?? result.Min(x => x.BaseWorkCard);
                var time2 = endTime ?? result.Max(x => x.BaseOffDutyCard);
                var days = RepotTool.GetHeadDays(result.Min(x => x.BaseWorkCard), result.Max(x => x.BaseOffDutyCard));
                var workBookResult = NpoiHelper.GetWorkbook(reportData, days);

                // 写 WorkBook信息到 内存流中
                byte[] buffer;
                using (var ms = new MemoryStream())
                {
                    workBookResult.Data.Write(ms);
                    buffer = ms.ToArray();
                }

                var fileName = new StringBuilder();
                fileName.Append("WT时间统计 - ");

                if (!string.IsNullOrWhiteSpace(person))
                {
                    fileName.Append($"[{person}]");
                }

                fileName.Append($"{time1:D}至{time2:D}.xlsx");

                // .xlsx文件对应的Mime信息
                var mime = new FileExtensionContentTypeProvider().Mappings[".xlsx"];
                return File(buffer, mime, fileName.ToString());
            }
            catch (Exception ex)
            {
                return Ok(ex.Message);
            }
        }

        private static void BuiderTree(TreeDto root, List<Department> depts)
        {
            var childrens = depts.Where(x => x.ParentId == root.Id).OrderBy(x => x.OrderNum).Select(x => new TreeDto
            {
                Id = x.Id,
                Title = x.Name,
            }).ToList();
            root.Children = childrens;
            foreach (var child in childrens)
            {
                BuiderTree(child, depts);
            }
        }

        private Expression<Func<WorkRecord, bool>> GetFilter(string person, TreeDto dept, DateTime? startTime, DateTime? endTime)
        {
            Expression<Func<WorkRecord, bool>> filter = x => true;
            if (!string.IsNullOrWhiteSpace(person))
            {
                filter = filter.And(x => x.Number.Contains(person) || x.PersonName.Contains(person));
            }

            var depts = GetPaths(dept, null);
            if (depts.Count != 0)
            {
                var personNumbers = depts.Select(d => _freeSql.Queryable<Person>().Where(x => x.Virtual_departmentPath.EndsWith(d)).ToList(x => x.Number)).SelectMany(x => x).ToList();
                filter = filter.And(x => personNumbers.Contains(x.Number));
            }

            if (startTime != null)
            {
                filter = filter.And(x => x.BaseWorkCard >= startTime.Value.Date);
            }
            if (endTime != null)
            {
                filter = filter.And(x => x.BaseOffDutyCard < endTime.Value.Date.AddDays(1));
            }

            return filter;
        }

        private static List<string> GetPaths(TreeDto node, string? currentPath = null)
        {
            var paths = new List<string>();
            // 构建当前节点的完整路径
            string fullPath = string.IsNullOrEmpty(currentPath) ? node.Title : currentPath + "/" + node.Title;

            // 递归基:如果是叶子节点,返回包含单个路径的列表
            if (node.Children.Count == 0)
            {
                paths.Add(fullPath);
                return paths;
            }
            paths.Add(fullPath);

            // 递归遍历所有子节点,并构建路径
            foreach (var child in node.Children)
            {
                paths.AddRange(GetPaths(child, fullPath));
            }

            return paths;
        }
    }
}