From 22c4997342cdd2e77a79f5df8c2309e80992d099 Mon Sep 17 00:00:00 2001 From: king Date: Wed, 16 Sep 2026 13:03:50 +0900 Subject: [PATCH] =?UTF-8?q?feat(project):=20=EB=A9=A4=EB=B2=84=20=EB=B0=B0?= =?UTF-8?q?=EC=A0=95=EC=9D=84=20=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=20?= =?UTF-8?q?=EB=8B=A4=EC=A4=91=EC=84=A0=ED=83=9D=20+=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=ED=91=9C=EC=8B=9C=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - +

관리자 페이지에서 프로젝트 관리 권한을 켠 직원이 후보로 나옵니다. 여러 명을 한 번에 선택할 수 있습니다.

+
직원 +
불러오는 중…
+
"; + }).join("") : "배정 가능한 직원이 없습니다(권한 미부여 또는 전원 배정됨)"; } catch (e) { - sel.innerHTML = '"; + box.innerHTML = "불러오기 실패: " + escapeHtml(e.message) + ""; } }); const saveMemberBtn = el("pj-save-member"); if (saveMemberBtn) saveMemberBtn.addEventListener("click", async function () { - const sel = el("pj-m-user"); - if (!sel.value) { alert("직원을 선택하세요."); return; } - const name = sel.selectedOptions[0] ? (sel.selectedOptions[0].dataset.name || "") : ""; - try { - const res = await api("POST", "/project/api/projects/" + projectId + "/members", { - user_email: sel.value, user_name: name, role: el("pj-m-role").value, - }); - members.push(res.member); - renderMemberList(); - closeModal(memberModal); - } catch (e) { showToast("배정 실패: " + e.message, "error"); } + const box = el("pj-m-users"); + const checked = box ? Array.from(box.querySelectorAll("input[type=checkbox]:checked")) : []; + if (!checked.length) { alert("직원을 선택하세요."); return; } + const role = el("pj-m-role").value; + let failCount = 0; + for (const cb of checked) { + try { + const res = await api("POST", "/project/api/projects/" + projectId + "/members", { + user_email: cb.value, user_name: cb.dataset.name || "", role: role, + }); + members.push(res.member); + } catch (e) { failCount++; } + } + renderMemberList(); + closeModal(memberModal); + if (failCount) showToast(failCount + "명 배정 실패", "error"); }); // 최초 렌더 — 아사나처럼 프로젝트에 들어오면 보드(세션)가 기본 화면이다