Feat: 배치/미배치 근로자 분리 내보내기 기능 추가

This commit is contained in:
user01
2026-05-24 23:59:30 +09:00
parent e62c10e66f
commit a80e0ad109
2 changed files with 77 additions and 31 deletions

51
app.py
View File

@@ -797,25 +797,64 @@ def reset():
@app.route('/api/export')
def export():
tid = request.args.get('tab') or store['active_tab']
export_type = request.args.get('type', 'all') # all, assigned, unassigned
t = store['tabs'].get(tid)
if not t:
return jsonify({'error': '탭 없음'}), 400
wb = openpyxl.Workbook()
wp_lookup = {wp['id']: wp for wp in t['workplaces']}
tab_name = t['name']
fname = store.get('filename', 'export.xlsx')
base, ext = os.path.splitext(fname)
if export_type == 'unassigned':
ws = wb.active
ws.title = '미배치 근로자'
ws.append(['이름', '희망사항', '주소', '생년월일', '연락처'])
for w in t['workers']:
if w['id'] not in t['assignments']:
ws.append([w['name'], w['hope'], w['address'], w['dob'], w['phone']])
dn = f'{base}_{tab_name}_미배치{ext}'
elif export_type == 'assigned':
ws = wb.active
ws.title = '배치 현황'
ws.append(['이름', '연락처', '생년월일', '희망사항', '주소', '배치근무지', '근무지주소'])
for w in t['workers']:
a_id = t['assignments'].get(w['id'])
if not a_id:
continue
wn = wp_lookup[a_id]['name'] if a_id in wp_lookup else ''
wa = wp_lookup[a_id]['address'] if a_id in wp_lookup else ''
ws.append([w['name'], w['phone'], w['dob'], w['hope'], w['address'], wn, wa])
ws2 = wb.create_sheet('근무지별 배치')
ws2.append(['근무지명', '주소', '배치인원', '배치된근무자'])
addr_groups = {}
for wp in t['workplaces']:
key = wp['address']
if key not in addr_groups:
addr_groups[key] = {'names': [], 'workplace_ids': []}
addr_groups[key]['names'].append(wp['name'])
addr_groups[key]['workplace_ids'].append(wp['id'])
for addr, g in addr_groups.items():
combined_name = ', '.join(g['names'])
aw = [w['name'] for w in t['workers'] if t['assignments'].get(w['id']) in g['workplace_ids']]
if aw:
ws2.append([combined_name, addr, len(aw), ', '.join(aw)])
dn = f'{base}_{tab_name}_배치결과{ext}'
else: # all (기존 동작)
ws1 = wb.active
ws1.title = '배치 현황'
ws1.append(['이름', '연락처', '생년월일', '희망사항', '주소', '배치근무지', '근무지주소'])
wp_lookup = {wp['id']: wp for wp in t['workplaces']}
for w in t['workers']:
a_id = t['assignments'].get(w['id'])
wn = wp_lookup[a_id]['name'] if a_id and a_id in wp_lookup else ''
wa = wp_lookup[a_id]['address'] if a_id and a_id in wp_lookup else ''
ws1.append([w['name'], w['phone'], w['dob'], w['hope'], w['address'], wn, wa])
ws2 = wb.create_sheet('근무지별 배치')
ws2.append(['근무지명', '주소', '배치인원', '배치된근무자'])
# 같은 주소의 근무처는 통합하여 표시
addr_groups = {}
for wp in t['workplaces']:
key = wp['address']
@@ -827,15 +866,11 @@ def export():
combined_name = ', '.join(g['names'])
aw = [w['name'] for w in t['workers'] if t['assignments'].get(w['id']) in g['workplace_ids']]
ws2.append([combined_name, addr, len(aw), ', '.join(aw)])
dn = f'{base}_{tab_name}_배치결과{ext}'
buf = io.BytesIO()
wb.save(buf)
buf.seek(0)
tab_name = t['name']
fname = store.get('filename', 'export.xlsx')
base, ext = os.path.splitext(fname)
dn = f'{base}_{tab_name}_배치결과{ext}'
return send_file(buf, as_attachment=True, download_name=dn,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')

View File

@@ -24,7 +24,10 @@
<input type="file" id="workplaceFileInput" accept=".xlsx,.xls" hidden />
</form>
<button class="btn btn-info" onclick="openGoogleDriveModal()"><i class="fab fa-google-drive"></i> 구글 드라이브</button>
<button class="btn btn-success" onclick="exportExcel()"><i class="fas fa-download"></i> 내보내기</button>
<div class="btn-group" style="position:relative;display:inline-flex;">
<button class="btn btn-success" onclick="exportExcel('assigned')"><i class="fas fa-download"></i> 배치결과</button>
<button class="btn btn-warning" onclick="exportExcel('unassigned')" style="background:#f59e0b;color:#fff;"><i class="fas fa-user-clock"></i> 미배치</button>
</div>
<button class="btn btn-danger" onclick="resetAssignments()"><i class="fas fa-undo"></i> 초기화</button>
<span id="statusBadge" class="status-badge"></span>
</div>
@@ -953,11 +956,19 @@ async function resetAssignments() {
} catch { showToast('초기화 실패', 'error'); }
}
function exportExcel() {
function exportExcel(type) {
if (!activeTabId) { showToast('내보낼 탭이 없습니다.', 'warning'); return; }
const d = currentData();
if (d.workers.length === 0) { showToast('내보낼 데이터가 없습니다.', 'warning'); return; }
window.location.href = `/api/export?tab=${activeTabId}`;
if (type === 'unassigned') {
const unassigned = d.workers.filter(w => !d.assignments[w.id]);
if (unassigned.length === 0) { showToast('미배치 근로자가 없습니다.', 'info'); return; }
}
if (type === 'assigned') {
const assigned = d.workers.filter(w => d.assignments[w.id]);
if (assigned.length === 0) { showToast('배치된 근로자가 없습니다.', 'info'); return; }
}
window.location.href = `/api/export?tab=${activeTabId}&type=${type}`;
}
function getWorkplaceName(id) {