공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
127 lines
5.5 KiB
Python
127 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
import openpyxl, json, shutil
|
|
from copy import copy
|
|
from openpyxl.styles import PatternFill, Font, Alignment
|
|
from openpyxl.utils import get_column_letter as gl
|
|
|
|
XP='한국중부발전.xlsx'
|
|
BLUE=PatternFill('solid', fgColor='FFBDD7EE', bgColor='FFBDD7EE')
|
|
MAXCOL=27
|
|
HEADER_MERGES={'B1:R1','S1:W1','Y1:AA1'}
|
|
|
|
# N corrections (over-detected image -> 어문), keyed (anchor_row, label)
|
|
NFIX={(45,'인재육성'):'어문',(156,'인권경영 추진방향'):'어문',(156,'인권경영 추진조직'):'어문',
|
|
(160,'안전조직'):'어문',(160,'안전보건 경영방침'):'어문'}
|
|
|
|
plan=json.load(open('plan.json',encoding='utf-8'))
|
|
planmap={e['row']:e for e in plan}
|
|
|
|
wb=openpyxl.load_workbook(XP); ws=wb.active
|
|
# capture header-area styling reference later; unmerge non-header
|
|
for mr in list(ws.merged_cells.ranges):
|
|
if str(mr) in HEADER_MERGES: continue
|
|
top=ws.cell(mr.min_row,mr.min_col).value
|
|
ws.unmerge_cells(str(mr))
|
|
for rr in range(mr.min_row,mr.max_row+1):
|
|
for cc in range(mr.min_col,mr.max_col+1):
|
|
if ws.cell(rr,cc).value in (None,''): ws.cell(rr,cc).value=top
|
|
|
|
def cap_row(r):
|
|
vals={c:ws.cell(r,c).value for c in range(1,MAXCOL+1)}
|
|
sty={c:(copy(ws.cell(r,c).font),copy(ws.cell(r,c).fill),copy(ws.cell(r,c).border),
|
|
copy(ws.cell(r,c).alignment),ws.cell(r,c).number_format,copy(ws.cell(r,c).protection)) for c in range(1,MAXCOL+1)}
|
|
hl=ws.cell(r,11).hyperlink
|
|
return {'vals':vals,'sty':sty,'hl':hl.target if hl else None,'blue':set()}
|
|
|
|
# build ordered final rows
|
|
final=[]
|
|
for r in range(3,ws.max_row+1):
|
|
if all(ws.cell(r,c).value in (None,'') for c in range(2,MAXCOL+1)): continue
|
|
rec=cap_row(r)
|
|
if r in planmap:
|
|
e=planmap[r]; lc=e['lc']
|
|
if e['mode']=='child':
|
|
# anchor keeps path; set leaf+1 = self label
|
|
self_nr=next(nr for nr in e['newrows'] if nr['is_self'])
|
|
rec['vals'][lc+1]=self_nr['label']; rec['blue'].add(lc+1)
|
|
final.append(rec)
|
|
# other tabs as child rows
|
|
for nr in e['newrows']:
|
|
if nr['is_self']: continue
|
|
child=cap_row(r) # copy anchor styles/path
|
|
# keep D..lc same(parent path), set lc+1 label, clear deeper
|
|
for c in range(lc+1,11): child['vals'][c]=None
|
|
child['vals'][lc+1]=nr['label']
|
|
Nv=NFIX.get((r,nr['label']),nr.get('N'))
|
|
child['vals'][11]=nr.get('url'); child['vals'][12]=nr.get('L')
|
|
child['vals'][13]=nr.get('M'); child['vals'][14]=Nv; child['vals'][15]=nr.get('O') or None
|
|
for c in range(16,MAXCOL+1): child['vals'][c]=None
|
|
child['hl']=nr.get('url') if nr.get('L')!='사이트' or True else None
|
|
child['blue']=set(range(2,16))
|
|
final.append(child)
|
|
else: # sibling
|
|
final.append(rec)
|
|
for nr in e['newrows']:
|
|
sib=cap_row(r)
|
|
for c in range(lc,11): sib['vals'][c]=None
|
|
sib['vals'][lc]=nr['label']
|
|
Nv=NFIX.get((r,nr['label']),nr.get('N'))
|
|
sib['vals'][11]=nr.get('url'); sib['vals'][12]=nr.get('L')
|
|
sib['vals'][13]=nr.get('M'); sib['vals'][14]=Nv; sib['vals'][15]=nr.get('O') or None
|
|
for c in range(16,MAXCOL+1): sib['vals'][c]=None
|
|
sib['hl']=nr.get('url')
|
|
sib['blue']=set(range(2,16))
|
|
final.append(sib)
|
|
else:
|
|
final.append(rec)
|
|
|
|
# write back
|
|
START=3
|
|
for r in range(START, ws.max_row+1):
|
|
for c in range(1,MAXCOL+1):
|
|
ws.cell(r,c).value=None; ws.cell(r,c).hyperlink=None
|
|
ws.cell(r,c).fill=PatternFill()
|
|
for i,rec in enumerate(final):
|
|
r=START+i
|
|
for c in range(1,MAXCOL+1):
|
|
cell=ws.cell(r,c)
|
|
f,fl,bd,al,nf,pr=rec['sty'][c]
|
|
cell.font=copy(f); cell.fill=copy(fl); cell.border=copy(bd)
|
|
cell.alignment=copy(al); cell.number_format=nf; cell.protection=copy(pr)
|
|
cell.value=rec['vals'][c]
|
|
ws.cell(r,2).value=i+1 # B renumber 1..N
|
|
ws.cell(r,3).value='한국중부발전'
|
|
END=START+len(final)-1
|
|
# re-merge D..I deepest first
|
|
center=Alignment(horizontal='center',vertical='center',wrap_text=True)
|
|
def merge_runs(col, group_cols):
|
|
cur=ws.cell(START,col).value; grp=tuple(ws.cell(START,g).value for g in group_cols); run=START
|
|
runs=[]
|
|
for r in range(START+1,END+1):
|
|
val=ws.cell(r,col).value; g=tuple(ws.cell(r,gg).value for gg in group_cols)
|
|
if val==cur and g==grp: continue
|
|
if cur not in (None,'') and r-1>run: runs.append((run,r-1))
|
|
cur,grp,run=val,g,r
|
|
if cur not in (None,'') and END>run: runs.append((run,END))
|
|
for s,e in runs:
|
|
ws.merge_cells(f'{gl(col)}{s}:{gl(col)}{e}'); ws.cell(s,col).alignment=center
|
|
for col in (9,8,7,6,5,4): # I H G F E D deepest first
|
|
merge_runs(col, tuple(range(4,col)))
|
|
# K hyperlinks + blue fills + heights
|
|
for i,rec in enumerate(final):
|
|
r=START+i
|
|
u=ws.cell(r,11).value
|
|
if isinstance(u,str) and u.startswith(('http://','https://')):
|
|
if rec['hl']:
|
|
ws.cell(r,11).hyperlink=u
|
|
old=ws.cell(r,11).font
|
|
ws.cell(r,11).font=Font(name=old.name or '맑은 고딕',size=old.size or 11,color='0000FF',underline='single')
|
|
for c in rec['blue']:
|
|
ws.cell(r,c).fill=copy(BLUE)
|
|
ws.row_dimensions[r].height=15
|
|
|
|
shutil.copy(XP, XP.replace('.xlsx','_backup_탭전개전.xlsx'))
|
|
wb.save(XP)
|
|
print('rows', len(final), 'B', 1, '..', len(final))
|
|
print('saved, backup 탭전개전')
|