# -*- coding: utf-8 -*- """Full rebuild of 한국의료분쟁조정중재원 with tab-expanded authoritative tree.""" import openpyxl, copy, re, sys sys.stdout.reconfigure(encoding='utf-8') from openpyxl.utils import get_column_letter SRC='2.한국의료분쟁조정중재원/한국의료분쟁조정중재원.xlsx' BASE='https://www.k-medi.or.kr' def U(p): return p if p.startswith('http') else BASE+p wbo=openpyxl.load_workbook(SRC); wso=wbo.active exist={} for r in range(3,80): k=wso.cell(r,11).value if not k: continue key=k.replace(BASE,'').split('#')[0].rstrip('?') exist[key]={'L':wso.cell(r,12).value,'M':wso.cell(r,13).value,'N':wso.cell(r,14).value, 'O':wso.cell(r,15).value,'P':wso.cell(r,16).value,'Q':wso.cell(r,17).value,'url':k} NEW='__NEW__' T=[ (1,'의료분쟁상담','/web/lay1/S1T1C8/sublink.do'), (2,'상담안내','/web/lay1/S1T8C17/contents.do'), (2,'자주묻는질문','/web/lay1/bbs/S1T8C69/E/21/list.do'), (1,'의료분쟁 조정/중재','/web/lay1/S1T1C9/sublink.do'), (2,'제도안내','/web/lay1/S1T9C130/sublink.do'), (3,'제도소개','/web/lay1/S1T130C154/contents.do'), (3,'감정 절차 안내','/web/lay1/S1T130C909/contents.do'), (3,'조정 절차 안내','/web/lay1/S1T155C243/contents.do'), (3,'중재 절차 안내','/web/lay1/S1T155C244/contents.do'), (2,'조정신청','/web/lay1/S1T9C132/sublink.do'), (3,'조정신청 방법','/web/lay1/S1T132C158/contents.do',NEW,'페이지',1), (3,'필수제출 서류(환자)','/web/lay1/S1T132C156/contents.do',NEW,'페이지',1), (3,'필수제출 서류(의료기관)','/web/lay1/S1T130C989/contents.do',NEW,'페이지',1), (3,'수수료','/web/lay1/S1T132C157/contents.do',NEW,'페이지',1), (3,'신청내역 조회','/web/lay1/program/S1T132C159/adjustment/list.do',NEW,'페이지',1), (2,'신청서식','/web/lay1/S1T9C133/sublink.do'), (3,'조정신청 서식','/web/lay1/S1T133C878/contents.do'), (3,'중재신청 서식','/web/lay1/S1T133C879/contents.do'), (3,'이의신청 서식','/web/lay1/S1T133C880/contents.do'), (3,'기타 서식','/web/lay1/S1T133C881/contents.do'), (2,'나의사건조회','/web/lay1/program/S1T132C160/incident/index.do'), (1,'수탁감정','/web/lay1/S1T1C12/sublink.do'), (2,'제도 소개','/web/lay1/S1T12C229/contents.do'), (2,'수탁감정 의뢰(서식)','/web/lay1/S1T12C1128/contents.do'), (2,'수탁감정 처리 흐름도','/web/lay1/S1T228C230/contents.do'), (2,'수탁감정 시행','/web/lay1/S1T228C231/contents.do'), (2,'수탁사건 조회','/web/lay1/program/S1T12C628/trust/index.do'), (2,'수탁감정제도 이용 안내서','/web/lay1/bbs/S1T27C1148/A/26/view.do?article_seq=12582&cpage=1&rows=10'), (1,'손해배상금 대불','/web/lay1/S1T1C867/sublink.do'), (2,'손해배상금 대불제도란?','/web/lay1/S1T867C868/contents.do'), (2,'대불 청구 및 심사','/web/lay1/S1T867C869/sublink.do'), (3,'대불청구 방법','/web/lay1/S1T869C873/contents.do',NEW,'페이지',1), (3,'대불청구 심사절차','/web/lay1/S1T869C874/contents.do',NEW,'페이지',1), (2,'대불비용 부담액','/web/lay1/S1T867C870/sublink.do'), (3,'부담액 부과·징수','/web/lay1/S1T870C875/contents.do',NEW,'페이지',1), (3,'부담액 조회','/web/lay1/program/S1T870C876/burden/index.do',NEW,'페이지',1), (3,'부담액 반환','/web/lay1/S1T870C877/contents.do',NEW,'페이지',1), (2,'대불금의 상환','/web/lay1/S1T867C871/contents.do'), (2,'관련 법령 및 서식','/web/lay1/S1T867C872/contents.do'), (1,'불가항력 의료사고 보상','/web/lay1/S1T1C856/sublink.do'), (2,'불가항력 의료사고 보상제도란?','/web/lay1/S1T856C857/contents.do'), (2,'보상 청구 및 심사','/web/lay1/S1T856C858/sublink.do'), (3,'보상청구 방법','/web/lay1/S1T858C863/contents.do',NEW,'페이지',1), (3,'보상청구 심사절차','/web/lay1/S1T858C864/contents.do',NEW,'페이지',1), (2,'보상 심의기준','/web/lay1/S1T856C1168/contents.do'), (2,'불가항력 의료사고 보상 사례','/web/lay1/program/S1T856C860/indemnification/list.do'), (2,'자주 묻는 질문','/web/lay1/bbs/S1T856C861/E/190/list.do'), (2,'관련 법령 및 서식','/web/lay1/bbs/S1T856C862/E/183/list.do'), (1,'의료사고예방','/web/lay1/S1T1C114/sublink.do'), (2,'업무소개','/web/lay1/S1T114C115/contents.do'), (2,'의료사고예방위원회','/web/lay1/S1T114C116/contents.do'), (2,'의료사고예방 소식지','/web/lay1/S1T114C119/sublink.do'), (3,'정기간행물(MAP)','/web/lay1/bbs/S1T119C689/B/189/list.do',NEW,'게시판',32), (3,'정기간행물(MAP_EBOOK)','/web/lay1/bbs/S1T119C850/A/184/list.do',NEW,'게시판',4), (3,'비 정기간행물','/web/lay1/bbs/S1T119C708/A/123/list.do',NEW,'게시판',29), (2,'교육/세미나 신청','/web/lay1/S1T114C248/sublink.do'), (3,'교육 신청','/web/lay1/program/S1T248C648/education/index.do',NEW,'페이지',1), (3,'정기 온라인 동영상 교육','/web/lay1/program/S1T248C31/seminar/list.do',NEW,'게시판',0), (1,'알림마당','/web/lay1/S1T1C13/sublink.do'), (2,'공지사항','/web/lay1/bbs/S1T13C18/A/1/list.do'), (2,'보도자료','/web/lay1/bbs/S1T13C24/A/2/list.do'), (2,'신고센터','/web/lay1/S1T13C29/sublink.do'), (3,'국민신문고','/web/lay1/S1T29C422/sublink.do'), (4,'민원신청','/web/lay1/program/S1T422C423/epeople/write.do',NEW,'페이지',1), (4,'나의민원확인','/web/lay1/program/S1T422C424/epeople/list.do',NEW,'페이지',1), (3,'부조리신고','/web/lay1/program/S1T29C149/irrationality/index.do'), (3,'청탁금지법 위반 신고','/web/lay1/S1T29C150/contents.do'), (2,'입찰공고','/web/lay1/bbs/S1T13C26/A/23/list.do'), (2,'칭찬합시다','/web/lay1/program/S1T13C30/compliment/list.do'), (2,'채용정보','/web/lay1/bbs/S1T13C148/A/47/list.do'), (2,'자료실','/web/lay1/S1T13C27/sublink.do'), (3,'정기간행물','/web/lay1/bbs/S1T27C96/A/25/list.do'), (3,'의료분쟁 사례','/web/lay1/S1T27C118/sublink.do'), (4,'조정중재사례','/web/lay1/program/S1T118C291/dispute/list.do',NEW,'게시판',630), (4,'감정사례와 예방 TIP','/web/lay1/bbs/S1T118C124/A/89/list.do',NEW,'게시판',269), (4,'상담사례','/web/lay1/program/S1T118C1048/advice/list.do',NEW,'게시판',443), (3,'일반 자료실','/web/lay1/bbs/S1T27C1148/A/26/list.do'), (2,'정보공개','/web/lay1/S1T13C14/sublink.do'), (3,'정보공개제도안내','/web/lay1/S1T14C87/contents.do'), (3,'업무흐름도','/web/lay1/S1T14C88/contents.do'), (3,'정보공개 수수료','/web/lay1/S1T14C89/contents.do'), (3,'비공개대상정보','/web/lay1/S1T14C92/contents.do'), (3,'정보공개청구','/web/lay1/S1T14C93/contents.do'), (3,'공공데이터 개방 및 수요조사 채널','/web/lay1/bbs/S1T14C949/C/221/list.do'), (3,'경영공시','/web/lay1/S1T14C95/sublink.do'), (4,'사업실명제','/web/lay1/bbs/S1T95C91/A/45/list.do',NEW,'게시판',183), (4,'기관장 업무추진비','/web/lay1/bbs/S1T95C452/A/102/list.do',NEW,'게시판',150), (4,'친인척 신규채용인원 공개','/web/lay1/bbs/S1T95C768/A/141/list.do',NEW,'게시판',25), (4,'상품권 구매 및 사용내역','/web/lay1/bbs/S1T95C852/A/185/list.do',NEW,'게시판',22), (1,'의료중재원 소개','/web/lay1/S1T1C15/sublink.do'), (2,'기관소개','/web/lay1/S1T15C98/sublink.do'), (3,'미션 및 비전','/web/lay1/S1T98C170/contents.do',NEW,'페이지',1), (3,'CI','/web/lay1/S1T98C173/contents.do',NEW,'페이지',1), (3,'캐릭터','/web/lay1/S1T98C174/contents.do',NEW,'페이지',1), (3,'원훈','/web/lay1/S1T98C172/contents.do',NEW,'페이지',1), (2,'윤리경영','/web/lay1/S1T15C103/sublink.do'), (3,'윤리경영 개요','/web/lay1/S1T103C234/sublink.do'), (4,'기관장 청렴·윤리경영 메시지','/web/lay1/S1T234C490/contents.do',NEW,'페이지',1), (4,'윤리경영 개요','/web/lay1/S1T234C489/contents.do',NEW,'페이지',1), (3,'윤리헌장','/web/lay1/S1T103C175/sublink.do'), (4,'윤리헌장','/web/lay1/S1T175C235/contents.do',NEW,'페이지',1), (4,'윤리규범','/web/lay1/S1T175C233/contents.do',NEW,'페이지',1), (4,'청탁금지법 준수ㆍ청렴서약서','/web/lay1/S1T175C176/contents.do',NEW,'페이지',1), (3,'윤리경영 실천','/web/lay1/S1T103C236/sublink.do'), (4,'윤리경영 실천','/web/lay1/S1T236C237/contents.do',NEW,'페이지',1), (4,'윤리경영 소식','/web/lay1/bbs/S1T236C488/A/121/list.do',NEW,'게시판',141), (4,'신고센터','/web/lay1/S1T236C238/contents.do',NEW,'페이지',1), (2,'인사말','/web/lay1/S1T15C99/contents.do'), (2,'인권경영','/web/lay1/S1T15C588/sublink.do'), (3,'인권경영 헌장','/web/lay1/bbs/S1T588C788/A/161/list.do',NEW,'게시판',1), (3,'인권경영 주요활동','/web/lay1/bbs/S1T588C789/A/162/list.do',NEW,'게시판',5), (2,'연혁','/web/lay1/S1T15C100/contents.do'), (2,'조직도','/web/lay1/program/S1T15C101/staff/org_chart/list.do'), (2,'업무소개','/web/lay1/S1T15C102/contents.do'), (2,'고객헌장','/web/lay1/S1T15C104/contents.do'), (2,'홍보관','/web/lay1/S1T15C105/sublink.do'), (3,'홍보영상','/web/lay1/bbs/S1T105C853/G/186/list.do',NEW,'게시판',24), (3,'카드뉴스','/web/lay1/bbs/S1T105C854/G/187/list.do',NEW,'게시판',10), (3,'웹툰','/web/lay1/bbs/S1T105C855/B/188/list.do',NEW,'게시판',3), (3,'공모전 수상작','/web/lay1/bbs/S1T105C129/B/101/list.do',NEW,'게시판',19), (2,'찾아오시는길','/web/lay1/S1T15C106/sublink.do'), (3,'서울본원','/web/lay1/S1T106C508/contents.do',NEW,'페이지',1), (3,'부산지원','/web/lay1/S1T106C509/contents.do',NEW,'페이지',1), ] # N override for new rows, keyed by path (S-code identifies node) NOVR={ 'S1T132C158':'어문', # 조정신청 방법 (흐름도) 'S1T132C156':'어문', # 필수제출(환자) 'S1T130C989':'어문', # 필수제출(의료기관) 'S1T132C157':'어문', # 수수료 'S1T132C159':'어문', # 신청내역 조회 'S1T869C873':'어문', # 대불청구 방법 'S1T869C874':'어문', # 대불청구 심사절차 'S1T870C875':'어문', # 부담액 부과·징수 (절차도) 'S1T870C876':'어문', # 부담액 조회 'S1T870C877':'어문', # 부담액 반환 (절차도) 'S1T858C863':'어문', # 보상청구 방법 'S1T858C864':'어문', # 보상청구 심사절차 'S1T119C689':'어문,이미지', # 정기간행물(MAP) 표지썸네일 'S1T119C850':'어문,이미지', # 정기간행물(MAP_EBOOK) 'S1T119C708':'어문,이미지', # 비 정기간행물 'S1T248C648':'어문,이미지', # 교육 신청 (실사진) 'S1T248C31':'어문,영상', # 정기 온라인 동영상 교육 'S1T422C423':'어문', # 민원신청 'S1T422C424':'어문', # 나의민원확인 'S1T118C291':'어문', # 조정중재사례 'S1T118C124':'어문', # 감정사례와 예방 TIP 'S1T118C1048':'어문', # 상담사례 'S1T95C91':'어문', # 사업실명제 'S1T95C452':'어문', # 기관장 업무추진비 'S1T95C768':'어문', # 친인척 신규채용 'S1T95C852':'어문', # 상품권 구매 'S1T98C170':'어문', # 미션 및 비전 (아이콘) 'S1T98C173':'어문,이미지', # CI (심벌) 'S1T98C174':'어문,이미지', # 캐릭터 (마스코트) 'S1T98C172':'어문', # 원훈 (글자이미지) 'S1T234C490':'어문', # 기관장 청렴·윤리경영 메시지 'S1T234C489':'어문', # 윤리경영 개요 (인포그래픽) 'S1T175C235':'어문', # 윤리헌장 'S1T175C233':'어문', # 윤리규범 'S1T175C176':'어문', # 청탁금지법 서약서 'S1T236C237':'어문,이미지', # 윤리경영 실천 (실사진) 'S1T236C488':'어문', # 윤리경영 소식 'S1T236C238':'어문,이미지', # 신고센터 (실사진) 'S1T588C788':'어문', # 인권경영 헌장 'S1T588C789':'어문', # 인권경영 주요활동 'S1T105C853':'어문,영상', # 홍보영상 (youtube) 'S1T105C854':'어문,이미지', # 카드뉴스 'S1T105C855':'어문,이미지', # 웹툰 'S1T105C129':'어문,이미지', # 공모전 수상작 'S1T106C508':'어문', # 서울본원 (지도위젯) 'S1T106C509':'어문', # 부산지원 (지도위젯) } def scode(path): m=re.search(r'(S1T\d+C\d+)',path); return m.group(1) if m else None INST='한국의료분쟁조정중재원' recs=[] for t in T: depth,label,path=t[0],t[1],t[2] isnew=len(t)>3 and t[3]==NEW key=path.split('#')[0].rstrip('?') if not isnew and key in exist: e=exist[key]; L,M,N,O,P,Q=e['L'],e['M'],e['N'],e['O'],e['P'],e['Q']; url=e['url'] else: url=U(path) if isnew: L=t[4]; M=t[5] sc=scode(path); N=NOVR.get(sc,'어문') O='미부착'; P=('게시물' if L=='페이지' else '게시판'); Q='' else: L='페이지'; M=1; N='TBD'; O='미부착'; P='게시물'; Q='' recs.append({'d':depth,'label':label,'url':url,'L':L,'M':M,'N':N,'O':O,'P':P,'Q':Q,'new':isnew}) if __name__=='__main__' and '--check' in sys.argv: print('total recs',len(recs),'new',sum(1 for r in recs if r['new'])) used=set(r['url'].replace(BASE,'').split('#')[0].rstrip('?') for r in recs if not r['new']) missing=[k for k in exist if k not in used] print('existing urls NOT placed:',len(missing)) for k in missing: print(' MISSING',k) sys.exit(0) if __name__=='__main__' and '--write' in sys.argv: from openpyxl.styles import Font, Alignment, Border, Side import shutil, datetime OUT=SRC # backup bk=OUT.replace('.xlsx',f'_backup_탭전개전.xlsx') shutil.copy(OUT,bk); print('backup',bk) wb=openpyxl.load_workbook(OUT); ws=wb.active # capture style template from row3 tpl_align=copy.copy(ws.cell(3,2).alignment) tpl_font=copy.copy(ws.cell(3,2).font) klink_font=copy.copy(ws.cell(3,11).font) thin=Side(style='thin',color='FFBFBFBF') border=Border(left=thin,right=thin,top=thin,bottom=thin) # clear all data rows (3..max) values+merges+hyperlinks for m in list(ws.merged_cells.ranges): if m.min_row>=3: ws.unmerge_cells(str(m)) maxr=ws.max_row for r in range(3,maxr+1): for c in range(2,28): cell=ws.cell(r,c); cell.value=None; cell.hyperlink=None # write records r0=3 for i,rec in enumerate(recs): r=r0+i ws.cell(r,2,i+1) # B 순번 ws.cell(r,3,INST) # C # D..J : place label at depth col (4=D) col=4+rec['d']-1 ws.cell(r,col,rec['label']) kc=ws.cell(r,11,rec['url']); kc.hyperlink=rec['url']; kc.font=copy.copy(klink_font) ws.cell(r,12,rec['L']) ws.cell(r,13,rec['M']) ws.cell(r,14,rec['N']) ws.cell(r,15,rec['O']) ws.cell(r,16,rec['P'] if rec['P'] else None) ws.cell(r,17,rec['Q'] if rec['Q'] else None) for c in range(2,28): cell=ws.cell(r,c) if c!=11: cell.font=copy.copy(tpl_font) cell.alignment=copy.copy(tpl_align) cell.border=border ws.row_dimensions[r].height=15 last=r0+len(recs)-1 # determine for each row which column holds its own label (depth col) depthcol=[None]*(last+2) for i,rec in enumerate(recs): depthcol[r0+i]=4+rec['d']-1 # merge D..J: a parent cell at (R,ci) spans down to just before the next row whose depthcol<=ci for ci in range(4,11): # D(4)..J(10) r=r0 while r<=last: if depthcol[r]==ci: # this row owns a label at column ci; span until next row with depthcol<=ci end=r rr=r+1 while rr<=last and depthcol[rr]>ci: end=rr; rr+=1 if end>r: ws.merge_cells(start_row=r,start_column=ci,end_row=end,end_column=ci) r=rr else: r+=1 wb.save(OUT); print('saved',OUT,'rows',len(recs),'last',last)