using CloudBuilder.Core.DatabaseAccessor; using CloudBuilder.Core.DatabaseAccessor.Entity; using CloudBuilder.Core.Service; using CloudBuilder.Master.Data; using CloudBuilder.Master.Entity; using CloudBuilder.Master.Policy; using CloudBuilder.Master.SearchCriteria; using CloudBuilder.Master.Service.FamilyTreeUtility; using CloudBuilder.Security.Data; using CloudBuilder.Security.Entity; using CloudBuilder.Security.Policy; using CloudBuilder.Security.Service; using CloudBuilder.Security.Utility; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; namespace CloudBuilder.Master.Service { public class FamilyTreeService : IFamilyTreeService { /// 头像上传目录,与前端 FileUpload 的 file-path 保持一致 private const string AVATAR_FOLDER_NAME = "FamilyPersonAvatar"; private readonly IApplicationService service; private IRepository repository; public FamilyTreeService(IApplicationService service) { this.service = service; repository = service.GetRepository>(); } /// 把 AvatarFilename 拼装成可访问的 AvatarUrl,供谱系图卡片显示头像 private void FillAvatarUrl(FamilyPersonDisplayData person) { if (person == null) return; person.AvatarUrl = FileTypePolicy.PackAvatarUrl(service, AVATAR_FOLDER_NAME, person.AvatarFilename); } /// 批量填充头像访问地址 private void FillAvatarUrl(FamilyPersonDisplayData[] persons) { if (persons == null || persons.Length == 0) return; foreach (FamilyPersonDisplayData person in persons) { FillAvatarUrl(person); } } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] public FamilyTreeData FindAllByTreeId(string treeId) { FamilyTreeData data = new FamilyTreeData(); if (string.IsNullOrEmpty(treeId)) return data; FamilyTreeEntity d = repository.DetachedEntities.Where(x => x.TreeId == treeId).FirstOrDefault(); if (d == null) return data; data.FamilyTree = new FamilyTreeDisplayData(d); data.CurrentPerson = new FamilyPersonData(); IRepository repositoryFamilyPerson = repository.GetRepository>(); var currentPerson = d.AncestorPersonId; data.CurrentPerson.FamilyPerson = new FamilyPersonDisplayData(repositoryFamilyPerson.DetachedEntities.Where(x => x.PersonId == currentPerson).FirstOrDefault()!); FillAvatarUrl(data.CurrentPerson.FamilyPerson); data.FamilyTree.AncestorPersonGenealogyName = data.CurrentPerson.FamilyPerson.GenealogyName; IRepository repositoryChildrenMap = repository.GetRepository>(); IRepository repositorySpouseMap = repository.GetRepository>(); data.CurrentPerson.FamilyTreeSpouseMaps = repositorySpouseMap.GetRepository>().DetachedEntities.Where(x => x.TreeId == treeId).OrderBy(x => x.Orderby).ToArray(); data.CurrentPerson.FamilyTreeChildrenMaps = repositoryChildrenMap.GetRepository>().DetachedEntities.Where(x => x.TreeId == treeId).OrderBy(x => x.Orderby).ToArray(); List ps = new List(); ps.Add(d.AncestorPersonId); if (data.CurrentPerson.FamilyTreeSpouseMaps != null && data.CurrentPerson.FamilyTreeSpouseMaps.Length > 0) { ps.AddRange(data.CurrentPerson.FamilyTreeSpouseMaps.Select(x => x.SpouseId).ToArray()); } if (data.CurrentPerson.FamilyTreeChildrenMaps != null && data.CurrentPerson.FamilyTreeChildrenMaps.Length > 0) { ps.AddRange(data.CurrentPerson.FamilyTreeChildrenMaps.Select(x => x.ChildrenId).ToArray()); } ps = ps.Distinct().ToList(); FamilyPersonEntity[] families = repositoryFamilyPerson.DetachedEntities.Where(x => ps.AsQueryable().Contains(x.PersonId)).ToArray(); if (families != null && families.Length > 0) { data.CurrentPerson.FamilyTreePersons = families.Select(x => new FamilyPersonDisplayData(x)).ToArray(); FillAvatarUrl(data.CurrentPerson.FamilyTreePersons); } return data; } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] public FamilyTreeData FindByKey(string key) { return FindByCurrentPerson(key, null); } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] public FamilyTreeData FindByCurrentPerson(string key, string personId) { FamilyTreeData data = new FamilyTreeData(); if (string.IsNullOrEmpty(key)) return data; FamilyTreeEntity d = repository.DetachedEntities.Where(x => x.TreeId == key).FirstOrDefault(); if (d == null) return data; IRepository repositoryPermission = repository.GetRepository>(); data.FamilyTree = new FamilyTreeDisplayData(d); data.CurrentPerson = new FamilyPersonData(); data.FamilyTreePermissions = repositoryPermission.DetachedEntities.Where(x => x.TreeId == key).ToArray(); if (data.FamilyTreePermissions.Any()) { data.IsManager = data.FamilyTreePermissions.Where(x => x.UserName == service.UserId && x.ManagerIndc == YesNoPolicy.YES).Any(); if (data.IsManager) data.IsCanAmend = true; // 成员口径:有绑定到自己且已生效的权限行即算(与锚点是否可编无关,供前端选项卡级控权);需在下方过滤名单前算,否则非管理员只剩待审行 var selfValidRows = data.FamilyTreePermissions.Where(x => x.UserName == service.UserId && x.ValidIndc == YesNoPolicy.YES).ToArray(); data.IsMember = selfValidRows.Any(); // 自己绑定的族员(供前端切换「绑定账号/解除绑定」按钮),管理员无绑定概念不下发 if (!data.IsManager) data.SelfBindPersonId = selfValidRows.Select(x => x.PersonId).FirstOrDefault() ?? ""; } if (!data.IsManager && data.FamilyTreePermissions.Any()) { data.FamilyTreePermissions = data.FamilyTreePermissions.Where(x => x.UserName == service.UserId && x.ValidIndc == YesNoPolicy.NO).ToArray(); } IRepository repositoryFamilyPerson = repository.GetRepository>(); var currentPerson = personId; if (string.IsNullOrEmpty(personId)) { currentPerson = d.AncestorPersonId; data.CurrentPerson.FamilyPerson = new FamilyPersonDisplayData(repositoryFamilyPerson.DetachedEntities.Where(x => x.PersonId == currentPerson).FirstOrDefault()!); data.FamilyTree.AncestorPersonGenealogyName = data.CurrentPerson.FamilyPerson.GenealogyName; } else { data.CurrentPerson.FamilyPerson = new FamilyPersonDisplayData(repositoryFamilyPerson.DetachedEntities.Where(x => x.PersonId == d.AncestorPersonId).FirstOrDefault()!); data.FamilyTree.AncestorPersonGenealogyName = data.CurrentPerson.FamilyPerson.GenealogyName; data.CurrentPerson.FamilyPerson = new FamilyPersonDisplayData(repositoryFamilyPerson.DetachedEntities.Where(x => x.PersonId == personId).FirstOrDefault()!); } FillAvatarUrl(data.CurrentPerson.FamilyPerson); IRepository repositoryChildrenMap = repository.GetRepository>(); IRepository repositorySpouseMap = repository.GetRepository>(); data.CurrentPerson.FamilyTreeSpouseMaps = repositorySpouseMap.GetRepository>().DetachedEntities.Where(x => x.PersonId == currentPerson && x.TreeId == d.TreeId).OrderBy(x => x.Orderby).ToArray(); //data.CurrentPerson.FamilyTreeParentMaps = repositoryChildrenMap.GetRepository>().DetachedEntities.Where(x => x.ChildrenId == key).OrderBy(x => x.Orderby).ToArray(); data.CurrentPerson.FamilyTreeChildrenMaps = repositoryChildrenMap.GetRepository>().DetachedEntities.Where(x => x.PersonId == currentPerson && x.TreeId == d.TreeId).OrderBy(x => x.Orderby).ToArray(); // 补充当前人员及其配偶、子女的人员信息(含头像地址),供谱系图卡片显示头像 List ps = new List(); if (!string.IsNullOrEmpty(currentPerson)) ps.Add(currentPerson); // 始祖恒定并入下发集合:切换当前族员后,前端「始祖信息」卡仍需回查始祖档案(Distinct 去重) if (!string.IsNullOrEmpty(d.AncestorPersonId)) ps.Add(d.AncestorPersonId); if (data.CurrentPerson.FamilyTreeSpouseMaps != null) { ps.AddRange(data.CurrentPerson.FamilyTreeSpouseMaps.Select(x => x.SpouseId).ToArray()); } if (data.CurrentPerson.FamilyTreeChildrenMaps != null) { ps.AddRange(data.CurrentPerson.FamilyTreeChildrenMaps.Select(x => x.ChildrenId).ToArray()); } ps = ps.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); FamilyPersonEntity[] families = repositoryFamilyPerson.DetachedEntities.Where(x => ps.AsQueryable().Contains(x.PersonId)).ToArray(); if (families != null && families.Length > 0) { data.CurrentPerson.FamilyTreePersons = families.Select(x => new FamilyPersonDisplayData(x)).ToArray(); FillAvatarUrl(data.CurrentPerson.FamilyTreePersons); } if (!data.IsCanAmend) data.IsCanAmend = new FamilyTreePermissionHelper(service).HasPermission(data.FamilyTree.TreeId, currentPerson); // 逐个目标人的可编集合(关系行里的旁支靠它隐藏编辑/删除钮);管理员全量可编不限量不下发 if (!data.IsManager && data.IsMember) data.CanAmendPersonIds = new FamilyTreePermissionHelper(service).GetAmendablePersonIds(data.FamilyTree.TreeId).ToArray(); return data; } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] public FamilyTreeResultData FindBySearchCriteria(FamilyTreeSearchCriteria criteria) { FamilyTreeResultData data = new FamilyTreeResultData(); FamilyTreeViewEntity[] list = null; Int64 count = 0; string sqlWhere = null; if (criteria.Filter != null && criteria.Filter.Length > 0) { sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter); } FamilyTreeViewEntity entity = FamilyTreeViewEntity.GetInstance(repository.GetDbContext().Database.ProviderName); string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere); IRepository repositoryView = repository.GetRepository>(); string err = null; try { list = repositoryView.FromSql(sql).ToArray(); } catch (System.Exception ex) { err = ex.Message; } if (list != null && list.Length > 0) { sql = entity.GetSelectCountFrom(sqlWhere); count = Convert.ToInt64(repository.ExecuteScalar(sql)); } data.Limit = criteria.limit; data.Page = criteria.page; data.Datas = list; data.Total = count; //data.Sql = sql; data.ErrorMessage = err; return data; } //[PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Print)] public dynamic PrintBySearchCriteria(FamilyTreeSearchCriteria criteria) { throw new NotImplementedException(); } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Insert)] [UnitOfWork] public FamilyTreeData Insert(FamilyTreeData data) { FamilyTreeEntity d = repository.DetachedEntities.Where(x => x.TreeName == data.FamilyTree.TreeName).FirstOrDefault(); if (d != null) { throw new ValidatedException("家族名称已存在."); } Validate(data.FamilyTree); d = new FamilyTreeEntity(); ObjectCopyHelper.Copy(data.FamilyTree, d); ISecurityGeneratorNumberService securityGeneratorNumberService = service.ServiceProvider.GetService()!; d.TreeId = securityGeneratorNumberService.GetNo(MasterPrefixPolicy.FAMILY_TREE, MasterPrefixPolicy.FAMILY_TREE_TREE_ID, MasterPrefixPolicy.FAMILY_TREE_PREFIX, YesNoPolicy.NO, MasterPrefixPolicy.FAMILY_TREE_FORMAT); repository.InsertNow(d); FamilyTreePermissionEntity treePermissionEntity = new FamilyTreePermissionEntity(); treePermissionEntity.TreeId = d.TreeId; treePermissionEntity.PersonId = d.AncestorPersonId; treePermissionEntity.UserName = service.UserId; treePermissionEntity.ManagerIndc = YesNoPolicy.YES; treePermissionEntity.ValidIndc = YesNoPolicy.YES; InsertFamilyTreePermission(treePermissionEntity); IRepository repositoryPerson = repository.GetRepository>(); FamilyPersonEntity familyPerson; familyPerson = repositoryPerson.DetachedEntities.Where(x => x.PersonId == d.AncestorPersonId).FirstOrDefault()!; familyPerson.TreeId = d.TreeId; repositoryPerson.UpdateNow(familyPerson); var currentPerson = d.AncestorPersonId; if (data.CurrentPerson != null && data.CurrentPerson.FamilyPerson != null && !string.IsNullOrEmpty(data.CurrentPerson.FamilyPerson.PersonId)) { currentPerson = data.CurrentPerson.FamilyPerson.PersonId; } if (data.CurrentPerson != null && data.CurrentPerson.FamilyTreeSpouseMaps != null && data.CurrentPerson.FamilyTreeSpouseMaps.Length > 0) data.CurrentPerson.FamilyTreeSpouseMaps.ToLookup(x => x.TreeId = d.TreeId); if (data.CurrentPerson != null && data.CurrentPerson.FamilyTreeChildrenMaps != null && data.CurrentPerson.FamilyTreeChildrenMaps.Length > 0) data.CurrentPerson.FamilyTreeChildrenMaps.ToLookup(x => x.TreeId = d.TreeId); SaveSpouseMaps(d.TreeId, currentPerson, data.CurrentPerson.FamilyTreeSpouseMaps); //SaveParentMaps(data.CurrentPerson.FamilyPerson.PersonId, data.CurrentPerson.FamilyTreeParentMaps); SaveSonMaps(d.TreeId, currentPerson, data.CurrentPerson.FamilyTreeChildrenMaps); return FindByCurrentPerson(d.TreeId, currentPerson); } public void InsertFamilyTreePermission(FamilyTreePermissionEntity treePermissionEntity) { IRepository repositoryPermission = repository.GetRepository>(); repositoryPermission.InsertNow(treePermissionEntity); } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] [UnitOfWork] public void RequestFamilyTreePermission(string treeId, string currentPersonId) { IRepository repositoryPermission = repository.GetRepository>(); // 一人一谱一行:PersonId 不再参与定位与绑定(申请锚点≠本人),查重按 TreeId+UserName FamilyTreePermissionEntity treePermissionEntity = repositoryPermission.DetachedEntities.Where(x => x.TreeId == treeId && service.UserId == x.UserName).FirstOrDefault()!; if (treePermissionEntity != null) return; treePermissionEntity = new FamilyTreePermissionEntity(); treePermissionEntity.TreeId = treeId; // 申请时不绑定任何族员(旧口径把申请锚点——往往是始祖——绑了进去,导致成员误得大支系); // 绑定时机:审批时按中文姓名同名唯一自动绑,或通过后由用户自行「绑定账号」 treePermissionEntity.PersonId = ""; treePermissionEntity.UserName = service.UserId; treePermissionEntity.ManagerIndc = YesNoPolicy.NO; treePermissionEntity.ValidIndc = YesNoPolicy.NO; InsertFamilyTreePermission(treePermissionEntity); } /// /// PersonId 属复合主键 (PersonId,TreeId,UserName),EF 分离实体直接改主键列更新不可靠,换绑一律删旧行插新行 /// private void RebindFamilyTreePermission(FamilyTreePermissionEntity row, string personId) { IRepository repositoryPermission = repository.GetRepository>(); FamilyTreePermissionEntity fresh = new FamilyTreePermissionEntity(); fresh.TreeId = row.TreeId; fresh.UserName = row.UserName; fresh.PersonId = personId; fresh.ManagerIndc = row.ManagerIndc; fresh.ValidIndc = row.ValidIndc; repositoryPermission.DeleteNow(row); repositoryPermission.InsertNow(fresh); } /// /// 用户中文姓名(security_user.user_local_name);登录账号只是标识,不参与同名比较 /// private string GetUserLocalName(string userName) { IRepository repositoryUser = repository.GetRepository>(); return repositoryUser.DetachedEntities.Where(x => x.UserName == userName).FirstOrDefault()?.UserLocalName ?? ""; } /// /// 同名口径:族员「姓+谱名」组合或常用名与用户中文姓名相同 /// private bool IsMatchedByLocalName(FamilyPersonEntity person, string localName) { if (string.IsNullOrEmpty(localName)) return false; return (person.Surname ?? "") + (person.GenealogyName ?? "") == localName || person.CommonName == localName; } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] [UnitOfWork] public void ApproveFamilyTreePermission(string treeId, string currentPersonId, string userName, string managerIndc) { IRepository repositoryPermission = repository.GetRepository>(); // 行定位不再用 PersonId(申请行已不绑族员,旧数据也可能已换绑),TreeId+UserName 即唯一行 FamilyTreePermissionEntity treePermissionEntity = repositoryPermission.DetachedEntities.Where(x => x.TreeId == treeId && userName == x.UserName).FirstOrDefault()!; if (treePermissionEntity == null) return; treePermissionEntity.ManagerIndc = managerIndc; treePermissionEntity.ValidIndc = YesNoPolicy.YES; // 通过为成员:不绑始祖;用户中文姓名与「姓+谱名」或常用名相同且全谱唯一才自动绑定,否则留空由用户自行「绑定账号」 if (managerIndc != YesNoPolicy.YES) { string localName = GetUserLocalName(userName); IRepository repositoryPerson = repository.GetRepository>(); // 姓+谱名是运行时拼接,EF 翻不动就拉全谱内存筛(单谱人数量级小) FamilyPersonEntity[] matches = repositoryPerson.DetachedEntities.Where(x => x.TreeId == treeId).ToArray() .Where(x => IsMatchedByLocalName(x, localName)).ToArray(); string boundPersonId = matches.Length == 1 ? matches[0].PersonId : ""; if (treePermissionEntity.PersonId != boundPersonId) { RebindFamilyTreePermission(treePermissionEntity, boundPersonId); return; } } repositoryPermission.UpdateNow(treePermissionEntity); } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] [UnitOfWork] public void RejectFamilyTreePermission(string treeId, string currentPersonId, string userName) { IRepository repositoryPermission = repository.GetRepository>(); FamilyTreePermissionEntity treePermissionEntity = repositoryPermission.DetachedEntities.Where(x => x.TreeId == treeId && userName == x.UserName).FirstOrDefault()!; if (treePermissionEntity == null) return; repositoryPermission.DeleteNow(treePermissionEntity); } /// /// 绑定账号:把当前族员绑到自己已生效的权限行(仅限与登录中文姓名同名的族员); /// 返回绑定后的详情数据(锚点切到刚绑的族员) /// [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] [UnitOfWork] public FamilyTreeData BindSelfPerson(string treeId, string personId) { IRepository repositoryPermission = repository.GetRepository>(); FamilyTreePermissionEntity row = repositoryPermission.DetachedEntities.Where(x => x.TreeId == treeId && x.UserName == service.UserId && x.ValidIndc == YesNoPolicy.YES).FirstOrDefault()!; if (row == null) throw new ValidatedException("您还未通过审批,不能绑定账号."); IRepository repositoryPerson = repository.GetRepository>(); FamilyPersonEntity person = repositoryPerson.DetachedEntities.Where(x => x.TreeId == treeId && x.PersonId == personId).FirstOrDefault()!; if (person == null) throw new ValidatedException("族员不存在."); // 同名口径:族员「姓+谱名」组合或常用名与登录中文姓名相同才可绑定(与管理员审批自动绑定同一把尺) if (!IsMatchedByLocalName(person, GetUserLocalName(service.UserId))) throw new ValidatedException("只能绑定与您的中文姓名同名的族员."); if (row.PersonId != personId) RebindFamilyTreePermission(row, personId); return FindByCurrentPerson(treeId, personId); } /// /// 解除绑定:把自己已生效权限行的 PersonId 置空(锚点回到始祖),解绑后可重新「绑定账号」 /// [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] [UnitOfWork] public FamilyTreeData UnbindSelfPerson(string treeId) { IRepository repositoryPermission = repository.GetRepository>(); FamilyTreePermissionEntity row = repositoryPermission.DetachedEntities.Where(x => x.TreeId == treeId && x.UserName == service.UserId && x.ValidIndc == YesNoPolicy.YES).FirstOrDefault()!; if (row == null) throw new ValidatedException("您还未通过审批,不能解除绑定."); if (!string.IsNullOrEmpty(row.PersonId)) RebindFamilyTreePermission(row, ""); return FindByCurrentPerson(treeId, ""); } private void SaveSpouseMaps(string treeId, string personId, FamilyTreeSpouseMapViewEntity[] maps) { IRepository repositoryMapView = repository.GetRepository>(); IRepository repositoryMap = repository.GetRepository>(); IRepository repositoryPerson = repository.GetRepository>(); FamilyPersonEntity familyPerson; FamilyTreeSpouseMapViewEntity[] olds = repositoryMapView.Entities.Where(x => x.TreeId == treeId && x.PersonId == personId).ToArray(); if (olds != null && olds.Length > 0) { foreach (FamilyTreeSpouseMapViewEntity old in olds) { // 仅当新载荷不再保留该配偶时才连带删其人员档案;原写法误用 old.PersonId(父辈本人), // 会把父辈 family_person 行删掉,导致子女 view 联查丢行、SaveSonMaps 查不到旧行不删,重插同主键报 Duplicate entry if (maps == null || !maps.Any(m => m.SpouseId == old.SpouseId)) { familyPerson = repositoryPerson.DetachedEntities.Where(x => x.PersonId == old.SpouseId).FirstOrDefault()!; if (familyPerson != null) { repositoryPerson.DeleteNow(familyPerson); } } repositoryMap.DeleteNow(new FamilyTreeSpouseMapEntity() { TreeId = old.TreeId, PersonId = personId, SpouseId = old.SpouseId }); } } if (maps == null || maps.Length == 0) return; int i = 1; foreach (FamilyTreeSpouseMapViewEntity map in maps.OrderBy(x => x.Orderby).ToArray()) { familyPerson = repositoryPerson.DetachedEntities.Where(x => x.PersonId == map.PersonId && string.IsNullOrEmpty(x.TreeId)).FirstOrDefault()!; if (familyPerson != null) { familyPerson.TreeId = map.TreeId; repositoryPerson.Update(familyPerson); } repositoryMap.InsertNow(new FamilyTreeSpouseMapEntity() { TreeId = map.TreeId, PersonId = personId, SpouseId = map.SpouseId, MarryDateText = map.MarryDateText, MarryDate = map.MarryDate, DivorceDateText = map.DivorceDateText, DivorceDate = map.DivorceDate, MarryType = map.MarryType, IsCurrent = map.IsCurrent, Remark = map.Remark, Orderby = i++ }); } } private void SaveSonMaps(string treeId, string personId, FamilyTreeChildrenMapViewEntity[] maps) { IRepository repositoryMapView = repository.GetRepository>(); IRepository repositoryMap = repository.GetRepository>(); IRepository repositoryPerson = repository.GetRepository>(); FamilyPersonEntity familyPerson; FamilyTreeChildrenMapViewEntity[] olds = repositoryMapView.Entities.Where(x => x.TreeId == treeId && x.PersonId == personId).ToArray(); if (olds != null && olds.Length > 0) { foreach (FamilyTreeChildrenMapViewEntity old in olds) { // 同 SaveSpouseMaps:只在该子女不再被新载荷保留时才连带删档案,且删的是子女而非父辈 if (maps == null || !maps.Any(m => m.ChildrenId == old.ChildrenId)) { familyPerson = repositoryPerson.DetachedEntities.Where(x => x.PersonId == old.ChildrenId).FirstOrDefault()!; if (familyPerson != null) { repositoryPerson.DeleteNow(familyPerson); } } repositoryMap.DeleteNow(new FamilyTreeChildrenMapEntity() { TreeId = old.TreeId, PersonId = personId, ChildrenId = old.ChildrenId }); } } if (maps == null || maps.Length == 0) return; int i = 1; foreach (FamilyTreeChildrenMapViewEntity map in maps.OrderBy(x => x.Orderby).ToArray()) { familyPerson = repositoryPerson.DetachedEntities.Where(x => x.PersonId == map.PersonId && string.IsNullOrEmpty(x.TreeId)).FirstOrDefault()!; if (familyPerson != null) { familyPerson.TreeId = map.TreeId; repositoryPerson.Update(familyPerson); } repositoryMap.InsertNow(new FamilyTreeChildrenMapEntity() { TreeId = map.TreeId, PersonId = personId, SpouseId = map.SpouseId, ChildrenId = map.ChildrenId, RelationType = map.RelationType, Remark = map.Remark, Orderby = i++ }); } } private void Validate(FamilyTreeEntity d) { List sysTableSchemas = service.ServiceProvider.GetRequiredService().FindByTableName(FamilyTreeEntity.DB_NAME_FAMILY_TREE); ValidateHelper.ValidateString(d, sysTableSchemas.ToArray()); } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Update)] [UnitOfWork] public FamilyTreeData Update(FamilyTreeData data) { FamilyTreeEntity d = null; if (data.FamilyTree.TreeName != data.FamilyTree.OrgTreeName) { d = repository.DetachedEntities.Where(x => x.TreeName == data.FamilyTree.TreeName).FirstOrDefault(); if (d != null) { throw new ValidatedException("家族名称已存在."); } } d = repository.DetachedEntities.Where(x => x.TreeId == data.FamilyTree.TreeId).FirstOrDefault(); Validate(data.FamilyTree); var helper = new FamilyTreePermissionHelper(service); var currentPerson = data.CurrentPerson != null ? data.CurrentPerson.FamilyPerson.PersonId : null; if (string.IsNullOrEmpty(currentPerson)) currentPerson = d.AncestorPersonId; // 谱级口径:管理员才能改谱字段(名/简介/公开开关/挂始祖); // 成员只准维护以自己当前族员为锚点的家支关系(锚点上溯两代内可能含始祖,HasPermission(始祖) 做不了谱级闸) var isManager = helper.IsManager(d.TreeId); if (!isManager) { if (!helper.HasPermission(d.TreeId, currentPerson)) { throw new ValidatedException("您没有修改权限."); } if (!string.IsNullOrEmpty(data.FamilyTree.AncestorPersonId) && data.FamilyTree.AncestorPersonId != d.AncestorPersonId) { throw new ValidatedException("您没有挂始祖权限."); } } if (isManager) { ObjectCopyHelper.Copy(data.FamilyTree, d); repository.UpdateNow(d); } if (data.CurrentPerson != null && data.CurrentPerson.FamilyTreeSpouseMaps != null && data.CurrentPerson.FamilyTreeSpouseMaps.Length > 0) data.CurrentPerson.FamilyTreeSpouseMaps.ToLookup(x => x.TreeId = d.TreeId); if (data.CurrentPerson != null && data.CurrentPerson.FamilyTreeChildrenMaps != null && data.CurrentPerson.FamilyTreeChildrenMaps.Length > 0) data.CurrentPerson.FamilyTreeChildrenMaps.ToLookup(x => x.TreeId = d.TreeId); SaveSpouseMaps(d.TreeId, data.CurrentPerson.FamilyPerson.PersonId, data.CurrentPerson.FamilyTreeSpouseMaps); //SaveParentMaps(data.CurrentPerson.FamilyPerson.PersonId, data.CurrentPerson.FamilyTreeParentMaps); SaveSonMaps(d.TreeId, data.CurrentPerson.FamilyPerson.PersonId, data.CurrentPerson.FamilyTreeChildrenMaps); return FindByCurrentPerson(data.FamilyTree.TreeId, currentPerson); } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Delete)] [UnitOfWork] public void Delete(string key) { var ent = repository.DetachedEntities.Where(x => x.TreeId == key).FirstOrDefault()!; if (ent == null) return; // 删谱属谱级操作,仅管理员:成员锚点若贴近始祖,HasPermission 也会为真,不能做闸 if (!new FamilyTreePermissionHelper(service).IsManager(ent.TreeId)) { throw new ValidatedException("您没有删除权限."); } repository.DeleteNow(ent); IRepository repositoryPerson = repository.GetRepository>(); FamilyPersonEntity familyPerson; familyPerson = repositoryPerson.DetachedEntities.Where(x => x.PersonId == ent.AncestorPersonId).FirstOrDefault()!; if (familyPerson != null) { repositoryPerson.DeleteNow(familyPerson); } DeleteSpouses(ent.AncestorPersonId); DeleteChildrens(ent.AncestorPersonId); } private void DeleteSpouses(string personId) { IRepository repositoryMap = repository.GetRepository>(); FamilyTreeSpouseMapEntity[] olds = repositoryMap.Entities.Where(x => x.PersonId == personId).ToArray(); if (olds != null && olds.Length > 0) { repositoryMap.DeleteNow(olds); } } private void DeleteChildrens(string personId) { IRepository repositoryMap = repository.GetRepository>(); FamilyTreeChildrenMapEntity[] olds = repositoryMap.Entities.Where(x => x.PersonId == personId).ToArray(); if (olds != null && olds.Length > 0) { repositoryMap.DeleteNow(olds); } foreach (FamilyTreeChildrenMapEntity old in olds) { DeleteChildrens(old.ChildrenId); DeleteSpouses(old.ChildrenId); } } [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Delete)] [UnitOfWork] public void Deletes(string[] keys) { foreach (string key in keys) { Delete(key); } } } }