From a80e0ad1099b4f67a9467b0653dd2917ac18ebaf Mon Sep 17 00:00:00 2001 From: user01 Date: Sun, 24 May 2026 23:59:30 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20=EB=B0=B0=EC=B9=98/=EB=AF=B8=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EA=B7=BC=EB=A1=9C=EC=9E=90=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 91 ++++++++++++++++++++++++++++++-------------- templates/index.html | 17 +++++++-- 2 files changed, 77 insertions(+), 31 deletions(-) diff --git a/app.py b/app.py index dfc46dc..d56c0df 100644 --- a/app.py +++ b/app.py @@ -797,45 +797,80 @@ 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() - - 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]) + tab_name = t['name'] + fname = store.get('filename', 'export.xlsx') + base, ext = os.path.splitext(fname) - 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']] - ws2.append([combined_name, addr, len(aw), ', '.join(aw)]) + 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(['이름', '연락처', '생년월일', '희망사항', '주소', '배치근무지', '근무지주소']) + 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'] + 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']] + 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') diff --git a/templates/index.html b/templates/index.html index 0ab4507..61d19ad 100644 --- a/templates/index.html +++ b/templates/index.html @@ -24,7 +24,10 @@ - +
+ + +
@@ -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) {