using JNPF.Common.Const; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Manager; using JNPF.Common.Security; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; using JNPF.Systems.Entitys.Dto.Position; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.Permission; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; namespace JNPF.Systems; /// /// 业务实现:岗位管理. /// 版 本:V3.2.0 /// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) /// 日 期:2021.06.07. /// [ApiDescriptionSettings(Tag = "Permission", Name = "Position", Order = 162)] [Route("api/Permission/[controller]")] public class PositionService : IPositionService, IDynamicApiController, ITransient { /// /// 基础仓储. /// private readonly ISqlSugarRepository _repository; /// /// 组织管理. /// private readonly IOrganizeService _organizeService; /// /// 缓存管理器. /// private readonly ICacheManager _cacheManager; /// /// 用户管理器. /// private readonly IUserManager _userManager; /// /// 初始化一个类型的新实例. /// public PositionService( ISqlSugarRepository repository, IOrganizeService organizeService, ICacheManager cacheManager, IUserManager userManager) { _repository = repository; _organizeService = organizeService; _cacheManager = cacheManager; _userManager = userManager; } #region GET /// /// 获取列表 根据organizeId. /// /// 参数. /// [HttpGet("getList/{organizeId}")] public async Task GetListByOrganizeId(string organizeId) { List? oid = new List(); if (!string.IsNullOrWhiteSpace(organizeId)) { // 获取组织下的所有组织 id 集合 List? oentity = await _repository.AsSugarClient().Queryable().ToChildListAsync(x => x.ParentId, organizeId); oid = oentity.Select(x => x.Id).ToList(); } List? data = await _repository.AsSugarClient().Queryable( (a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) // 组织机构 .WhereIF(!string.IsNullOrWhiteSpace(organizeId), a => oid.Contains(a.OrganizeId)) .Where(a => a.DeleteMark == null).OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc).OrderBy(a => a.LastModifyTime, OrderByType.Desc) .Select((a, b, c) => new PositionListOutput { id = a.Id, fullName = a.FullName, enCode = a.EnCode, type = c.FullName, department = b.FullName, enabledMark = a.EnabledMark, creatorTime = a.CreatorTime, description = a.Description, sortCode = a.SortCode }).ToListAsync(); return data.OrderBy(x => x.sortCode).ToList(); } /// /// 获取列表. /// /// 参数. /// [HttpGet("")] public async Task GetList([FromQuery] PositionListQuery input) { if (input.organizeId == "0") input.organizeId = _userManager.User.OrganizeId; // 获取分级管理组织 var dataScope = _userManager.DataScope.Where(x => x.Select).Select(x => x.organizeId).Distinct().ToList(); List? childOrgIds = new List(); if (input.organizeId.IsNotEmptyOrNull()) { childOrgIds.Add(input.organizeId); // 根据组织Id 获取所有子组织Id集合 childOrgIds.AddRange(_repository.AsSugarClient().Queryable().ToChildList(x => x.ParentId, input.organizeId).Select(x => x.Id).ToList()); childOrgIds = childOrgIds.Distinct().ToList(); } var data = await _repository.AsSugarClient().Queryable( (a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) // 组织机构 .WhereIF(childOrgIds.Any(), a => childOrgIds.Contains(a.OrganizeId)) .WhereIF(!_userManager.IsAdministrator, a => dataScope.Contains(a.OrganizeId)) // 关键字(名称、编码) .WhereIF(!input.keyword.IsNullOrEmpty(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) .Where(a => a.DeleteMark == null).OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc).OrderBy(a => a.LastModifyTime, OrderByType.Desc) .Select((a, b, c) => new PositionListOutput { id = a.Id, fullName = a.FullName, enCode = a.EnCode, type = c.FullName, department = b.FullName, organizeId = b.OrganizeIdTree, enabledMark = a.EnabledMark, creatorTime = a.CreatorTime, description = a.Description, sortCode = a.SortCode }).ToPagedListAsync(input.currentPage, input.pageSize); // 处理组织树 名称 List? orgList = _organizeService.GetOrgListTreeName(); #region 处理岗位所属组织树 foreach (PositionListOutput? item in data.list) { // 获取用户组织集合 item.department = orgList.Where(x => x.Id == item.organizeId.Split(",").LastOrDefault()).Select(x => x.Description).FirstOrDefault(); } #endregion return PageResult.SqlSugarPageResult(data); } /// /// 获取列表. /// /// [HttpGet("All")] public async Task GetList() { List? data = await _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) .Where(a => a.DeleteMark == null && a.EnabledMark == 1).OrderBy(a => a.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc).OrderBy(a => a.LastModifyTime, OrderByType.Desc) .Select((a, b, c) => new PositionListOutput { id = a.Id, fullName = a.FullName, enCode = a.EnCode, type = c.FullName, department = b.FullName, enabledMark = a.EnabledMark, creatorTime = a.CreatorTime, description = a.Description, sortCode = a.SortCode }).ToListAsync(); return new { list = data.OrderBy(x => x.sortCode).ToList() }; } /// /// 获取下拉框(公司+部门+岗位). /// /// [HttpGet("Selector")] public async Task GetSelector() { var orgInfoList = _organizeService.GetOrgListTreeName(); List? organizeList = await _organizeService.GetListAsync(); List? positionList = await _repository.AsQueryable().Where(t => t.EnabledMark == 1 && t.DeleteMark == null) .OrderBy(o => o.SortCode).OrderBy(a => a.CreatorTime, OrderByType.Desc).OrderBy(a => a.LastModifyTime, OrderByType.Desc).ToListAsync(); List? treeList = new List(); organizeList.ForEach(item => { treeList.Add( new PositionSelectorOutput { id = item.Id, parentId = item.ParentId, fullName = item.FullName, enabledMark = item.EnabledMark, icon = item.Category.Equals("department") ? "icon-ym icon-ym-tree-department1" : "icon-ym icon-ym-tree-organization3", type = item.Category, organize = orgInfoList.Find(x => x.Id.Equals(item.Id)).Description, organizeIdTree = item.OrganizeIdTree, num = positionList.Count(x => x.OrganizeId.Equals(item.Id)), sortCode = item.SortCode }); }); positionList.ForEach(item => { treeList.Add( new PositionSelectorOutput { id = item.Id, parentId = item.OrganizeId, fullName = item.FullName, enabledMark = item.EnabledMark, organize = orgInfoList.FirstOrDefault(x => x.Id.Equals(item.OrganizeId))?.Description, icon = "icon-ym icon-ym-tree-position1", type = "position", num = 1, sortCode = -2 }); }); treeList.Where(x => !x.type.Equals("position")).ToList().ForEach(item => { if (treeList.Any(x => !x.type.Equals("position") && x.num > 0 && x.organizeIdTree.Contains(item.organizeIdTree))) item.num = 1; else item.num = 0; }); return new { list = treeList.Where(x => x.num > 0).OrderBy(x => x.sortCode).ToList().ToTree("-1") }; } /// /// 获取信息. /// /// 主键. /// [HttpGet("{id}")] public async Task GetInfo(string id) { PositionEntity? entity = await _repository.GetSingleAsync(p => p.Id == id); var res = entity.Adapt(); res.organizeIdTree = (await _organizeService.GetInfoById(entity.OrganizeId)).OrganizeIdTree.Split(",").ToList(); return res; } #endregion #region POST /// /// 获取岗位列表 根据组织Id集合. /// /// 参数. /// [HttpPost("getListByOrgIds")] public async Task GetListByOrgIds([FromBody] PositionListQuery input) { List? data = await _repository.AsSugarClient().Queryable( (a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) .Where(a => input.organizeIds.Contains(a.OrganizeId) && a.DeleteMark == null && a.EnabledMark == 1).OrderBy(a => a.SortCode) .Select((a, b, c) => new PositionListOutput { id = a.Id, type = "position", parentId = b.Id, fullName = a.FullName, enabledMark = a.EnabledMark, creatorTime = a.CreatorTime, sortCode = -2, isLeaf = true }).ToListAsync(); // 获取所有组织 List? allOrgList = await _repository.AsSugarClient().Queryable().OrderBy(x => x.CreatorTime, OrderByType.Asc).ToListAsync(); allOrgList.ForEach(item => { item.ParentId = "0"; if (item.OrganizeIdTree == null || item.OrganizeIdTree.Equals(string.Empty)) item.OrganizeIdTree = item.Id; }); List? organizeList = allOrgList.Where(x => input.organizeIds.Contains(x.Id)).Select(x => new PositionListOutput() { id = x.Id, type = x.Category, parentId = "0", fullName = string.Join("/", allOrgList.Where(all => x.OrganizeIdTree.Split(",").Contains(all.Id)).Select(x => x.FullName)), num = data.Count(x => x.parentId == x.id) }).ToList(); return new { list = organizeList.Union(data).OrderBy(x => x.sortCode).ToList().ToTree("0") }; } /// /// 通过部门、岗位id获取岗位列表. /// /// 参数. /// [HttpPost("PositionCondition")] public async Task PositionCondition([FromBody] PositionConditionInput input) { List? data = await _repository.AsSugarClient().Queryable( (a, b, c) => new JoinQueryInfos(JoinType.Left, b.Id == a.OrganizeId, JoinType.Left, a.Type == c.EnCode && c.DictionaryTypeId == "dae93f2fd7cd4df999d32f8750fa6a1e")) .Where(a => a.DeleteMark == null) .Where(a => input.departIds.Contains(a.OrganizeId) || input.positionIds.Contains(a.Id)) .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.FullName.Contains(input.keyword) || a.EnCode.Contains(input.keyword)) .Select((a, b, c) => new PositionListOutput { id = a.Id, organizeId = a.OrganizeId, parentId = b.Id, type = "position", fullName = a.FullName, enabledMark = a.EnabledMark, creatorTime = a.CreatorTime, icon = "icon-ym icon-ym-tree-position1", sortCode = -2, num = 1, isLeaf = true }).ToListAsync(); // 获取所有组织 List? allOrgList = _organizeService.GetOrgListTreeName(); List? organizeList = allOrgList.Where(x => data.Select(x => x.organizeId).Distinct().Contains(x.Id)).Select(x => new PositionListOutput() { id = x.Id, type = x.Category, parentId = x.ParentId.Equals("-1") ? "0" : x.ParentId, icon = x.Category.Equals("department") ? "icon-ym icon-ym-tree-department1" : "icon-ym icon-ym-tree-organization3", fullName = x.Description, organizeId = x.OrganizeIdTree, num = data.Count(xx => xx.parentId == x.Id), sortCode = 99 }).ToList(); organizeList.OrderByDescending(x => x.organizeId.Length).ToList().ForEach(item => { if (!organizeList.Any(x => item.parentId.Equals(x.id))) item.parentId = "0"; var pOrgTree = organizeList.Where(x => x.organizeId != item.organizeId && item.organizeId.Contains(x.organizeId)).FirstOrDefault()?.fullName; if (organizeList.Any(x => item.parentId.Equals(x.id))) pOrgTree = organizeList.FirstOrDefault(x => item.parentId.Equals(x.id))?.fullName; if (pOrgTree.IsNotEmptyOrNull() && item.organizeId.IsNotEmptyOrNull()) item.fullName = item.fullName.Replace(pOrgTree + "/", string.Empty); }); organizeList.Where(x => !x.type.Equals("position")).ToList().ForEach(item => { if (organizeList.Any(x => !x.type.Equals("position") && x.num > 0 && x.organizeId.Contains(item.organizeId))) item.num = 1; else item.num = 0; organizeList.Where(x => !x.type.Equals("position") && x.organizeId.Contains(item.organizeId) && x.organizeId != item.organizeId).ToList().ForEach(it => { it.parentId = item.id; }); }); return new { list = organizeList.Where(x => x.num > 0).ToList().Union(data).OrderBy(x => x.sortCode).ToList().ToTree("0") }; } /// /// 新建. /// /// 参数. /// [HttpPost("")] public async Task Create([FromBody] PositionCrInput input) { if (!_userManager.DataScope.Any(it => it.organizeId == input.organizeId && it.Add == true) && !_userManager.IsAdministrator) throw Oops.Oh(ErrorCode.D1013); if (await _repository.IsAnyAsync(p => p.OrganizeId == input.organizeId && p.FullName == input.fullName && p.DeleteMark == null)) throw Oops.Oh(ErrorCode.D6005); if (await _repository.IsAnyAsync(p => p.EnCode == input.enCode && p.DeleteMark == null)) throw Oops.Oh(ErrorCode.D6000); PositionEntity? entity = input.Adapt(); int isOk = await _repository.AsSugarClient().Insertable(entity).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); if (!(isOk > 0)) throw Oops.Oh(ErrorCode.D6001); await DelPosition(string.Format("{0}_{1}", _userManager.TenantId, _userManager.UserId)); } /// /// 删除. /// /// 主键. /// [HttpDelete("{id}")] public async Task Delete(string id) { PositionEntity? entity = await _repository.GetSingleAsync(p => p.Id == id && p.DeleteMark == null); if (!_userManager.DataScope.Any(it => it.organizeId == entity.OrganizeId && it.Delete == true) && !_userManager.IsAdministrator) throw Oops.Oh(ErrorCode.D1013); // 岗位下有用户不能删 if (await _repository.AsSugarClient().Queryable().AnyAsync(u => u.ObjectType == "Position" && u.ObjectId == id)) throw Oops.Oh(ErrorCode.D6007); int isOk = await _repository.AsSugarClient().Updateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandAsync(); if (!(isOk > 0)) throw Oops.Oh(ErrorCode.D6002); await DelPosition(string.Format("{0}_{1}", _userManager.TenantId, _userManager.UserId)); } /// /// 更新. /// /// 主键. /// 参数. /// [HttpPut("{id}")] public async Task Update(string id, [FromBody] PositionUpInput input) { PositionEntity? oldEntity = await _repository.GetSingleAsync(it => it.Id == id); if (oldEntity.OrganizeId != input.organizeId && !_userManager.DataScope.Any(it => it.organizeId == oldEntity.OrganizeId && it.Edit == true) && !_userManager.IsAdministrator) throw Oops.Oh(ErrorCode.D1013); if (!_userManager.DataScope.Any(it => it.organizeId == input.organizeId && it.Edit == true) && !_userManager.IsAdministrator) throw Oops.Oh(ErrorCode.D1013); if (await _repository.IsAnyAsync(p => p.OrganizeId == input.organizeId && p.FullName == input.fullName && p.DeleteMark == null && p.Id != id)) throw Oops.Oh(ErrorCode.D6005); if (await _repository.IsAnyAsync(p => p.EnCode == input.enCode && p.DeleteMark == null && p.Id != id)) throw Oops.Oh(ErrorCode.D6000); // 如果变更组织,该岗位下已存在成员,则不允许修改 if (input.organizeId != oldEntity.OrganizeId) { if (await _repository.AsSugarClient().Queryable().AnyAsync(u => u.ObjectType == "Position" && u.ObjectId == id)) throw Oops.Oh(ErrorCode.D6008); } PositionEntity? entity = input.Adapt(); int isOk = await _repository.AsSugarClient().Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync(); if (!(isOk > 0)) throw Oops.Oh(ErrorCode.D6003); await DelPosition(string.Format("{0}_{1}", _userManager.TenantId, _userManager.UserId)); } /// /// 更新状态. /// /// 主键. /// [HttpPut("{id}/Actions/State")] public async Task UpdateState(string id) { if (!_userManager.DataScope.Any(it => it.organizeId == id && it.Add == true) && !_userManager.IsAdministrator) throw Oops.Oh(ErrorCode.D1013); if (!await _repository.IsAnyAsync(r => r.Id == id && r.DeleteMark == null)) throw Oops.Oh(ErrorCode.D6006); int isOk = await _repository.AsSugarClient().Updateable().UpdateColumns(it => new PositionEntity() { EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1), LastModifyUserId = _userManager.UserId, LastModifyTime = SqlFunc.GetDate() }).Where(it => it.Id == id).ExecuteCommandAsync(); if (!(isOk > 0)) throw Oops.Oh(ErrorCode.D6004); await DelPosition(string.Format("{0}_{1}", _userManager.TenantId, _userManager.UserId)); } #endregion #region PublicMethod /// /// 获取信息. /// /// 主键. /// [NonAction] public async Task GetInfoById(string id) { return await _repository.GetSingleAsync(p => p.Id == id); } /// /// 获取岗位列表. /// /// [NonAction] public async Task> GetListAsync() { return await _repository.AsQueryable().Where(u => u.DeleteMark == null).ToListAsync(); } /// /// 名称. /// /// 岗位ID组 /// [NonAction] public string GetName(string ids) { if (ids.IsNullOrEmpty()) return string.Empty; List? idList = ids.Split(",").ToList(); List? nameList = new List(); List? roleList = _repository.AsQueryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).ToList(); foreach (string item in idList) { var info = roleList.Find(x => x.Id == item); if (info != null && info.FullName.IsNotEmptyOrNull()) { nameList.Add(info.FullName); } } return string.Join(",", nameList); } #endregion #region PrivateMethod /// /// 删除岗位缓存. /// /// 适配多租户模式(userId:tenantId_userId). /// private async Task DelPosition(string userId) { string? cacheKey = string.Format("{0}{1}", CommonConst.CACHEKEYPOSITION, userId); await _cacheManager.DelAsync(cacheKey); return await Task.FromResult(true); } #endregion }