LqEmployeeRosterService.cs 7.44 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NCC.Common.Core.Manager;
using NCC.Common.Filter;
using NCC.Common.Util;
using NCC.Dependency;
using NCC.DynamicApiController;
using NCC.Extend.Entitys.Dto.LqEmployeeRoster;
using NCC.Extend.Entitys.lq_attendance_summary;
using NCC.Extend.Entitys.lq_mdxx;
using NCC.FriendlyException;
using NCC.System.Entitys.Model.Permission.User;
using NCC.System.Entitys.Permission;
using SqlSugar;

namespace NCC.Extend
{
    /// <summary>
    /// 员工花名册(按年月、组织机构查询在职人员)
    /// </summary>
    [ApiDescriptionSettings(Tag = "绿纤员工花名册", Name = "LqEmployeeRoster", Order = 203)]
    [Route("api/Extend/LqEmployeeRoster")]
    public class LqEmployeeRosterService : IDynamicApiController, ITransient
    {
        private readonly ISqlSugarClient _db;
        private readonly IUserManager _userManager;

        /// <summary>
        /// 初始化员工花名册服务
        /// </summary>
        public LqEmployeeRosterService(ISqlSugarClient db, IUserManager userManager)
        {
            _db = db;
            _userManager = userManager;
        }

        /// <summary>
        /// 分页查询指定年月在职员工花名册。口径:优先取该月有效考勤汇总(F_IsEffective=1)中员工状态为在职(F_EmployeeStatus=1);
        /// 无汇总且查询月不晚于当前月时:入职不晚于该月末,且(无离职日或离职日≥该月 1 日)。含义:离职日在上月或更早则本月不出现;离职日在本月或之后则本月仍出现(含当月中途离职);查下月时因「离职日≥下月1日」不成立,上月已离职者不会出现在下月(不依赖 F_IsOnJob)。
        /// 有有效汇总且员工状态非在职则不列入。未来月仅认汇总。
        /// </summary>
        /// <param name="year">年</param>
        /// <param name="month">月(1-12)</param>
        /// <param name="organizeId">组织机构节点 ID,含其下级;不传则按数据权限范围内全部</param>
        /// <param name="keyword">账号或姓名模糊</param>
        /// <param name="page">分页参数</param>
        [HttpGet("")]
        public async Task<dynamic> GetList(
            [FromQuery] int year,
            [FromQuery] int month,
            [FromQuery] string organizeId,
            [FromQuery] string keyword,
            [FromQuery] PageInputBase page)
        {
            if (year < 1990 || year > 2100 || month < 1 || month > 12)
            {
                throw NCCException.Oh("year/month 参数不合法");
            }

            page ??= new PageInputBase();
            var user = await _userManager.GetUserInfo();
            var orgFilter = await ResolveOrganizeFilterAsync(user, organizeId);
            var now = DateTime.Now;
            var isFutureMonth = year > now.Year || (year == now.Year && month > now.Month);
            var monthEnd = new DateTime(year, month, DateTime.DaysInMonth(year, month), 23, 59, 59);
            var firstDayOfMonth = new DateTime(year, month, 1);
            var kw = string.IsNullOrWhiteSpace(keyword) ? null : keyword.Trim();

            var query = _db.Queryable<UserEntity, OrganizeEntity, LqAttendanceSummaryEntity, LqMdxxEntity>(
                    (u, o, s, m) => new JoinQueryInfos(
                        JoinType.Left, o.Id == SqlFunc.ToString(u.OrganizeId),
                        JoinType.Left,
                        s.UserId == u.Id && s.Year == year && s.Month == month && s.IsEffective == 1,
                        JoinType.Left, m.Id == u.Mdid))
                .Where((u, o, s, m) => u.DeleteMark == null)
                .Where((u, o, s, m) =>
                    (!SqlFunc.IsNullOrEmpty(s.Id) && s.EmployeeStatus == 1)
                    || (!isFutureMonth
                        && SqlFunc.IsNullOrEmpty(s.Id)
                        && u.EntryDate != null
                        && u.EntryDate <= monthEnd
                        && (u.LeaveDate == null || u.LeaveDate >= firstDayOfMonth)))
                .WhereIF(kw != null, (u, o, s, m) => u.Account.Contains(kw) || u.RealName.Contains(kw))
                .Select((u, o, s, m) => new LqEmployeeRosterListOutput
                {
                    id = u.Id,
                    account = u.Account,
                    realName = u.RealName,
                    department = o.FullName,
                    organizeId = u.OrganizeId,
                    mdid = u.Mdid,
                    mdName = m.Dm,
                    gw = u.Gw,
                    zw = u.Zw,
                    enabledMark = u.EnabledMark,
                    isOnJob = u.IsOnJob,
                    summaryEmployeeStatus = SqlFunc.IIF(SqlFunc.IsNullOrEmpty(s.Id), (int?)null, s.EmployeeStatus),
                    workDays = SqlFunc.IIF(SqlFunc.IsNullOrEmpty(s.Id), (decimal?)null, s.WorkDays),
                    mobilePhone = u.MobilePhone,
                    entryDate = u.EntryDate
                })
                .MergeTable();

            if (orgFilter != null)
            {
                query = query.Where(x => orgFilter.Contains(x.organizeId));
            }

            query = query
                .OrderBy(x => x.organizeId)
                .OrderBy(x => x.realName);

            var paged = await query.ToPagedListAsync(page.currentPage, page.pageSize);
            return PageResult<LqEmployeeRosterListOutput>.SqlSugarPageResult(paged);
        }

        /// <summary>
        /// 管理员:未选组织时不限制;已选组织则限制为该节点及下级。非管理员:限制在数据权限机构(含下级)内,并可与所选组织求交。
        /// </summary>
        private async Task<List<string>> ResolveOrganizeFilterAsync(UserInfo user, string organizeId)
        {
            var allOrgs = await _db.Queryable<OrganizeEntity>()
                .Where(x => x.DeleteMark == null)
                .ToListAsync();

            List<string> subtree = null;
            if (!string.IsNullOrWhiteSpace(organizeId))
            {
                subtree = allOrgs
                    .TreeChildNode(organizeId.Trim(), t => t.Id, t => t.ParentId)
                    .Select(x => x.Id)
                    .ToList();
            }

            if (user.isAdministrator)
            {
                return subtree;
            }

            var allowed = new HashSet<string>();
            foreach (var scope in user.dataScope ?? new List<UserDataScope>())
            {
                if (!scope.Add && !scope.Edit && !scope.Delete)
                {
                    continue;
                }

                if (string.IsNullOrEmpty(scope.organizeId))
                {
                    continue;
                }

                foreach (var id in allOrgs.TreeChildNode(scope.organizeId, t => t.Id, t => t.ParentId)
                             .Select(x => x.Id))
                {
                    allowed.Add(id);
                }
            }

            if (allowed.Count == 0)
            {
                return new List<string> { "__no_scope__" };
            }

            if (subtree != null && subtree.Count > 0)
            {
                var sel = subtree.ToHashSet();
                allowed.IntersectWith(sel);
                if (allowed.Count == 0)
                {
                    return new List<string> { "__no_scope__" };
                }
            }

            return allowed.ToList();
        }
    }
}