Files
Docker/CloudBuilder/CloudBuilder.Master.Service/FamilyTreeService.auto.cs
T
2026-10-19 13:36:58 +08:00

723 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
/// <summary>头像上传目录,与前端 FileUpload 的 file-path 保持一致</summary>
private const string AVATAR_FOLDER_NAME = "FamilyPersonAvatar";
private readonly IApplicationService service;
private IRepository<FamilyTreeEntity> repository;
public FamilyTreeService(IApplicationService service)
{
this.service = service;
repository = service.GetRepository<IRepository<FamilyTreeEntity>>();
}
/// <summary>把 AvatarFilename 拼装成可访问的 AvatarUrl,供谱系图卡片显示头像</summary>
private void FillAvatarUrl(FamilyPersonDisplayData person)
{
if (person == null) return;
person.AvatarUrl = FileTypePolicy.PackAvatarUrl(service, AVATAR_FOLDER_NAME, person.AvatarFilename);
}
/// <summary>批量填充头像访问地址</summary>
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<FamilyPersonEntity> repositoryFamilyPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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<FamilyTreeChildrenMapViewEntity> repositoryChildrenMap = repository.GetRepository<IRepository<FamilyTreeChildrenMapViewEntity>>();
IRepository<FamilyTreeSpouseMapViewEntity> repositorySpouseMap = repository.GetRepository<IRepository<FamilyTreeSpouseMapViewEntity>>();
data.CurrentPerson.FamilyTreeSpouseMaps = repositorySpouseMap.GetRepository<IRepository<FamilyTreeSpouseMapViewEntity>>().DetachedEntities.Where(x => x.TreeId == treeId).OrderBy(x => x.Orderby).ToArray();
data.CurrentPerson.FamilyTreeChildrenMaps = repositoryChildrenMap.GetRepository<IRepository<FamilyTreeChildrenMapViewEntity>>().DetachedEntities.Where(x => x.TreeId == treeId).OrderBy(x => x.Orderby).ToArray();
List<string> ps = new List<string>();
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<FamilyTreePermissionUserViewEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionUserViewEntity>>();
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<FamilyPersonEntity> repositoryFamilyPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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<FamilyTreeChildrenMapViewEntity> repositoryChildrenMap = repository.GetRepository<IRepository<FamilyTreeChildrenMapViewEntity>>();
IRepository<FamilyTreeSpouseMapViewEntity> repositorySpouseMap = repository.GetRepository<IRepository<FamilyTreeSpouseMapViewEntity>>();
data.CurrentPerson.FamilyTreeSpouseMaps = repositorySpouseMap.GetRepository<IRepository<FamilyTreeSpouseMapViewEntity>>().DetachedEntities.Where(x => x.PersonId == currentPerson && x.TreeId == d.TreeId).OrderBy(x => x.Orderby).ToArray();
//data.CurrentPerson.FamilyTreeParentMaps = repositoryChildrenMap.GetRepository<IRepository<FamilyTreeChildrenMapViewEntity>>().DetachedEntities.Where(x => x.ChildrenId == key).OrderBy(x => x.Orderby).ToArray();
data.CurrentPerson.FamilyTreeChildrenMaps = repositoryChildrenMap.GetRepository<IRepository<FamilyTreeChildrenMapViewEntity>>().DetachedEntities.Where(x => x.PersonId == currentPerson && x.TreeId == d.TreeId).OrderBy(x => x.Orderby).ToArray();
// 补充当前人员及其配偶、子女的人员信息(含头像地址),供谱系图卡片显示头像
List<string> ps = new List<string>();
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<FamilyTreeViewEntity> repositoryView = repository.GetRepository<IRepository<FamilyTreeViewEntity>>();
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<ISecurityGeneratorNumberService>()!;
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<FamilyPersonEntity> repositoryPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
repositoryPermission.InsertNow(treePermissionEntity);
}
[PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)]
[UnitOfWork]
public void RequestFamilyTreePermission(string treeId, string currentPersonId)
{
IRepository<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
// 一人一谱一行: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);
}
/// <summary>
/// PersonId 属复合主键 (PersonId,TreeId,UserName),EF 分离实体直接改主键列更新不可靠,换绑一律删旧行插新行
/// </summary>
private void RebindFamilyTreePermission(FamilyTreePermissionEntity row, string personId)
{
IRepository<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
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);
}
/// <summary>
/// 用户中文姓名(security_user.user_local_name);登录账号只是标识,不参与同名比较
/// </summary>
private string GetUserLocalName(string userName)
{
IRepository<SecurityUserEntity> repositoryUser = repository.GetRepository<IRepository<SecurityUserEntity>>();
return repositoryUser.DetachedEntities.Where(x => x.UserName == userName).FirstOrDefault()?.UserLocalName ?? "";
}
/// <summary>
/// 同名口径:族员「姓+谱名」组合或常用名与用户中文姓名相同
/// </summary>
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<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
// 行定位不再用 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<FamilyPersonEntity> repositoryPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
// 姓+谱名是运行时拼接,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<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
FamilyTreePermissionEntity treePermissionEntity = repositoryPermission.DetachedEntities.Where(x => x.TreeId == treeId && userName == x.UserName).FirstOrDefault()!;
if (treePermissionEntity == null) return;
repositoryPermission.DeleteNow(treePermissionEntity);
}
/// <summary>
/// 绑定账号:把当前族员绑到自己已生效的权限行(仅限与登录中文姓名同名的族员);
/// 返回绑定后的详情数据(锚点切到刚绑的族员)
/// </summary>
[PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)]
[UnitOfWork]
public FamilyTreeData BindSelfPerson(string treeId, string personId)
{
IRepository<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
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<FamilyPersonEntity> repositoryPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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);
}
/// <summary>
/// 解除绑定:把自己已生效权限行的 PersonId 置空(锚点回到始祖),解绑后可重新「绑定账号」
/// </summary>
[PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)]
[UnitOfWork]
public FamilyTreeData UnbindSelfPerson(string treeId)
{
IRepository<FamilyTreePermissionEntity> repositoryPermission = repository.GetRepository<IRepository<FamilyTreePermissionEntity>>();
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<FamilyTreeSpouseMapViewEntity> repositoryMapView = repository.GetRepository<IRepository<FamilyTreeSpouseMapViewEntity>>();
IRepository<FamilyTreeSpouseMapEntity> repositoryMap = repository.GetRepository<IRepository<FamilyTreeSpouseMapEntity>>();
IRepository<FamilyPersonEntity> repositoryPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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<FamilyTreeChildrenMapViewEntity> repositoryMapView = repository.GetRepository<IRepository<FamilyTreeChildrenMapViewEntity>>();
IRepository<FamilyTreeChildrenMapEntity> repositoryMap = repository.GetRepository<IRepository<FamilyTreeChildrenMapEntity>>();
IRepository<FamilyPersonEntity> repositoryPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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<SysTableSchemaViewEntity> sysTableSchemas = service.ServiceProvider.GetRequiredService<ISysTableSchemaViewService>().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<FamilyPersonEntity> repositoryPerson = repository.GetRepository<IRepository<FamilyPersonEntity>>();
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<FamilyTreeSpouseMapEntity> repositoryMap = repository.GetRepository<IRepository<FamilyTreeSpouseMapEntity>>();
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<FamilyTreeChildrenMapEntity> repositoryMap = repository.GetRepository<IRepository<FamilyTreeChildrenMapEntity>>();
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);
}
}
}
}