feat(activities): pick assignees by team or role

A team or role adds every member in one step, while each person's completion share stays unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-10 17:39:51 +03:30
co-authored by Cursor
parent 25a24772fc
commit 4c8604d346
2 changed files with 173 additions and 15 deletions
+31
View File
@@ -182,6 +182,35 @@ const assigneePeople = computed(() => {
if (a.assignees?.length) return a.assignees;
return a.assignee ? [a.assignee] : [];
});
const assigneeRoleChoices = computed(() => {
const map = new Map<string, { id: string; name: string; userIds: string[] }>();
for (const user of users.value) {
if (user.isActive === false || !user.orgRoleId || !user.orgRoleName) continue;
const row = map.get(user.orgRoleId) ?? {
id: user.orgRoleId,
name: user.orgRoleName,
userIds: [],
};
row.userIds.push(user.id);
map.set(user.orgRoleId, row);
}
return [...map.values()].sort((a, b) => a.name.localeCompare(b.name, 'fa'));
});
const assigneeTeamChoices = computed(() => {
const active = new Set(
users.value.filter((user) => user.isActive !== false).map((user) => user.id),
);
return teams.value
.map((team) => ({
id: team.id,
name: team.name,
userIds: [...new Set(team.members.map((member) => member.userId).filter((id) => active.has(id)))],
}))
.filter((team) => team.userIds.length > 0)
.sort((a, b) => a.name.localeCompare(b.name, 'fa'));
});
const assigneeNames = computed(() => {
const list = assigneePeople.value.map((u) => u.fullName);
return list.length ? list.join('، ') : '—';
@@ -746,6 +775,8 @@ onMounted(() => {
v-if="canReassign"
v-model="assignUserIds"
:users="users"
:roles="assigneeRoleChoices"
:teams="assigneeTeamChoices"
:disabled="saving"
:min="1"
select-all