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
{
///
/// 员工花名册(按年月、组织机构查询在职人员)
///
[ApiDescriptionSettings(Tag = "绿纤员工花名册", Name = "LqEmployeeRoster", Order = 203)]
[Route("api/Extend/LqEmployeeRoster")]
public class LqEmployeeRosterService : IDynamicApiController, ITransient
{
private readonly ISqlSugarClient _db;
private readonly IUserManager _userManager;
///
/// 初始化员工花名册服务
///
public LqEmployeeRosterService(ISqlSugarClient db, IUserManager userManager)
{
_db = db;
_userManager = userManager;
}
///
/// 分页查询指定年月在职员工花名册。口径:优先取该月有效考勤汇总(F_IsEffective=1)中员工状态为在职(F_EmployeeStatus=1);
/// 无汇总且查询月不晚于当前月时:入职不晚于该月末,且(无离职日或离职日≥该月 1 日)。含义:离职日在上月或更早则本月不出现;离职日在本月或之后则本月仍出现(含当月中途离职);查下月时因「离职日≥下月1日」不成立,上月已离职者不会出现在下月(不依赖 F_IsOnJob)。
/// 有有效汇总且员工状态非在职则不列入。未来月仅认汇总。
///
/// 年
/// 月(1-12)
/// 组织机构节点 ID,含其下级;不传则按数据权限范围内全部
/// 账号或姓名模糊
/// 分页参数
[HttpGet("")]
public async Task 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(
(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.SqlSugarPageResult(paged);
}
///
/// 管理员:未选组织时不限制;已选组织则限制为该节点及下级。非管理员:限制在数据权限机构(含下级)内,并可与所选组织求交。
///
private async Task> ResolveOrganizeFilterAsync(UserInfo user, string organizeId)
{
var allOrgs = await _db.Queryable()
.Where(x => x.DeleteMark == null)
.ToListAsync();
List 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();
foreach (var scope in user.dataScope ?? new List())
{
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 { "__no_scope__" };
}
if (subtree != null && subtree.Count > 0)
{
var sel = subtree.ToHashSet();
allowed.IntersectWith(sel);
if (allowed.Count == 0)
{
return new List { "__no_scope__" };
}
}
return allowed.ToList();
}
}
}