feat: promote seatmap and organization updates
This commit is contained in:
@@ -44,6 +44,15 @@ function cloneMembers(items) {
|
||||
return JSON.parse(JSON.stringify(items));
|
||||
}
|
||||
|
||||
function isRetiredLegacyMember(member) {
|
||||
const workStatus = String(member?.['근무상태'] || '').trim();
|
||||
return workStatus === '퇴직';
|
||||
}
|
||||
|
||||
function getVisibleLegacyMembers(items) {
|
||||
return (items || []).filter((member) => !isRetiredLegacyMember(member));
|
||||
}
|
||||
|
||||
function getPhotoPlaceholder(name = '') {
|
||||
return `https://via.placeholder.com/160?text=${encodeURIComponent(name || 'Profile')}`;
|
||||
}
|
||||
@@ -155,7 +164,7 @@ async function uploadProfilePhoto(file, memberName) {
|
||||
}
|
||||
|
||||
function setMembers(items) {
|
||||
members = items.map(toLegacyMember);
|
||||
members = getVisibleLegacyMembers(items.map(toLegacyMember));
|
||||
if (selectedDept !== '전체' && !members.some((member) => member['부서'] === selectedDept)) {
|
||||
selectedDept = '전체';
|
||||
}
|
||||
@@ -1014,11 +1023,11 @@ function handlePhotoFileChange(event) {
|
||||
|
||||
function renderSeatPreviewCard(seatInfo) {
|
||||
const assigned = Boolean(seatInfo?.assigned);
|
||||
const safeLabel = escapeHtml(seatInfo?.seatLabel || '');
|
||||
const seatMapLabel = String(seatInfo?.seatMapName || '자리배치도').replace(/\s*자리배치도\s*$/u, '').trim() || '사무실';
|
||||
const safeSeatMapName = escapeHtml(seatInfo?.seatMapName || '자리배치도');
|
||||
const safeSlotKey = escapeHtml(seatInfo?.slotKey || '');
|
||||
const safeOfficeLabel = escapeHtml(seatMapLabel);
|
||||
const badge = assigned
|
||||
? `<span class="seat-preview-badge">${safeLabel || '배치완료'}</span>`
|
||||
? `<span class="seat-preview-badge">${safeOfficeLabel}</span>`
|
||||
: '<span class="seat-preview-badge seat-preview-badge-muted">미배치</span>';
|
||||
const body = assigned
|
||||
? `
|
||||
@@ -1039,11 +1048,11 @@ function renderSeatPreviewCard(seatInfo) {
|
||||
`;
|
||||
|
||||
return `
|
||||
<div class="seat-preview-card">
|
||||
<div class="seat-preview-card${assigned ? ' is-assigned' : ''}">
|
||||
<div class="seat-preview-head">
|
||||
<div>
|
||||
<strong>재석위치</strong>
|
||||
<p>${assigned ? '현재 자리배치도 기준으로 배치된 좌석 정보를 표시합니다.' : '현재 자리배치도에서 배치된 좌석이 없습니다.'}</p>
|
||||
<p>${assigned ? '현재 배치된 사무실과 좌석 위치를 강조해서 표시합니다.' : '현재 자리배치도에서 배치된 좌석이 없습니다.'}</p>
|
||||
</div>
|
||||
${badge}
|
||||
</div>
|
||||
@@ -1177,8 +1186,9 @@ function openModal(id) {
|
||||
<div class="col-span-1">
|
||||
<label class="text-[11px] font-black text-slate-600 block">근무 상태</label>
|
||||
<select id="m-status" class="w-full bg-white p-3 rounded-xl border text-sm font-bold outline-none">
|
||||
<option value="근무" ${member['근무상태'] !== '휴직' ? 'selected' : ''}>근무</option>
|
||||
<option value="근무" ${member['근무상태'] !== '휴직' && member['근무상태'] !== '퇴직' ? 'selected' : ''}>근무</option>
|
||||
<option value="휴직" ${member['근무상태'] === '휴직' ? 'selected' : ''}>휴직</option>
|
||||
<option value="퇴직" ${member['근무상태'] === '퇴직' ? 'selected' : ''}>퇴직</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-1">
|
||||
@@ -1199,15 +1209,15 @@ function openModal(id) {
|
||||
<button id="modal-tab-basic" onclick="switchModalTab('basic')" class="flex-1 py-3 font-bold border-b-2 border-indigo-600 text-indigo-600 text-sm transition-all">기본 정보</button>
|
||||
<button id="modal-tab-org" onclick="switchModalTab('org')" class="flex-1 py-3 font-bold border-b-2 border-transparent text-slate-400 text-sm transition-all">조직 및 근무</button>
|
||||
</div>
|
||||
<div id="modal-sec-basic" class="grid grid-cols-2 gap-3 modal-form-grid">
|
||||
<div id="modal-sec-basic" class="modal-form-grid member-basic-editor">
|
||||
<input type="hidden" id="m-id" value="${id || ''}">
|
||||
<input type="hidden" id="m-photo-hidden" value="${member['사진'] || ''}">
|
||||
<input type="hidden" id="m-seat-hidden" value="${member['자리위치'] || ''}">
|
||||
<div class="col-span-2 member-edit-layout">
|
||||
<div class="member-edit-left-pane">
|
||||
<div class="member-edit-profile-card">
|
||||
<label class="text-[11px] font-black text-slate-600 block">프로필 사진</label>
|
||||
<div class="member-photo-upload-card member-photo-upload-card-compact">
|
||||
<div class="member-basic-split">
|
||||
<div class="member-basic-left">
|
||||
<div class="member-photo-panel">
|
||||
<div class="member-photo-upload-card member-photo-upload-card-inline">
|
||||
<div class="member-photo-card-title">프로필 사진</div>
|
||||
<div class="member-photo-preview-wrap">
|
||||
<img id="m-photo-preview" src="${member['사진'] || getPhotoPlaceholder(member['이름'] || '')}" alt="프로필 미리보기" class="member-photo-preview">
|
||||
</div>
|
||||
@@ -1219,28 +1229,28 @@ function openModal(id) {
|
||||
<strong id="m-photo-file-name" class="member-photo-file-name">선택된 파일 없음</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-name-field member-name-field-compact">
|
||||
</div>
|
||||
<div class="member-basic-fields">
|
||||
<div class="member-basic-field">
|
||||
<label class="text-[11px] font-black text-slate-600 block">이름 (필수)</label>
|
||||
<input id="m-name" value="${member['이름'] || ''}" oninput="syncPhotoPreviewFromUrl()" class="w-full bg-slate-50 p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
<div class="member-inline-info-grid member-inline-info-grid-stacked">
|
||||
<div class="member-inline-info-card member-inline-info-card-full">
|
||||
<label>사번</label>
|
||||
<input id="m-employee-id" value="${member['사번'] || ''}" class="w-full bg-white p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
<div class="member-inline-info-card member-inline-info-card-full">
|
||||
<label>전화번호</label>
|
||||
<input id="m-phone" value="${member['전화번호'] || ''}" class="w-full bg-white p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
<div class="member-inline-info-card member-inline-info-card-full">
|
||||
<label>이메일</label>
|
||||
<input id="m-email" value="${member['이메일'] || ''}" class="w-full bg-white p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
<div class="member-basic-field">
|
||||
<label class="text-[11px] font-black text-slate-600 block">사번</label>
|
||||
<input id="m-employee-id" value="${member['사번'] || ''}" class="w-full bg-white p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
<div class="member-basic-field">
|
||||
<label class="text-[11px] font-black text-slate-600 block">전화번호</label>
|
||||
<input id="m-phone" value="${member['전화번호'] || ''}" class="w-full bg-white p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
<div class="member-basic-field">
|
||||
<label class="text-[11px] font-black text-slate-600 block">이메일</label>
|
||||
<input id="m-email" value="${member['이메일'] || ''}" class="w-full bg-white p-3 rounded-xl border font-bold text-sm outline-none">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-edit-right-pane">
|
||||
<div class="member-seat-field member-seat-field-emphasis">
|
||||
<div class="member-basic-right">
|
||||
<div class="member-seat-field member-seat-field-compact">
|
||||
<div id="member-seat-preview">${renderSeatPreviewCard({ assigned: false, seatLabel: member['자리위치'] || '', seatMapName: '자리배치도', slotKey: '' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1583,7 +1593,7 @@ async function loadSnapshotListView() {
|
||||
}
|
||||
const payload = await apiFetch(`/api/members?as_of=${encodeURIComponent(snapshotDate)}`);
|
||||
listViewState.snapshotDate = snapshotDate;
|
||||
listViewState.snapshotMembers = (payload.items || []).map(toLegacyMember);
|
||||
listViewState.snapshotMembers = getVisibleLegacyMembers((payload.items || []).map(toLegacyMember));
|
||||
listViewState.mode = 'snapshot';
|
||||
renderListViewModalContent();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user