Feat: 배치/미배치 근로자 분리 내보내기 기능 추가
This commit is contained in:
51
app.py
51
app.py
@@ -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')
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user