Бывает, что в ходе проекта мы активно используем стандартные группы и орг. структуру для создания ролевой структуры. Очень удобно бывает использовать переменные типа "Роль", но стандартный функционал не позволяет нам, например получить пользователей из вложенной группы или вложенной орг. структуры из той же группы. Данная функция работает с применением рекурсии, но она ограничивается (бесконечная рекурсия невозможна). Думаю, данную функцию можно улучшить, предлагайте свои улучшения -)
Код:
// Метод получения пользователей из роли|группы|орг.структуры. Особенности:
// Метод возвращает пользователей из группы с учетом вложенности. Бесконечная рекурсия возможна, но она ограничивается значением limit_nesting (не советую ставить слишком высокое значение)
// Метод также успешно возвращает пользователей из вложенной в группу орг. структуры
// В случае если орг.структура это отдел, метод возвращает всех сотрудников из данного отдела. В случае если это группа или должность, то возвращает только пользователей по данным позициям
// В случае если в роли находится пользователь метод также успешно его вернёт
async function getUsersFromRole(outside_role : Role | UserGroupItemRef | OrganisationStructureItemRef) : Promise<UserItem[]> {
const limit_nesting = 10 // Максимальный уровень вложенности рекурсивных вызовов
//#region Разбиваем переменную типа "Role" на "UserGroupItemRef | OrganisationStructureItemRef" для более удобной работы
let user_component : UserGroupItemRef | OrganisationStructureItemRef
if ((outside_role as any).type === "group" || (outside_role as any).type === "orgstruct" || (outside_role as any).type === "user") { // Это роль - вытягиваем UserGroupItemRef | OrganisationStructureItemRef
let role : Role = (outside_role as any)
if (role.type === "group") {
user_component = (await System.userGroups.search().where((f,g) => g.and(f.__deletedAt.eq(null),f.__id.eq(role.code))).first())!
} else if (role.type === "orgstruct") {
user_component = (await System.organisationStructure.search().where((f,g) => g.and(f.__deletedAt.eq(null),f.__id.eq(role.code))).first())!
} else if (role.type === "user") { // Выход из функции
return await System.users.search().where((f,g) => g.and(f.__status.eq(UserStatus.Active),f.__id.eq(role.code))).all()
}
} else {
user_component = (outside_role as any)
}
//#endregion
//#region Получение пользователей из группы|орг.структуры с применением рекурсии
let users = await async function getUsersFromRoleRecursive(user_component: UserGroupItemRef | OrganisationStructureItemRef,current_nesting:number) {
// Проверка лимитов рекурсивных вызовов
if (current_nesting > limit_nesting) return [];
current_nesting++;
let users : UserItem[] = [];
if (user_component.kind === 'group') { // Группа
let group = (user_component as UserGroupItem)
if (group.data.subOrgunitIds && group.data.subOrgunitIds.length > 0) {
// Получение вложенных групп и орг. структур из группы
let [sub_groups, sub_orgstructs] = (await Promise.all([group.subGroups(),System.organisationStructure.search().where((f,g) => g.and(f.__deletedAt.eq(null),f.__id.in(group.data.subOrgunitIds!))).size(10000).all()]));
// Перебор всех элементов группы
(await Promise.all(group.data.subOrgunitIds.map((sub_element) => {
// Группа
let sub_group_index = sub_groups.map(sub_group => sub_group.id).indexOf(sub_element);
if (sub_group_index != -1) {
return getUsersFromRoleRecursive(sub_groups[sub_group_index],current_nesting);
}
// Орг. структура
let sub_orgstruct_index = sub_orgstructs.map(sub_orgstruct => sub_orgstruct.id).indexOf(sub_element);
if (sub_orgstruct_index != -1) {
return getUsersFromRoleRecursive(sub_orgstructs[sub_orgstruct_index],current_nesting);
}
// Пользователь
return System.users.search().where((f,g) => g.and(f.__status.eq(UserStatus.Active),f.__id.eq(sub_element))).all();
}))).map(sub_users => users = users.concat(sub_users));
}
} else if (user_component.kind === 'orgstruct') { // Орг. структура
let orgstruct = (user_component as OrganisationStructureItem)
if (orgstruct && orgstruct.data.type === "DEPARTMENT") { // Если выбран отдел, то включаем всех сотрудников из отдела
let children_orgstructs = getChildrenOrgs(orgstruct);
users = await System.users.search().where((f,g) => {
let orgstruct_filters : Filter[] = []
children_orgstructs.forEach(children_orgstruct => {
orgstruct_filters.push(f.osIds.has(children_orgstruct))
})
return g.and(f.__status.eq(UserStatus.Active),g.or(...orgstruct_filters))
}).size(10000).all()
} else if (orgstruct) { // Если выбрана группа или должность, то включаем только их
users = users.concat(await System.users.search().where((f,g) => g.and(f.__status.eq(UserStatus.Active),f.osIds.has(orgstruct!))).size(10000).all());
}
}
return users;
}(user_component!,0)
//#endregion
return users;
}
Для работы потребуется еще одна функция для получения дочерних орг. структур организационного элемента
Код:
// Получение дочерних орг.структур
function getChildrenOrgs(orgItem : OrganisationStructureItem) : OrganisationStructureItem[] {
let childrenIDs : OrganisationStructureItem[] = []
for (let childrenOrgItem of orgItem.getChildren()) {
if (childrenOrgItem.getChildren().length > 0) {
childrenIDs = childrenIDs.concat(getChildrenOrgs(childrenOrgItem))
}
childrenIDs.push(childrenOrgItem)
}
return childrenIDs
}