GTELP HR
채용솔루션 분석 · 관리자 로그인
2026년 데이터 입력
입력 루트맵 ↗
기업명 상반기 시작 (1~6월) 하반기 시작 (7~12월) 마감일 발표일
(유)사조씨피케이 6/117/17/1511/1412/27 11/27 -
(재)서울경제진흥원 7/2 - -
(재)서울관광재단 5/26/2310/1312/10 10/23 -
(재)씨젠의료재단 8/14 - -
(재)아산나눔재단 6/912/18 - -
(재)이노베이션아카데미 12/24 - -
(재)자동차융합기술원 5/22 - -
(재)전북바이오융합산업진흥원 7/16 - -
(재)한국기계전기전자시험연구원 11/13 - -
(재)한국조선해양기자재연구원 6/19 - -
(재)환경재단 12/22 - -
(주)경농 7/712/10 - -
(주)노루페인트 11/1012/2 11/16 -
(주)멀티캠퍼스 11/4 - -
(주)삼양홀딩스 5/16/189/39/2210/1511/1712/15 9/2810/2612/28 -
(주)오뚜기 6/510/13 - -
(주)우아한형제들 12/19 - -
(주)유라코퍼레이션 7/2 - -
(주)이마트 9/19 - -
(주)코스알엑스 8/610/22 - -
(주)폴라리스오피스 6/1611/17 11/30 -
(주)휴스틸 9/8 9/21 -
AP시스템㈜ - 6/14 -
DS단석 9/1912/9 12/26 -
GS네오텍㈜ 8/1811/19 9/7 -
GS리테일 9/5 - -
GS파워㈜ 9/26 - -
HL Klemove 7/2810/31 9/2111/12 -
JW홀딩스㈜ 7/1811/11 - -
KB캐피탈㈜ 7/18 6/12 -
KPX케미칼㈜ 6/26 7/6 -
LF 7/1 - -
LT메탈 7/119/911/1412/27 11/27 -
SFA반도체㈜ 5/136/257/238/2010/1510/3112/30 5/25 -
SK바이오텍㈜ 10/10 - -
SK하이닉스㈜ 9/22 - -
㈔대한산업안전협회 9/26 - -
㈔서울시관광협회 7/30 8/10 -
㈔한국선급 6/910/27 6/26 -
㈜ABB코리아 5/27/29/312/2 5/3112/31 -
㈜D&O 6/199/11 - -
㈜ECS텔레콤 12/4 - -
㈜KCC건설 12/9 12/23 -
㈜NH농협무역 5/7 - -
㈜SBI저축은행 12/3 - -
㈜가비아 8/25 - -
㈜경동나비엔 7/119/1910/211/1411/28 7/209/2810/1212/7 -
㈜경보제약 7/188/229/1012/5 8/17 -
㈜경인양행 8/30 9/7 -
㈜글로벌스탠다드테크놀로지 5/226/26 6/217/26 -
㈜금화피에스시 8/5 8/17 -
㈜내일신문 12/9 - -
㈜네오팜 5/266/277/169/18 6/312/16 -
㈜넥슨 9/212/10 12/31 -
㈜녹십자 6/209/2512/18 - -
㈜농협사료 6/168/2810/22 6/22 -
㈜농협케미컬 12/12 - -
㈜니프코코리아 8/19 8/31 -
㈜다우기술 7/1710/17 - -
㈜다우데이타 5/23 - -
㈜다원시스 5/27/28 - -
㈜대동 10/28 - -
㈜대웅제약 6/2410/3111/1211/17 7/611/1611/23 -
㈜대학내일 5/3012/4 - -
㈜더블유비스킨 6/9 - -
㈜도루코 10/29 - -
㈜디비아이엔씨 7/4 - -
㈜디알텍 5/17/31 - -
㈜디에이피 8/5 - -
㈜딜리 5/15 6/1412/17 -
㈜레드페이스 10/30 11/29 -
㈜리워터 8/6 10/5 -
㈜리치몬트코리아 6/188/810/15 8/31 -
㈜마니커에프앤지 4/228/12 - -
㈜마크로젠 - 11/2 -
㈜메타바이오메드 8/26 - -
㈜면사랑 5/2410/20 - -
㈜모나미 6/237/38/510/2912/9 6/711/8 -
㈜무학 5/158/1310/1712/1112/23 10/25 -
㈜문화방송 8/18 - -
㈜미래컴퍼니 9/30 10/9 -
㈜바운스 7/8 - -
㈜보령 - 10/19 -
㈜보령바이오파마 12/18 - -
㈜비나우 5/217/178/29 6/3 -
㈜비바리퍼블리카 3/276/10 - -
㈜비상교육 7/4 - -
㈜비씨월드제약 12/29 - -
㈜비엠스마일 5/267/2910/27 - -
㈜비지에프리테일 12/3 12/16 -
㈜사조대림 8/1 8/12 -
㈜삼구아이앤씨 9/18 10/3 -
㈜삼원페이퍼 7/25 - -
㈜삼표산업 6/20 - -
㈜서원유통 7/2110/22 8/1011/9 -
㈜서한 9/1210/1011/20 11/27 -
㈜성원아이북랜드 7/49/23 8/3 -
㈜세아특수강 10/30 11/2 -
㈜센추리 6/24 - -
㈜셀트리온 11/1 - -
㈜셀트리온제약 5/309/1110/2412/23 - -
㈜소노인터내셔널 5/85/135/235/276/236/277/147/318/18/198/219/1110/210/2911/611/7 5/275/316/87/137/278/108/178/319/2010/1911/16 6/311/26
㈜스마트비전 7/88/4 - -
㈜시스윈로보틱스 11/26 - -
㈜신세계아이앤씨 9/23 - -
㈜신영 10/24 - -
㈜신한디에스 5/19 - -
㈜십사일동안 - 2/28 -
㈜씨티알 6/117/98/1 8/31 -
㈜씨티알모빌리티 6/117/912/3 - -
㈜아모텍 4/2311/5 - -
㈜아성테크노 9/12 - -
㈜아워홈 10/1 10/21 -
㈜아이디스 6/128/22 - -
㈜아이에스시 7/4 - -
㈜안랩 5/236/68/1210/3 7/13 -
㈜알레르망 4/111/112/30 8/30 -
㈜에스원 5/147/1511/5 - -
㈜에스티젠바이오 5/27 6/3 -
㈜에이플러스에셋어드바이저 5/155/26 12/6 -
㈜에치와이(한국야쿠르트) 5/3012/12 12/26 -
㈜에코비트워터 5/13 - -
㈜엔씨소프트 10/13 10/21 -
㈜엘비아브노바 7/10 - -
㈜엘에스 5/26 - -
㈜엘지씨엔에스 9/1 - -
㈜연합뉴스 6/30 - -
㈜영신피앤엘 4/297/15 7/5 -
㈜영원무역 7/19/311/6 - -
㈜예가람저축은행 9/1710/29 - -
㈜오리온 9/30 - -
㈜우성 - 10/12 -
㈜우신화장품 5/77/28/119/311/25 10/3 -
㈜우양 5/95/277/2510/14 - -
㈜웅진씽크빅 12/11 - -
㈜원봉 5/307/21 - -
㈜원익QnC 6/128/2012/26 - -
㈜원익홀딩스 9/26 - -
㈜웨이버스 6/2411/11 11/25 -
㈜웹젠 7/178/29 8/3 -
㈜윈스테크넷 11/1812/17 - -
㈜유도 7/21 - -
㈜유영제약 4/30 - -
㈜유진홈센터 8/21 10/11 -
㈜유피케미칼 7/299/16 - -
㈜유한양행 6/108/219/2310/2312/5 10/9 -
㈜이도 10/27 - -
㈜이랜드이츠 5/9 - -
㈜이랜드파크 11/3 - -
㈜인트론바이오테크놀로지 5/7 - -
㈜인팩 - 12/17 -
㈜일신석재 7/3 - -
㈜일화 5/26 - -
㈜젠스타메이트 7/23 8/3 -
㈜쥬비스다이어트 11/1 - -
㈜지마켓 12/19 - -
㈜지씨에스 7/30 - -
㈜지오시스템리서치 12/3 - -
㈜지학사 5/22 - -
㈜케어원 9/30 - -
㈜케이씨씨 6/25 7/6 -
㈜케이씨이노베이션 6/66/217/107/22 - -
㈜케이에프씨코리아 11/11 - -
㈜케이티 7/219/26 10/10 -
㈜케이티아이에스 8/4 - -
㈜케이티앤지 6/58/49/2911/10 - -
㈜케이티에스테이트 10/28 11/2 -
㈜케이티피앤엠 10/28 - -
㈜켐트로닉스 11/21 12/7 -
㈜타라 티. 피. 에스 4/30 - -
㈜태안모터스 8/79/1011/18 6/148/159/6 -
㈜토탈셀러 10/28 12/27 -
㈜티와이엠 10/211/11 - -
㈜파괴연구소 11/26 - -
㈜파마리서치 12/29 - -
㈜팜스코 9/2312/30 10/5 -
㈜펩트론 5/2010/21 - -
㈜포스코인터내셔널 6/212/26 - -
㈜포인트모바일 10/2312/12 11/8 -
㈜풀무원푸드앤컬처 9/26 - -
㈜프레인글로벌 5/1 - -
㈜피씨디렉트 8/78/2011/19 11/25 -
㈜피알앤디컴퍼니 6/27 10/25 -
㈜피플웍스아스날 10/17 - -
㈜하나투어 5/29 - -
㈜한독 9/29 10/19 -
㈜한샘 7/23 - -
㈜한유에너지 12/12 12/25 -
㈜한주 6/1110/22 - -
㈜현대그린푸드 6/139/2912/1 - -
㈜현대드림투어 6/1012/16 - -
㈜호반호텔앤리조트 5/6 7/5 -
㈜호텔신라 8/219/911/412/4 - -
㈜효성 7/2811/3 8/1011/9 -
㈜휴메딕스 8/13 - -
㈜휴비츠 6/111/1 - -
㈜휴온스글로벌 5/226/208/209/1611/18 - -
강남건영㈜ 6/16 7/15 -
강남화성㈜ 6/2 6/15 -
강운공업 5/127/910/16 5/31 -
건국대학교 GLOCAL(글로컬)캠퍼스 6/13 - -
경동물류 4/116/239/912/15 10/9 -
경동제약(주) 5/168/1311/14 8/24 -
경민대학교 6/11 - -
경성문화사 6/179/29/1610/1410/3111/2112/30 11/3012/21 -
고려아연(주) 10/1 10/16 -
교보생명 9/24 - -
교보증권㈜ 5/128/25 9/7 -
교원그룹 5/196/167/148/1810/2011/1712/15 5/256/227/208/249/2110/2611/2312/21 -
교촌에프앤비㈜ 6/167/149/49/17 9/14 -
국가정보원 5/111/712/5 6/3 -
국가철도공단 9/25 10/9 -
국도화학㈜ 5/157/109/15 5/257/209/28 -
그랜드 하얏트 서울 4/114/165/206/46/177/77/117/228/18/119/1010/2712/212/8 4/306/88/17 -
금호건설㈜ 9/19 9/28 -
금호석유화학그룹 9/1 - -
금호타이어㈜ 5/159/1311/3 5/2811/13 -
기아㈜ 8/199/1 - -
깨끗한나라㈜ 5/217/119/4 - -
나이스피앤아이㈜ 5/2011/21 12/7 -
남양유업㈜ 10/1511/20 10/2211/26 -
넥스콘테크놀러지(주) 7/31 8/30 -
넷마블네오㈜ 10/21 11/20 -
노아에이티에스㈜ 6/19 6/26 -
농협양곡㈜ 11/17 - -
능원금속공업㈜ 6/178/19 8/1610/18 -
다이닝브랜즈그룹㈜ 10/13 10/26 -
닥터블릿헬스케어㈜ 2/28 3/31 -
대.중소기업.농어업협력재단 7/28 8/17 -
대구경북과학기술원 11/19 - -
대구신용보증재단 8/29 - -
대구텍(유) 9/510/3012/19 - -
대덕전자 12/112/22 12/14 -
대방건설 11/311/21 11/30 -
대보건설 10/15 10/26 -
대상 5/127/109/1011/10 5/257/209/2111/23 -
대상웰라이프㈜ 9/211/1212/17 11/2512/21 -
대성산업㈜ 7/2511/612/16 11/13 -
대원제약㈜ 12/20 - -
대한유화㈜ 10/13 - -
대화제약㈜ 8/5 - -
도레이첨단소재 주식회사 6/2411/24 7/6 -
도미노피자(청오디피케이) 5/26/47/78/111/412/5 6/1 -
도요엔지니어링코리아㈜ 5/14 - -
동광제약 7/169/2212/1 7/2910/9 -
동국제약㈜ 5/126/237/98/209/810/2011/611/2412/112/11 8/1212/18 -
동부엔지니어링 5/3111/21 - -
동아쏘시오홀딩스㈜ 10/24 11/2 -
동아에스티 7/2511/7 8/3 -
동양대학교 4/30 - -
동원그룹 9/2411/10 11/23 -
동화기업㈜ 7/31 8/24 -
동화약품㈜ 12/15 12/28 -
두성종이㈜ - 10/19 -
디더블유피홀딩스㈜ 9/25 10/8 -
디만트코리아㈜ 12/24 - -
디비손해보험 주식회사 8/2910/31 9/7 -
디비증권㈜ 8/710/16 - -
디스코하이테크코리아㈜ (DISCO HI-TEC KOREA) 7/1010/29 - -
디와이오토㈜ 5/219/8 6/8 -
디와이피엔에프㈜ 5/711/3 6/87/15 -
람정엔터테인먼트코리아 5/76/47/110/111/1 11/30 -
로젠 5/16 - -
롯데손해보험㈜ 8/8 - -
롯데오토케어㈜ 6/19 6/29 -
메가스터디교육㈜ 6/18 - -
메가존클라우드㈜ 12/8 - -
메리츠증권㈜ 10/14 - -
메리츠화재해상보험 6/48/410/2012/8 - -
명인제약㈜ - 10/26 -
무림페이퍼㈜ 7/9 - -
미래에셋생명보험㈜ 9/9 - -
미래에셋증권㈜ 7/30 - -
미창석유공업(주) 6/9 6/22 -
바이엘코리아㈜ 8/14 - -
백조씽크 5/127/1411/1912/29 - -
본아이에프㈜ - 6/29 -
부산국제영화제 6/20 6/29 -
뷰웍스 9/12 - -
비에이치아이㈜ 5/29 6/28 -
비젠트로주식회사 6/178/22 6/26 -
비테스코테크놀로지스코리아(유) 6/137/219/2511/712/18 7/2710/1111/1512/28 -
사단법인 금융보안원 9/4 - -
산일전기㈜ 8/22 - -
삼보모터스㈜ 5/138/13 - -
삼성디스플레이 8/27 - -
삼성메디슨㈜ 11/4 - -
삼성생명서비스손해사정㈜ 11/4 11/18 -
삼성선물㈜ 5/13 - -
삼성이앤에이㈜ 8/27 - -
삼성전기 8/27 - -
삼성전자㈜ 8/27 - -
삼성중공업㈜ 8/27 - -
삼양식품㈜ 5/14 - -
삼지전자㈜ 9/510/111/6 - -
삼화페인트공업㈜ 8/1812/10 - -
상산고등학교 12/312/17 - -
샘표식품㈜ 5/237/1110/312/26 6/810/19 -
서강대학교 6/2512/29 - -
서울대학교병원 8/25 - -
서울도시가스㈜ 12/16 12/25 -
서울올림픽기념국민체육진흥공단 10/17 - -
서진씨엔에스(주) 7/26 - -
선문대학교 9/22 - -
세종기획 5/87/23 5/31 -
소니세미컨덕터솔루션코리아㈜ 12/24 - -
솔탑 6/2710/3012/8 - -
슈어소프트테크㈜ 7/79/89/2012/8 10/8 -
슈피겐코리아 5/239/512/5 6/19/1412/14 -
스투트가르트스포츠카㈜ 2/5 3/9 -
식품안전정보원 7/23 - -
신라에이치엠㈜ 3/315/95/215/29 4/306/28 -
신세계푸드 10/2 - -
신한은행 9/10 - -
씨앤씨인터내셔널 6/2 - -
아시아나IDT㈜ 10/24 - -
안국약품㈜ 6/138/2910/20 6/299/1411/212/21 -
애경산업㈜ 9/30 - -
애경케미칼㈜ 6/47/168/1410/1411/28 6/15 -
앰코테크놀로지코리아㈜ 7/79/18 - -
어드밴텍케이알㈜ 5/9 - -
에너지엔 6/277/2411/28 7/278/2312/28 -
에스에프씨㈜ 11/19 - -
에스제이지세종㈜ 8/14 - -
에스케이에어플러스㈜ 6/107/2511/27 12/14 -
에스케이엠앤서비스㈜ 6/5 - -
에스케이증권㈜ 7/28/11 - -
에스케이핀크스㈜ 8/610/8 8/159/14 -
에이치디현대이엔티㈜ - 11/9 -
에이치알에스코리아㈜ 7/14 7/27 -
에이치엘홀딩스 주식회사 9/8 - -
에프앤코 5/198/2511/24 12/7 -
에프엠커뮤니케이션즈 6/10 - -
엔에이치엔서비스㈜ (NHN Service Corporation) 6/25 - -
엔에이치엔애드㈜ 5/1411/11 11/20 -
엘아이지넥스원㈜ 9/1 - -
엘에스마린솔루션㈜ 6/28/289/12 - -
엘에스엠앤엠㈜ 7/1811/512/19 11/1612/31 -
엘에스일렉트릭㈜ 7/24 8/3 -
엠제이텍 9/2 - -
영신정공㈜ 6/13 - -
영풍전자㈜ 12/24 - -
오비맥주㈜ 6/30 7/20 -
오스템임플란트㈜ 6/27/48/8 6/157/13 -
옵티시스㈜ 5/198/6 - -
와이엠티㈜ 12/22 - -
요진건설산업㈜ 11/24 - -
우리에프아이에스㈜ 8/11 8/24 -
우미건설㈜ 12/112/412/24 - -
웰텍㈜ 6/308/2610/27 11/26 -
유니셈 7/178/7 7/29 -
유니온머티리얼㈜ 5/1411/25 12/14 -
유니테스트 7/168/269/30 11/29 -
유비벨록스㈜ 5/297/8 6/15 -
유진기업㈜ 6/18 7/6 -
유코카캐리어스㈜ 6/18 - -
유한기술㈜ - 8/10 -
율촌화학㈜ 9/13 - -
이녹스첨단소재 7/22 - -
이미인 6/1910/1011/27 7/1911/9 -
이스타항공㈜ 8/1812/30 - -
이연제약㈜ 7/39/312/31 11/9 -
인챈트 5/28 - -
인천공항시설관리㈜ 6/56/98/259/25 - -
인천공항운영서비스 8/4 - -
일동제약 9/412/4 6/15 -
일성아이에스㈜ 5/3011/28 6/12 -
자라리테일코리아 9/1811/13 10/1812/13 -
자화전자㈜ 5/168/1910/30 5/2511/8 -
잡코리아(유) 7/29 - -
재영솔루텍㈜ 12/22 - -
전국 농축협 9/24 - -
전북은행 - 10/3 -
정보통신산업진흥원 8/13 - -
제주신화월드㈜ 5/17/38/5 8/2 -
종근당 5/297/38/2612/12 6/12 -
주식회사 KB손해보험 9/9 - -
주식회사 다스 9/24 10/12 -
주식회사 여기어때컴퍼니 6/3012/29 - -
주식회사 파수 6/30 7/13 -
중소기업은행 11/512/11 - -
중앙일보㈜ 12/22 - -
지니언스(주) 6/17/31 - -
지에스이피에스 8/69/15 8/249/21 -
지에스차지비㈜ 7/30 - -
지케이엘위드㈜ 6/6 - -
진인프라 9/16 - -
차병원·바이오그룹 5/28 - -
청호나이스㈜ 10/23 - -
캐논코리아(주) 12/2 - -
케이비라이프파트너스㈜ 6/20 - -
케이비아이건설㈜ 8/8 8/15 -
케이에이치필룩스㈜ 10/16 - -
케이지모빌리티㈜ 11/10 - -
케이지스틸㈜ 5/28 - -
케이투코리아㈜ 5/2811/1212/15 6/2211/2912/28 -
코레일테크(주) 10/1610/17 - -
코오롱글로벌 6/24 - -
코오롱모터스㈜ 4/1711/20 4/25 -
코오롱인더스트리㈜ 9/15 - -
코웨이㈜ 6/25 - -
쿠쿠홀딩스 5/197/87/2412/23 8/319/14 -
킨코스코리아㈜ - 6/14 -
티케이지태광㈜ 8/711/1412/2 12/14 -
풍산 9/12 - -
프레이저 플레이스 호텔 8/8 12/6 -
피떠불유인터내쇼날 7/22 - -
피케이씨㈜ 6/28 7/13 -
한국과학기술원 9/24 10/8 -
한국관광공사 7/1 - -
한국남부발전 9/119/29 - -
한국단자공업㈜ 11/7 11/16 -
한국렌탈㈜ 11/29 - -
한국마사회시설관리㈜ - - 8/15
한국산업기술시험원 8/28 - -
한국산업은행 9/11 - -
한국서부발전㈜ 9/17 - -
한국수출입은행 8/30 - -
한국알프스㈜ 6/149/20 6/2210/5 -
한국유나이티드제약㈜ 10/10 - -
한국자금중개 5/219/17 - -
한국전기기술인협회 7/18 - -
한국전기연구원 5/20 - -
한국전력공사 10/1 - -
한국전자기술연구원 10/23 - -
한국주택금융공사 8/12 - -
한국지역난방기술 8/2811/5 - -
한국철도기술연구원 7/308/28 - -
한국타이어앤테크놀로지(주) 5/210/2111/13 6/111/30 -
한국투자부동산신탁㈜ 5/9 - -
한국표준협회 8/23 - -
한국피자헛(유) 8/219/1811/1212/1912/31 - -
한국항공우주산업㈜ 9/17 - -
한세실업㈜ 9/16 - -
한신기계공업㈜ 8/11 6/6 -
한온시스템㈜ 8/22 - -
한화손해사정㈜ 11/29 - -
해양에너지 8/26 - -
현대건설 7/87/249/59/199/23 - -
현대글로비스㈜ 11/18 11/23 -
현대로템㈜ 9/411/28 9/7 -
현대비앤지스틸 주식회사[현대자동차그룹] 5/279/2912/9 10/12 -
현대성우그룹 6/17 6/29 -
현대아이에이치엘㈜ 5/2210/2412/10 - -
현대약품㈜ 12/6 - -
현대오토에버㈜ 7/227/2810/28 7/27 -
현대위아㈜ 9/19/2 - -
현대제철주식회사 9/15 - -
현대종합금속㈜ 9/2211/2412/11 10/1212/712/21 -
현대트랜시스㈜ 8/14 - -
호텔롯데 6/57/24 - -
호텔에이치디씨㈜ 보코 서울 명동 7/1712/23 - -
흥국화재해상보험 10/14 - -
희성촉매㈜ 9/15 9/28 -
희성피엠텍㈜ 10/2 - -
2월 (시작 2 · 마감 1 · 발표 0)
일자 구분 기업명
2/5 시작 스투트가르트스포츠카㈜
2/28 마감 ㈜십사일동안
2/28 시작 닥터블릿헬스케어㈜
3월 (시작 2 · 마감 2 · 발표 0)
일자 구분 기업명
3/9 마감 스투트가르트스포츠카㈜
3/27 시작 ㈜비바리퍼블리카
3/31 마감 닥터블릿헬스케어㈜
3/31 시작 신라에이치엠㈜
4월 (시작 11 · 마감 3 · 발표 0)
일자 구분 기업명
4/1 시작 ㈜알레르망
4/11 시작 경동물류
4/11 시작 그랜드 하얏트 서울
4/16 시작 그랜드 하얏트 서울
4/17 시작 코오롱모터스㈜
4/22 시작 ㈜마니커에프앤지
4/23 시작 ㈜아모텍
4/25 마감 코오롱모터스㈜
4/29 시작 ㈜영신피앤엘
4/30 마감 그랜드 하얏트 서울
4/30 마감 신라에이치엠㈜
4/30 시작 ㈜유영제약
4/30 시작 ㈜타라 티. 피. 에스
4/30 시작 동양대학교
5월 (시작 95 · 마감 11 · 발표 0)
일자 구분 기업명
5/1 시작 (주)삼양홀딩스
5/1 시작 ㈜디알텍
5/1 시작 ㈜프레인글로벌
5/1 시작 국가정보원
5/1 시작 제주신화월드㈜
5/2 시작 (재)서울관광재단
5/2 시작 ㈜ABB코리아
5/2 시작 ㈜다원시스
5/2 시작 도미노피자(청오디피케이)
5/2 시작 한국타이어앤테크놀로지(주)
5/6 시작 ㈜호반호텔앤리조트
5/7 시작 ㈜NH농협무역
5/7 시작 ㈜우신화장품
5/7 시작 ㈜인트론바이오테크놀로지
5/7 시작 디와이피엔에프㈜
5/7 시작 람정엔터테인먼트코리아
5/8 시작 ㈜소노인터내셔널
5/8 시작 세종기획
5/9 시작 ㈜우양
5/9 시작 ㈜이랜드이츠
5/9 시작 신라에이치엠㈜
5/9 시작 어드밴텍케이알㈜
5/9 시작 한국투자부동산신탁㈜
5/12 시작 강운공업
5/12 시작 교보증권㈜
5/12 시작 대상
5/12 시작 동국제약㈜
5/12 시작 백조씽크
5/13 시작 SFA반도체㈜
5/13 시작 ㈜소노인터내셔널
5/13 시작 ㈜에코비트워터
5/13 시작 삼보모터스㈜
5/13 시작 삼성선물㈜
5/14 시작 ㈜에스원
5/14 시작 도요엔지니어링코리아㈜
5/14 시작 삼양식품㈜
5/14 시작 엔에이치엔애드㈜
5/14 시작 유니온머티리얼㈜
5/15 시작 ㈜딜리
5/15 시작 ㈜무학
5/15 시작 ㈜에이플러스에셋어드바이저
5/15 시작 국도화학㈜
5/15 시작 금호타이어㈜
5/16 시작 경동제약(주)
5/16 시작 로젠
5/16 시작 자화전자㈜
5/19 시작 ㈜신한디에스
5/19 시작 교원그룹
5/19 시작 에프앤코
5/19 시작 옵티시스㈜
5/19 시작 쿠쿠홀딩스
5/20 시작 ㈜펩트론
5/20 시작 그랜드 하얏트 서울
5/20 시작 나이스피앤아이㈜
5/20 시작 한국전기연구원
5/21 시작 ㈜비나우
5/21 시작 깨끗한나라㈜
5/21 시작 디와이오토㈜
5/21 시작 신라에이치엠㈜
5/21 시작 한국자금중개
5/22 시작 (재)자동차융합기술원
5/22 시작 ㈜글로벌스탠다드테크놀로지
5/22 시작 ㈜지학사
5/22 시작 ㈜휴온스글로벌
5/22 시작 현대아이에이치엘㈜
5/23 시작 ㈜다우데이타
5/23 시작 ㈜소노인터내셔널
5/23 시작 ㈜안랩
5/23 시작 샘표식품㈜
5/23 시작 슈피겐코리아
5/24 시작 ㈜면사랑
5/25 마감 SFA반도체㈜
5/25 마감 교원그룹
5/25 마감 국도화학㈜
5/25 마감 대상
5/25 마감 자화전자㈜
5/26 시작 ㈜네오팜
5/26 시작 ㈜비엠스마일
5/26 시작 ㈜에이플러스에셋어드바이저
5/26 시작 ㈜엘에스
5/26 시작 ㈜일화
5/27 마감 ㈜소노인터내셔널
5/27 시작 ㈜소노인터내셔널
5/27 시작 ㈜에스티젠바이오
5/27 시작 ㈜우양
5/27 시작 현대비앤지스틸 주식회사[현대자동차그룹]
5/28 마감 금호타이어㈜
5/28 시작 인챈트
5/28 시작 차병원·바이오그룹
5/28 시작 케이지스틸㈜
5/28 시작 케이투코리아㈜
5/29 시작 ㈜하나투어
5/29 시작 비에이치아이㈜
5/29 시작 신라에이치엠㈜
5/29 시작 유비벨록스㈜
5/29 시작 종근당
5/30 시작 ㈜대학내일
5/30 시작 ㈜셀트리온제약
5/30 시작 ㈜에치와이(한국야쿠르트)
5/30 시작 ㈜원봉
5/30 시작 일성아이에스㈜
5/31 마감 ㈜ABB코리아
5/31 마감 ㈜소노인터내셔널
5/31 마감 강운공업
5/31 마감 세종기획
5/31 시작 동부엔지니어링
6월 (시작 97 · 마감 42 · 발표 1)
일자 구분 기업명
6/1 마감 도미노피자(청오디피케이)
6/1 마감 슈피겐코리아
6/1 마감 한국타이어앤테크놀로지(주)
6/1 시작 ㈜휴비츠
6/1 시작 지니언스(주)
6/2 시작 ㈜포스코인터내셔널
6/2 시작 강남화성㈜
6/2 시작 씨앤씨인터내셔널
6/2 시작 엘에스마린솔루션㈜
6/2 시작 오스템임플란트㈜
6/3 마감 ㈜네오팜
6/3 마감 ㈜비나우
6/3 마감 ㈜에스티젠바이오
6/3 마감 국가정보원
6/3 발표 ㈜소노인터내셔널
6/4 시작 그랜드 하얏트 서울
6/4 시작 도미노피자(청오디피케이)
6/4 시작 람정엔터테인먼트코리아
6/4 시작 메리츠화재해상보험
6/4 시작 애경케미칼㈜
6/5 시작 (주)오뚜기
6/5 시작 ㈜케이티앤지
6/5 시작 에스케이엠앤서비스㈜
6/5 시작 인천공항시설관리㈜
6/5 시작 호텔롯데
6/6 마감 한신기계공업㈜
6/6 시작 ㈜안랩
6/6 시작 ㈜케이씨이노베이션
6/6 시작 지케이엘위드㈜
6/7 마감 ㈜모나미
6/8 마감 ㈜소노인터내셔널
6/8 마감 그랜드 하얏트 서울
6/8 마감 디와이오토㈜
6/8 마감 디와이피엔에프㈜
6/8 마감 샘표식품㈜
6/9 시작 (재)아산나눔재단
6/9 시작 ㈔한국선급
6/9 시작 ㈜더블유비스킨
6/9 시작 미창석유공업(주)
6/9 시작 인천공항시설관리㈜
6/10 시작 ㈜비바리퍼블리카
6/10 시작 ㈜유한양행
6/10 시작 ㈜현대드림투어
6/10 시작 에스케이에어플러스㈜
6/10 시작 에프엠커뮤니케이션즈
6/11 시작 (유)사조씨피케이
6/11 시작 ㈜씨티알
6/11 시작 ㈜씨티알모빌리티
6/11 시작 ㈜한주
6/11 시작 경민대학교
6/12 마감 KB캐피탈㈜
6/12 마감 일성아이에스㈜
6/12 마감 종근당
6/12 시작 ㈜아이디스
6/12 시작 ㈜원익QnC
6/13 시작 ㈜현대그린푸드
6/13 시작 건국대학교 GLOCAL(글로컬)캠퍼스
6/13 시작 비테스코테크놀로지스코리아(유)
6/13 시작 안국약품㈜
6/13 시작 영신정공㈜
6/14 마감 AP시스템㈜
6/14 마감 ㈜딜리
6/14 마감 ㈜태안모터스
6/14 마감 킨코스코리아㈜
6/14 시작 한국알프스㈜
6/15 마감 강남화성㈜
6/15 마감 애경케미칼㈜
6/15 마감 오스템임플란트㈜
6/15 마감 유비벨록스㈜
6/15 마감 일동제약
6/16 시작 (주)폴라리스오피스
6/16 시작 ㈜농협사료
6/16 시작 강남건영㈜
6/16 시작 교원그룹
6/16 시작 교촌에프앤비㈜
6/17 시작 경성문화사
6/17 시작 그랜드 하얏트 서울
6/17 시작 능원금속공업㈜
6/17 시작 비젠트로주식회사
6/17 시작 현대성우그룹
6/18 시작 (주)삼양홀딩스
6/18 시작 ㈜리치몬트코리아
6/18 시작 메가스터디교육㈜
6/18 시작 유진기업㈜
6/18 시작 유코카캐리어스㈜
6/19 시작 (재)한국조선해양기자재연구원
6/19 시작 ㈜D&O
6/19 시작 노아에이티에스㈜
6/19 시작 롯데오토케어㈜
6/19 시작 이미인
6/20 시작 ㈜녹십자
6/20 시작 ㈜삼표산업
6/20 시작 ㈜휴온스글로벌
6/20 시작 부산국제영화제
6/20 시작 케이비라이프파트너스㈜
6/21 마감 ㈜글로벌스탠다드테크놀로지
6/21 시작 ㈜케이씨이노베이션
6/22 마감 ㈜농협사료
6/22 마감 교원그룹
6/22 마감 미창석유공업(주)
6/22 마감 케이투코리아㈜
6/22 마감 한국알프스㈜
6/23 시작 (재)서울관광재단
6/23 시작 ㈜모나미
6/23 시작 ㈜소노인터내셔널
6/23 시작 경동물류
6/23 시작 동국제약㈜
6/24 시작 ㈜대웅제약
6/24 시작 ㈜센추리
6/24 시작 ㈜웨이버스
6/24 시작 도레이첨단소재 주식회사
6/24 시작 코오롱글로벌
6/25 시작 SFA반도체㈜
6/25 시작 ㈜케이씨씨
6/25 시작 서강대학교
6/25 시작 엔에이치엔서비스㈜ (NHN Service Corporation)
6/25 시작 코웨이㈜
6/26 마감 ㈔한국선급
6/26 마감 노아에이티에스㈜
6/26 마감 비젠트로주식회사
6/26 시작 KPX케미칼㈜
6/26 시작 ㈜글로벌스탠다드테크놀로지
6/27 시작 ㈜네오팜
6/27 시작 ㈜소노인터내셔널
6/27 시작 ㈜피알앤디컴퍼니
6/27 시작 솔탑
6/27 시작 에너지엔
6/28 마감 비에이치아이㈜
6/28 마감 신라에이치엠㈜
6/28 시작 피케이씨㈜
6/29 마감 롯데오토케어㈜
6/29 마감 본아이에프㈜
6/29 마감 부산국제영화제
6/29 마감 안국약품㈜
6/29 마감 현대성우그룹
6/30 시작 ㈜연합뉴스
6/30 시작 오비맥주㈜
6/30 시작 웰텍㈜
6/30 시작 주식회사 여기어때컴퍼니
6/30 시작 주식회사 파수
7월 (시작 112 · 마감 28 · 발표 0)
일자 구분 기업명
7/1 시작 (유)사조씨피케이
7/1 시작 LF
7/1 시작 ㈜영원무역
7/1 시작 람정엔터테인먼트코리아
7/1 시작 한국관광공사
7/2 시작 (재)서울경제진흥원
7/2 시작 (주)유라코퍼레이션
7/2 시작 ㈜ABB코리아
7/2 시작 ㈜우신화장품
7/2 시작 에스케이증권㈜
7/3 시작 ㈜모나미
7/3 시작 ㈜일신석재
7/3 시작 이연제약㈜
7/3 시작 제주신화월드㈜
7/3 시작 종근당
7/4 시작 ㈜디비아이엔씨
7/4 시작 ㈜비상교육
7/4 시작 ㈜성원아이북랜드
7/4 시작 ㈜아이에스시
7/4 시작 오스템임플란트㈜
7/5 마감 ㈜영신피앤엘
7/5 마감 ㈜호반호텔앤리조트
7/6 마감 KPX케미칼㈜
7/6 마감 ㈜대웅제약
7/6 마감 ㈜케이씨씨
7/6 마감 도레이첨단소재 주식회사
7/6 마감 유진기업㈜
7/7 시작 (주)경농
7/7 시작 그랜드 하얏트 서울
7/7 시작 도미노피자(청오디피케이)
7/7 시작 슈어소프트테크㈜
7/7 시작 앰코테크놀로지코리아㈜
7/8 시작 ㈜바운스
7/8 시작 ㈜스마트비전
7/8 시작 유비벨록스㈜
7/8 시작 쿠쿠홀딩스
7/8 시작 현대건설
7/9 시작 ㈜씨티알
7/9 시작 ㈜씨티알모빌리티
7/9 시작 강운공업
7/9 시작 동국제약㈜
7/9 시작 무림페이퍼㈜
7/10 시작 ㈜엘비아브노바
7/10 시작 ㈜케이씨이노베이션
7/10 시작 국도화학㈜
7/10 시작 대상
7/10 시작 디스코하이테크코리아㈜ (DISCO HI-TEC KOREA)
7/11 시작 LT메탈
7/11 시작 ㈜경동나비엔
7/11 시작 그랜드 하얏트 서울
7/11 시작 깨끗한나라㈜
7/11 시작 샘표식품㈜
7/13 마감 ㈜소노인터내셔널
7/13 마감 ㈜안랩
7/13 마감 오스템임플란트㈜
7/13 마감 주식회사 파수
7/13 마감 피케이씨㈜
7/14 시작 ㈜소노인터내셔널
7/14 시작 교원그룹
7/14 시작 교촌에프앤비㈜
7/14 시작 백조씽크
7/14 시작 에이치알에스코리아㈜
7/15 마감 강남건영㈜
7/15 마감 디와이피엔에프㈜
7/15 시작 (유)사조씨피케이
7/15 시작 ㈜에스원
7/15 시작 ㈜영신피앤엘
7/16 시작 (재)전북바이오융합산업진흥원
7/16 시작 ㈜네오팜
7/16 시작 동광제약
7/16 시작 애경케미칼㈜
7/16 시작 유니테스트
7/17 시작 ㈜다우기술
7/17 시작 ㈜비나우
7/17 시작 ㈜웹젠
7/17 시작 유니셈
7/17 시작 호텔에이치디씨㈜ 보코 서울 명동
7/18 시작 JW홀딩스㈜
7/18 시작 KB캐피탈㈜
7/18 시작 ㈜경보제약
7/18 시작 엘에스엠앤엠㈜
7/18 시작 한국전기기술인협회
7/19 마감 이미인
7/20 마감 ㈜경동나비엔
7/20 마감 교원그룹
7/20 마감 국도화학㈜
7/20 마감 대상
7/20 마감 오비맥주㈜
7/21 시작 ㈜서원유통
7/21 시작 ㈜원봉
7/21 시작 ㈜유도
7/21 시작 ㈜케이티
7/21 시작 비테스코테크놀로지스코리아(유)
7/22 시작 ㈜케이씨이노베이션
7/22 시작 그랜드 하얏트 서울
7/22 시작 이녹스첨단소재
7/22 시작 피떠불유인터내쇼날
7/22 시작 현대오토에버㈜
7/23 시작 SFA반도체㈜
7/23 시작 ㈜젠스타메이트
7/23 시작 ㈜한샘
7/23 시작 세종기획
7/23 시작 식품안전정보원
7/24 시작 에너지엔
7/24 시작 엘에스일렉트릭㈜
7/24 시작 쿠쿠홀딩스
7/24 시작 현대건설
7/24 시작 호텔롯데
7/25 시작 ㈜삼원페이퍼
7/25 시작 ㈜우양
7/25 시작 대성산업㈜
7/25 시작 동아에스티
7/25 시작 에스케이에어플러스㈜
7/26 마감 ㈜글로벌스탠다드테크놀로지
7/26 시작 서진씨엔에스(주)
7/27 마감 ㈜소노인터내셔널
7/27 마감 비테스코테크놀로지스코리아(유)
7/27 마감 에너지엔
7/27 마감 에이치알에스코리아㈜
7/27 마감 현대오토에버㈜
7/28 시작 HL Klemove
7/28 시작 ㈜다원시스
7/28 시작 ㈜효성
7/28 시작 대.중소기업.농어업협력재단
7/28 시작 현대오토에버㈜
7/29 마감 동광제약
7/29 마감 유니셈
7/29 시작 ㈜비엠스마일
7/29 시작 ㈜유피케미칼
7/29 시작 잡코리아(유)
7/30 시작 ㈔서울시관광협회
7/30 시작 ㈜지씨에스
7/30 시작 미래에셋증권㈜
7/30 시작 지에스차지비㈜
7/30 시작 한국철도기술연구원
7/31 시작 ㈜디알텍
7/31 시작 ㈜소노인터내셔널
7/31 시작 넥스콘테크놀러지(주)
7/31 시작 동화기업㈜
7/31 시작 지니언스(주)
8월 (시작 101 · 마감 35 · 발표 1)
일자 구분 기업명
8/1 시작 ㈜사조대림
8/1 시작 ㈜소노인터내셔널
8/1 시작 ㈜씨티알
8/1 시작 그랜드 하얏트 서울
8/1 시작 도미노피자(청오디피케이)
8/2 마감 제주신화월드㈜
8/3 마감 ㈜성원아이북랜드
8/3 마감 ㈜웹젠
8/3 마감 ㈜젠스타메이트
8/3 마감 동아에스티
8/3 마감 엘에스일렉트릭㈜
8/4 시작 ㈜스마트비전
8/4 시작 ㈜케이티아이에스
8/4 시작 ㈜케이티앤지
8/4 시작 메리츠화재해상보험
8/4 시작 인천공항운영서비스
8/5 시작 ㈜금화피에스시
8/5 시작 ㈜디에이피
8/5 시작 ㈜모나미
8/5 시작 대화제약㈜
8/5 시작 제주신화월드㈜
8/6 시작 (주)코스알엑스
8/6 시작 ㈜리워터
8/6 시작 에스케이핀크스㈜
8/6 시작 옵티시스㈜
8/6 시작 지에스이피에스
8/7 시작 ㈜태안모터스
8/7 시작 ㈜피씨디렉트
8/7 시작 디비증권㈜
8/7 시작 유니셈
8/7 시작 티케이지태광㈜
8/8 시작 ㈜리치몬트코리아
8/8 시작 롯데손해보험㈜
8/8 시작 오스템임플란트㈜
8/8 시작 케이비아이건설㈜
8/8 시작 프레이저 플레이스 호텔
8/10 마감 ㈔서울시관광협회
8/10 마감 ㈜서원유통
8/10 마감 ㈜소노인터내셔널
8/10 마감 ㈜효성
8/10 마감 유한기술㈜
8/11 시작 ㈜우신화장품
8/11 시작 그랜드 하얏트 서울
8/11 시작 에스케이증권㈜
8/11 시작 우리에프아이에스㈜
8/11 시작 한신기계공업㈜
8/12 마감 ㈜사조대림
8/12 마감 동국제약㈜
8/12 시작 ㈜마니커에프앤지
8/12 시작 ㈜안랩
8/12 시작 한국주택금융공사
8/13 시작 ㈜무학
8/13 시작 ㈜휴메딕스
8/13 시작 경동제약(주)
8/13 시작 삼보모터스㈜
8/13 시작 정보통신산업진흥원
8/14 시작 (재)씨젠의료재단
8/14 시작 바이엘코리아㈜
8/14 시작 애경케미칼㈜
8/14 시작 에스제이지세종㈜
8/14 시작 현대트랜시스㈜
8/15 마감 ㈜태안모터스
8/15 마감 에스케이핀크스㈜
8/15 마감 케이비아이건설㈜
8/15 발표 한국마사회시설관리㈜
8/16 마감 능원금속공업㈜
8/17 마감 ㈜경보제약
8/17 마감 ㈜금화피에스시
8/17 마감 ㈜소노인터내셔널
8/17 마감 그랜드 하얏트 서울
8/17 마감 대.중소기업.농어업협력재단
8/18 시작 GS네오텍㈜
8/18 시작 ㈜문화방송
8/18 시작 교원그룹
8/18 시작 삼화페인트공업㈜
8/18 시작 이스타항공㈜
8/19 시작 ㈜니프코코리아
8/19 시작 ㈜소노인터내셔널
8/19 시작 기아㈜
8/19 시작 능원금속공업㈜
8/19 시작 자화전자㈜
8/20 시작 SFA반도체㈜
8/20 시작 ㈜원익QnC
8/20 시작 ㈜피씨디렉트
8/20 시작 ㈜휴온스글로벌
8/20 시작 동국제약㈜
8/21 시작 ㈜소노인터내셔널
8/21 시작 ㈜유진홈센터
8/21 시작 ㈜유한양행
8/21 시작 ㈜호텔신라
8/21 시작 한국피자헛(유)
8/22 시작 ㈜경보제약
8/22 시작 ㈜아이디스
8/22 시작 비젠트로주식회사
8/22 시작 산일전기㈜
8/22 시작 한온시스템㈜
8/23 마감 에너지엔
8/23 시작 한국표준협회
8/24 마감 경동제약(주)
8/24 마감 교원그룹
8/24 마감 동화기업㈜
8/24 마감 우리에프아이에스㈜
8/24 마감 지에스이피에스
8/25 시작 ㈜가비아
8/25 시작 교보증권㈜
8/25 시작 서울대학교병원
8/25 시작 에프앤코
8/25 시작 인천공항시설관리㈜
8/26 시작 ㈜메타바이오메드
8/26 시작 웰텍㈜
8/26 시작 유니테스트
8/26 시작 종근당
8/26 시작 해양에너지
8/27 시작 삼성디스플레이
8/27 시작 삼성이앤에이㈜
8/27 시작 삼성전기
8/27 시작 삼성전자㈜
8/27 시작 삼성중공업㈜
8/28 시작 ㈜농협사료
8/28 시작 엘에스마린솔루션㈜
8/28 시작 한국산업기술시험원
8/28 시작 한국지역난방기술
8/28 시작 한국철도기술연구원
8/29 시작 ㈜비나우
8/29 시작 ㈜웹젠
8/29 시작 대구신용보증재단
8/29 시작 디비손해보험 주식회사
8/29 시작 안국약품㈜
8/30 마감 ㈜알레르망
8/30 마감 넥스콘테크놀러지(주)
8/30 시작 ㈜경인양행
8/30 시작 한국수출입은행
8/31 마감 ㈜니프코코리아
8/31 마감 ㈜리치몬트코리아
8/31 마감 ㈜소노인터내셔널
8/31 마감 ㈜씨티알
8/31 마감 쿠쿠홀딩스
9월 (시작 114 · 마감 22 · 발표 0)
일자 구분 기업명
9/1 시작 ㈜엘지씨엔에스
9/1 시작 금호석유화학그룹
9/1 시작 기아㈜
9/1 시작 엘아이지넥스원㈜
9/1 시작 현대위아㈜
9/2 시작 ㈜넥슨
9/2 시작 경성문화사
9/2 시작 대상웰라이프㈜
9/2 시작 엠제이텍
9/2 시작 현대위아㈜
9/3 시작 (주)삼양홀딩스
9/3 시작 ㈜ABB코리아
9/3 시작 ㈜영원무역
9/3 시작 ㈜우신화장품
9/3 시작 이연제약㈜
9/4 시작 교촌에프앤비㈜
9/4 시작 깨끗한나라㈜
9/4 시작 사단법인 금융보안원
9/4 시작 일동제약
9/4 시작 현대로템㈜
9/5 시작 GS리테일
9/5 시작 대구텍(유)
9/5 시작 삼지전자㈜
9/5 시작 슈피겐코리아
9/5 시작 현대건설
9/6 마감 ㈜태안모터스
9/7 마감 GS네오텍㈜
9/7 마감 ㈜경인양행
9/7 마감 교보증권㈜
9/7 마감 디비손해보험 주식회사
9/7 마감 현대로템㈜
9/8 시작 (주)휴스틸
9/8 시작 동국제약㈜
9/8 시작 디와이오토㈜
9/8 시작 슈어소프트테크㈜
9/8 시작 에이치엘홀딩스 주식회사
9/9 시작 LT메탈
9/9 시작 ㈜호텔신라
9/9 시작 경동물류
9/9 시작 미래에셋생명보험㈜
9/9 시작 주식회사 KB손해보험
9/10 시작 ㈜경보제약
9/10 시작 ㈜태안모터스
9/10 시작 그랜드 하얏트 서울
9/10 시작 대상
9/10 시작 신한은행
9/11 시작 ㈜D&O
9/11 시작 ㈜셀트리온제약
9/11 시작 ㈜소노인터내셔널
9/11 시작 한국남부발전
9/11 시작 한국산업은행
9/12 시작 ㈜서한
9/12 시작 ㈜아성테크노
9/12 시작 뷰웍스
9/12 시작 엘에스마린솔루션㈜
9/12 시작 풍산
9/13 시작 금호타이어㈜
9/13 시작 율촌화학㈜
9/14 마감 교촌에프앤비㈜
9/14 마감 슈피겐코리아
9/14 마감 안국약품㈜
9/14 마감 에스케이핀크스㈜
9/14 마감 쿠쿠홀딩스
9/15 시작 국도화학㈜
9/15 시작 지에스이피에스
9/15 시작 코오롱인더스트리㈜
9/15 시작 현대제철주식회사
9/15 시작 희성촉매㈜
9/16 시작 ㈜유피케미칼
9/16 시작 ㈜휴온스글로벌
9/16 시작 경성문화사
9/16 시작 진인프라
9/16 시작 한세실업㈜
9/17 시작 ㈜예가람저축은행
9/17 시작 교촌에프앤비㈜
9/17 시작 한국서부발전㈜
9/17 시작 한국자금중개
9/17 시작 한국항공우주산업㈜
9/18 시작 ㈜네오팜
9/18 시작 ㈜삼구아이앤씨
9/18 시작 앰코테크놀로지코리아㈜
9/18 시작 자라리테일코리아
9/18 시작 한국피자헛(유)
9/19 시작 (주)이마트
9/19 시작 DS단석
9/19 시작 ㈜경동나비엔
9/19 시작 금호건설㈜
9/19 시작 현대건설
9/20 마감 ㈜소노인터내셔널
9/20 시작 슈어소프트테크㈜
9/20 시작 한국알프스㈜
9/21 마감 (주)휴스틸
9/21 마감 HL Klemove
9/21 마감 교원그룹
9/21 마감 대상
9/21 마감 지에스이피에스
9/22 시작 (주)삼양홀딩스
9/22 시작 SK하이닉스㈜
9/22 시작 동광제약
9/22 시작 선문대학교
9/22 시작 현대종합금속㈜
9/23 시작 ㈜성원아이북랜드
9/23 시작 ㈜신세계아이앤씨
9/23 시작 ㈜유한양행
9/23 시작 ㈜팜스코
9/23 시작 현대건설
9/24 시작 교보생명
9/24 시작 동원그룹
9/24 시작 전국 농축협
9/24 시작 주식회사 다스
9/24 시작 한국과학기술원
9/25 시작 ㈜녹십자
9/25 시작 국가철도공단
9/25 시작 디더블유피홀딩스㈜
9/25 시작 비테스코테크놀로지스코리아(유)
9/25 시작 인천공항시설관리㈜
9/26 시작 GS파워㈜
9/26 시작 ㈔대한산업안전협회
9/26 시작 ㈜원익홀딩스
9/26 시작 ㈜케이티
9/26 시작 ㈜풀무원푸드앤컬처
9/28 마감 (주)삼양홀딩스
9/28 마감 ㈜경동나비엔
9/28 마감 국도화학㈜
9/28 마감 금호건설㈜
9/28 마감 희성촉매㈜
9/29 시작 ㈜케이티앤지
9/29 시작 ㈜한독
9/29 시작 ㈜현대그린푸드
9/29 시작 한국남부발전
9/29 시작 현대비앤지스틸 주식회사[현대자동차그룹]
9/30 시작 ㈜미래컴퍼니
9/30 시작 ㈜오리온
9/30 시작 ㈜케어원
9/30 시작 애경산업㈜
9/30 시작 유니테스트
10월 (시작 87 · 마감 41 · 발표 0)
일자 구분 기업명
10/1 시작 ㈜아워홈
10/1 시작 고려아연(주)
10/1 시작 람정엔터테인먼트코리아
10/1 시작 삼지전자㈜
10/1 시작 한국전력공사
10/2 시작 ㈜경동나비엔
10/2 시작 ㈜소노인터내셔널
10/2 시작 ㈜티와이엠
10/2 시작 신세계푸드
10/2 시작 희성피엠텍㈜
10/3 마감 ㈜삼구아이앤씨
10/3 마감 ㈜우신화장품
10/3 마감 전북은행
10/3 시작 ㈜안랩
10/3 시작 샘표식품㈜
10/5 마감 ㈜리워터
10/5 마감 ㈜팜스코
10/5 마감 한국알프스㈜
10/8 마감 디더블유피홀딩스㈜
10/8 마감 슈어소프트테크㈜
10/8 마감 한국과학기술원
10/8 시작 에스케이핀크스㈜
10/9 마감 ㈜미래컴퍼니
10/9 마감 ㈜유한양행
10/9 마감 경동물류
10/9 마감 국가철도공단
10/9 마감 동광제약
10/10 마감 ㈜케이티
10/10 시작 SK바이오텍㈜
10/10 시작 ㈜서한
10/10 시작 이미인
10/10 시작 한국유나이티드제약㈜
10/11 마감 ㈜유진홈센터
10/11 마감 비테스코테크놀로지스코리아(유)
10/12 마감 ㈜경동나비엔
10/12 마감 ㈜우성
10/12 마감 주식회사 다스
10/12 마감 현대비앤지스틸 주식회사[현대자동차그룹]
10/12 마감 현대종합금속㈜
10/13 시작 (재)서울관광재단
10/13 시작 (주)오뚜기
10/13 시작 ㈜엔씨소프트
10/13 시작 다이닝브랜즈그룹㈜
10/13 시작 대한유화㈜
10/14 시작 ㈜우양
10/14 시작 경성문화사
10/14 시작 메리츠증권㈜
10/14 시작 애경케미칼㈜
10/14 시작 흥국화재해상보험
10/15 시작 (주)삼양홀딩스
10/15 시작 SFA반도체㈜
10/15 시작 ㈜리치몬트코리아
10/15 시작 남양유업㈜
10/15 시작 대보건설
10/16 마감 고려아연(주)
10/16 시작 강운공업
10/16 시작 디비증권㈜
10/16 시작 케이에이치필룩스㈜
10/16 시작 코레일테크(주)
10/17 시작 ㈜다우기술
10/17 시작 ㈜무학
10/17 시작 ㈜피플웍스아스날
10/17 시작 서울올림픽기념국민체육진흥공단
10/17 시작 코레일테크(주)
10/18 마감 능원금속공업㈜
10/18 마감 자라리테일코리아
10/19 마감 ㈜보령
10/19 마감 ㈜소노인터내셔널
10/19 마감 ㈜한독
10/19 마감 두성종이㈜
10/19 마감 샘표식품㈜
10/20 시작 ㈜면사랑
10/20 시작 교원그룹
10/20 시작 동국제약㈜
10/20 시작 메리츠화재해상보험
10/20 시작 안국약품㈜
10/21 마감 ㈜아워홈
10/21 마감 ㈜엔씨소프트
10/21 시작 ㈜펩트론
10/21 시작 넷마블네오㈜
10/21 시작 한국타이어앤테크놀로지(주)
10/22 마감 남양유업㈜
10/22 시작 (주)코스알엑스
10/22 시작 ㈜농협사료
10/22 시작 ㈜서원유통
10/22 시작 ㈜한주
10/23 마감 (재)서울관광재단
10/23 시작 ㈜유한양행
10/23 시작 ㈜포인트모바일
10/23 시작 청호나이스㈜
10/23 시작 한국전자기술연구원
10/24 시작 ㈜셀트리온제약
10/24 시작 ㈜신영
10/24 시작 동아쏘시오홀딩스㈜
10/24 시작 아시아나IDT㈜
10/24 시작 현대아이에이치엘㈜
10/25 마감 ㈜무학
10/25 마감 ㈜피알앤디컴퍼니
10/26 마감 (주)삼양홀딩스
10/26 마감 교원그룹
10/26 마감 다이닝브랜즈그룹㈜
10/26 마감 대보건설
10/26 마감 명인제약㈜
10/27 시작 ㈔한국선급
10/27 시작 ㈜비엠스마일
10/27 시작 ㈜이도
10/27 시작 그랜드 하얏트 서울
10/27 시작 웰텍㈜
10/28 시작 ㈜대동
10/28 시작 ㈜케이티에스테이트
10/28 시작 ㈜케이티피앤엠
10/28 시작 ㈜토탈셀러
10/28 시작 현대오토에버㈜
10/29 시작 ㈜도루코
10/29 시작 ㈜모나미
10/29 시작 ㈜소노인터내셔널
10/29 시작 ㈜예가람저축은행
10/29 시작 디스코하이테크코리아㈜ (DISCO HI-TEC KOREA)
10/30 시작 ㈜레드페이스
10/30 시작 ㈜세아특수강
10/30 시작 대구텍(유)
10/30 시작 솔탑
10/30 시작 자화전자㈜
10/31 시작 HL Klemove
10/31 시작 SFA반도체㈜
10/31 시작 ㈜대웅제약
10/31 시작 경성문화사
10/31 시작 디비손해보험 주식회사
11월 (시작 92 · 마감 46 · 발표 1)
일자 구분 기업명
11/1 시작 ㈜셀트리온
11/1 시작 ㈜알레르망
11/1 시작 ㈜쥬비스다이어트
11/1 시작 ㈜휴비츠
11/1 시작 람정엔터테인먼트코리아
11/2 마감 ㈜마크로젠
11/2 마감 ㈜세아특수강
11/2 마감 ㈜케이티에스테이트
11/2 마감 동아쏘시오홀딩스㈜
11/2 마감 안국약품㈜
11/3 시작 ㈜이랜드파크
11/3 시작 ㈜효성
11/3 시작 금호타이어㈜
11/3 시작 대방건설
11/3 시작 디와이피엔에프㈜
11/4 시작 (주)멀티캠퍼스
11/4 시작 ㈜호텔신라
11/4 시작 도미노피자(청오디피케이)
11/4 시작 삼성메디슨㈜
11/4 시작 삼성생명서비스손해사정㈜
11/5 시작 ㈜아모텍
11/5 시작 ㈜에스원
11/5 시작 엘에스엠앤엠㈜
11/5 시작 중소기업은행
11/5 시작 한국지역난방기술
11/6 시작 ㈜소노인터내셔널
11/6 시작 ㈜영원무역
11/6 시작 대성산업㈜
11/6 시작 동국제약㈜
11/6 시작 삼지전자㈜
11/7 시작 ㈜소노인터내셔널
11/7 시작 국가정보원
11/7 시작 동아에스티
11/7 시작 비테스코테크놀로지스코리아(유)
11/7 시작 한국단자공업㈜
11/8 마감 ㈜모나미
11/8 마감 ㈜포인트모바일
11/8 마감 자화전자㈜
11/9 마감 ㈜서원유통
11/9 마감 ㈜효성
11/9 마감 에이치디현대이엔티㈜
11/9 마감 이미인
11/9 마감 이연제약㈜
11/10 시작 (주)노루페인트
11/10 시작 ㈜케이티앤지
11/10 시작 대상
11/10 시작 동원그룹
11/10 시작 케이지모빌리티㈜
11/11 시작 JW홀딩스㈜
11/11 시작 ㈜웨이버스
11/11 시작 ㈜케이에프씨코리아
11/11 시작 ㈜티와이엠
11/11 시작 엔에이치엔애드㈜
11/12 마감 HL Klemove
11/12 시작 ㈜대웅제약
11/12 시작 대상웰라이프㈜
11/12 시작 케이투코리아㈜
11/12 시작 한국피자헛(유)
11/13 마감 금호타이어㈜
11/13 마감 대성산업㈜
11/13 시작 (재)한국기계전기전자시험연구원
11/13 시작 자라리테일코리아
11/13 시작 한국타이어앤테크놀로지(주)
11/14 시작 (유)사조씨피케이
11/14 시작 LT메탈
11/14 시작 ㈜경동나비엔
11/14 시작 경동제약(주)
11/14 시작 티케이지태광㈜
11/15 마감 비테스코테크놀로지스코리아(유)
11/16 마감 (주)노루페인트
11/16 마감 ㈜대웅제약
11/16 마감 ㈜소노인터내셔널
11/16 마감 엘에스엠앤엠㈜
11/16 마감 한국단자공업㈜
11/17 시작 (주)삼양홀딩스
11/17 시작 (주)폴라리스오피스
11/17 시작 ㈜대웅제약
11/17 시작 교원그룹
11/17 시작 농협양곡㈜
11/18 마감 삼성생명서비스손해사정㈜
11/18 시작 ㈜윈스테크넷
11/18 시작 ㈜태안모터스
11/18 시작 ㈜휴온스글로벌
11/18 시작 현대글로비스㈜
11/19 시작 GS네오텍㈜
11/19 시작 ㈜피씨디렉트
11/19 시작 대구경북과학기술원
11/19 시작 백조씽크
11/19 시작 에스에프씨㈜
11/20 마감 넷마블네오㈜
11/20 마감 엔에이치엔애드㈜
11/20 시작 ㈜서한
11/20 시작 남양유업㈜
11/20 시작 코오롱모터스㈜
11/21 시작 ㈜켐트로닉스
11/21 시작 경성문화사
11/21 시작 나이스피앤아이㈜
11/21 시작 대방건설
11/21 시작 동부엔지니어링
11/23 마감 ㈜대웅제약
11/23 마감 교원그룹
11/23 마감 대상
11/23 마감 동원그룹
11/23 마감 현대글로비스㈜
11/24 시작 도레이첨단소재 주식회사
11/24 시작 동국제약㈜
11/24 시작 에프앤코
11/24 시작 요진건설산업㈜
11/24 시작 현대종합금속㈜
11/25 마감 ㈜웨이버스
11/25 마감 ㈜피씨디렉트
11/25 마감 대상웰라이프㈜
11/25 시작 ㈜우신화장품
11/25 시작 유니온머티리얼㈜
11/26 마감 남양유업㈜
11/26 마감 웰텍㈜
11/26 발표 ㈜소노인터내셔널
11/26 시작 ㈜시스윈로보틱스
11/26 시작 ㈜파괴연구소
11/27 마감 (유)사조씨피케이
11/27 마감 LT메탈
11/27 마감 ㈜서한
11/27 시작 에스케이에어플러스㈜
11/27 시작 이미인
11/28 시작 ㈜경동나비엔
11/28 시작 애경케미칼㈜
11/28 시작 에너지엔
11/28 시작 일성아이에스㈜
11/28 시작 현대로템㈜
11/29 마감 ㈜레드페이스
11/29 마감 유니테스트
11/29 마감 케이투코리아㈜
11/29 시작 한국렌탈㈜
11/29 시작 한화손해사정㈜
11/30 마감 (주)폴라리스오피스
11/30 마감 경성문화사
11/30 마감 대방건설
11/30 마감 람정엔터테인먼트코리아
11/30 마감 한국타이어앤테크놀로지(주)
12월 (시작 103 · 마감 37 · 발표 0)
일자 구분 기업명
12/1 시작 ㈜현대그린푸드
12/1 시작 대덕전자
12/1 시작 동광제약
12/1 시작 동국제약㈜
12/1 시작 우미건설㈜
12/2 시작 (주)노루페인트
12/2 시작 ㈜ABB코리아
12/2 시작 그랜드 하얏트 서울
12/2 시작 캐논코리아(주)
12/2 시작 티케이지태광㈜
12/3 시작 ㈜SBI저축은행
12/3 시작 ㈜비지에프리테일
12/3 시작 ㈜씨티알모빌리티
12/3 시작 ㈜지오시스템리서치
12/3 시작 상산고등학교
12/4 시작 ㈜ECS텔레콤
12/4 시작 ㈜대학내일
12/4 시작 ㈜호텔신라
12/4 시작 우미건설㈜
12/4 시작 일동제약
12/5 시작 ㈜경보제약
12/5 시작 ㈜유한양행
12/5 시작 국가정보원
12/5 시작 도미노피자(청오디피케이)
12/5 시작 슈피겐코리아
12/6 마감 ㈜에이플러스에셋어드바이저
12/6 마감 프레이저 플레이스 호텔
12/6 시작 현대약품㈜
12/7 마감 ㈜경동나비엔
12/7 마감 ㈜켐트로닉스
12/7 마감 나이스피앤아이㈜
12/7 마감 에프앤코
12/7 마감 현대종합금속㈜
12/8 시작 그랜드 하얏트 서울
12/8 시작 메가존클라우드㈜
12/8 시작 메리츠화재해상보험
12/8 시작 솔탑
12/8 시작 슈어소프트테크㈜
12/9 시작 DS단석
12/9 시작 ㈜KCC건설
12/9 시작 ㈜내일신문
12/9 시작 ㈜모나미
12/9 시작 현대비앤지스틸 주식회사[현대자동차그룹]
12/10 시작 (재)서울관광재단
12/10 시작 (주)경농
12/10 시작 ㈜넥슨
12/10 시작 삼화페인트공업㈜
12/10 시작 현대아이에이치엘㈜
12/11 시작 ㈜무학
12/11 시작 ㈜웅진씽크빅
12/11 시작 동국제약㈜
12/11 시작 중소기업은행
12/11 시작 현대종합금속㈜
12/12 시작 ㈜농협케미컬
12/12 시작 ㈜에치와이(한국야쿠르트)
12/12 시작 ㈜포인트모바일
12/12 시작 ㈜한유에너지
12/12 시작 종근당
12/13 마감 자라리테일코리아
12/14 마감 대덕전자
12/14 마감 슈피겐코리아
12/14 마감 에스케이에어플러스㈜
12/14 마감 유니온머티리얼㈜
12/14 마감 티케이지태광㈜
12/15 시작 (주)삼양홀딩스
12/15 시작 경동물류
12/15 시작 교원그룹
12/15 시작 동화약품㈜
12/15 시작 케이투코리아㈜
12/16 마감 ㈜네오팜
12/16 마감 ㈜비지에프리테일
12/16 시작 ㈜현대드림투어
12/16 시작 대성산업㈜
12/16 시작 서울도시가스㈜
12/17 마감 ㈜딜리
12/17 마감 ㈜인팩
12/17 시작 ㈜윈스테크넷
12/17 시작 대상웰라이프㈜
12/17 시작 상산고등학교
12/18 마감 동국제약㈜
12/18 시작 (재)아산나눔재단
12/18 시작 ㈜녹십자
12/18 시작 ㈜보령바이오파마
12/18 시작 비테스코테크놀로지스코리아(유)
12/19 시작 (주)우아한형제들
12/19 시작 ㈜지마켓
12/19 시작 대구텍(유)
12/19 시작 엘에스엠앤엠㈜
12/19 시작 한국피자헛(유)
12/20 시작 대원제약㈜
12/21 마감 경성문화사
12/21 마감 교원그룹
12/21 마감 대상웰라이프㈜
12/21 마감 안국약품㈜
12/21 마감 현대종합금속㈜
12/22 시작 (재)환경재단
12/22 시작 대덕전자
12/22 시작 와이엠티㈜
12/22 시작 재영솔루텍㈜
12/22 시작 중앙일보㈜
12/23 마감 ㈜KCC건설
12/23 시작 ㈜무학
12/23 시작 ㈜셀트리온제약
12/23 시작 쿠쿠홀딩스
12/23 시작 호텔에이치디씨㈜ 보코 서울 명동
12/24 시작 (재)이노베이션아카데미
12/24 시작 디만트코리아㈜
12/24 시작 소니세미컨덕터솔루션코리아㈜
12/24 시작 영풍전자㈜
12/24 시작 우미건설㈜
12/25 마감 ㈜한유에너지
12/25 마감 서울도시가스㈜
12/26 마감 DS단석
12/26 마감 ㈜에치와이(한국야쿠르트)
12/26 시작 ㈜원익QnC
12/26 시작 ㈜포스코인터내셔널
12/26 시작 샘표식품㈜
12/27 마감 ㈜토탈셀러
12/27 시작 (유)사조씨피케이
12/27 시작 LT메탈
12/28 마감 (주)삼양홀딩스
12/28 마감 동화약품㈜
12/28 마감 비테스코테크놀로지스코리아(유)
12/28 마감 에너지엔
12/28 마감 케이투코리아㈜
12/29 시작 ㈜비씨월드제약
12/29 시작 ㈜파마리서치
12/29 시작 백조씽크
12/29 시작 서강대학교
12/29 시작 주식회사 여기어때컴퍼니
12/30 시작 SFA반도체㈜
12/30 시작 ㈜알레르망
12/30 시작 ㈜팜스코
12/30 시작 경성문화사
12/30 시작 이스타항공㈜
12/31 마감 ㈜ABB코리아
12/31 마감 ㈜넥슨
12/31 마감 엘에스엠앤엠㈜
12/31 시작 이연제약㈜
12/31 시작 한국피자헛(유)
-
2025 기업 수
-
2025 이벤트
-
2026 기업 수
-
2026 이벤트

월별 채용 시작 공고 수

상반기 vs 하반기 비교

채용 횟수 TOP 10 기업

업무보고

월간뉴스 작성 — 여러 기사 종합·재작성

여러 기사 원문을 칸마다 붙여넣고 AI 종합 작성을 누르면, 저작권 안전하게 단어·어순을 바꿔 재작성한 아나운서 톤 기사를 생성하고, 직접 인용·수치에 출처를 명시하며 마지막에 원본 대비 표절 유사도를 검사합니다.

기존 채용솔루션 분석

기업별 현황 파악 → Select IN 도입 제안

등록 기업
기업을 클릭해 분석 입력
왼쪽에서 기업을 선택하거나 + 기업 추가를 클릭하세요

영업 파이프라인

Select IN · AI · TEST 영업 현황 관리

최근 활동 로그

제안서 발송 현황

영업 파이프라인 편집

관심 제품
영업 단계
예상 계약금액 (원)
담당자
제안서 발송 완료
다음 액션 일정
다음 할 일
활동 로그 추가
메모

GTELP HR CRM

고객사 영업 파이프라인 관리

유형
단계
검색

영업 파이프라인

다음 액션 일정

7일 이내 재컨택 예정

고객사 목록

월 필터
카테고리
상태
카테고리2

활동 목록

월 필터
카테고리
상태

활동 목록

`; const win = window.open('', '_blank'); win.document.write(proposalHtml); win.document.close(); } // 삭제 async function solDelete() { if (!_solCurrentId) return; const name = _solDb[_solCurrentId]?.company_name || ''; if (!confirm(`"${name}" 분석 데이터를 삭제할까요?`)) return; await solDeleteRow(_solCurrentId); delete _solDb[_solCurrentId]; _solCurrentId = null; document.getElementById('sol-edit-panel').style.display = 'none'; document.getElementById('sol-empty-panel').style.display = 'flex'; solRenderList(); } // ══════════════════════════════════════════════════ // 파이프라인 모듈 // ══════════════════════════════════════════════════ const PL_STAGES = [ { id:'cold', label:'콜드콜', color:'#94a3b8', bg:'#f1f5f9' }, { id:'contact', label:'컨택완료', color:'#3b82f6', bg:'#eff6ff' }, { id:'meeting', label:'미팅', color:'#8b5cf6', bg:'#f5f3ff' }, { id:'demo', label:'데모', color:'#f59e0b', bg:'#fffbeb' }, { id:'proposal', label:'제안서', color:'#f97316', bg:'#fff7ed' }, { id:'contract', label:'계약', color:'#10b981', bg:'#ecfdf5' }, { id:'done', label:'완료', color:'#6b7280', bg:'#f9fafb' }, ]; const PL_PROD_COLORS = { IN:'#1d4ed8', AI:'#065f46', TEST:'#5b21b6' }; const PL_ACT_LABELS = { call:'전화', meeting:'미팅', email:'이메일', demo:'데모', proposal:'제안서' }; function plData() { try { return JSON.parse(localStorage.getItem('gtelp_pipeline') || '{}'); } catch(e) { return {}; } } function plSave(d) { localStorage.setItem('gtelp_pipeline', JSON.stringify(d)); } function plGet(name) { return plData()[name] || { products:[], stage:'cold', amount:0, contact:'', proposalSent:false, proposalDate:'', nextAction:'', nextActionDate:'', activities:[], memo:'' }; } function plSet(name, obj) { const d = plData(); d[name] = obj; plSave(d); } function plStageInfo(stageId) { return PL_STAGES.find(s => s.id === stageId) || PL_STAGES[0]; } // 기업별보기 셀 HTML function plCellHtml(name) { const p = plGet(name); const hasPL = p.products.length > 0 || p.stage !== 'cold'; const st = plStageInfo(p.stage); const prodBadges = p.products.map(pr => `${pr}`).join(''); const stageBadge = hasPL ? `${st.label}` : ''; return `
${prodBadges}${stageBadge}
`; } // 모달 열기 (기존 기업) function openPipelineEdit(name) { const p = plGet(name); document.getElementById('pl-modal-title').textContent = name + ' — 영업 파이프라인'; document.getElementById('pl-modal-company').value = name; ['IN','AI','TEST'].forEach(pr => { const btn = document.getElementById('pl-prod-' + pr); btn.className = 'pl-prod-btn' + (p.products.includes(pr) ? ' active-' + pr : ''); }); document.getElementById('pl-stage').value = p.stage || 'cold'; document.getElementById('pl-amount').value = p.amount || ''; document.getElementById('pl-contact').value = p.contact || ''; document.getElementById('pl-proposal-sent').checked = !!p.proposalSent; document.getElementById('pl-proposal-date').value = p.proposalDate || ''; document.getElementById('pl-next-action').value = p.nextAction || ''; document.getElementById('pl-next-date').value = p.nextActionDate || ''; document.getElementById('pl-memo').value = p.memo || ''; document.getElementById('pl-act-date').value = new Date().toISOString().split('T')[0]; plRenderActivityList(p.activities || []); document.getElementById('pipeline-modal').classList.add('open'); } // 모달 열기 (신규) — 기업풀(CRM 고객사 + 기존 파이프라인) 검색 선택 function openPipelineAdd() { const pool = []; const seen = new Set(); (typeof crmCompanies !== 'undefined' ? crmCompanies : []).forEach(c => { const nm = (c.name || c.company_name || '').trim(); if (nm && !seen.has(nm)) { seen.add(nm); pool.push(nm); } }); try { Object.keys(plData()).forEach(nm => { if (nm && !seen.has(nm)) { seen.add(nm); pool.push(nm); } }); } catch(e){} pool.sort((a, b) => a.localeCompare(b, 'ko')); window._plAddPool = pool; let ov = document.getElementById('pl-add-overlay'); if (ov) ov.remove(); ov = document.createElement('div'); ov.id = 'pl-add-overlay'; ov.style.cssText = 'position:fixed;inset:0;z-index:2000;background:rgba(0,0,0,.45);display:flex;align-items:flex-start;justify-content:center;padding-top:12vh;'; ov.onclick = (e) => { if (e.target === ov) ov.remove(); }; ov.innerHTML = '
' + '
' + '
파이프라인에 기업 추가
' + '' + '
' + '
' + '
' + '' + '' + '
' + '
'; document.body.appendChild(ov); const inp = document.getElementById('pl-add-search'); inp.oninput = plAddRender; inp.onkeydown = (e) => { if (e.key === 'Enter') plAddNewTyped(); if (e.key === 'Escape') ov.remove(); }; plAddRender(); setTimeout(() => inp.focus(), 30); } function plAddRender() { const q = (document.getElementById('pl-add-search')?.value || '').trim().toLowerCase(); const pool = window._plAddPool || []; const list = document.getElementById('pl-add-list'); if (!list) return; const filtered = (q ? pool.filter(n => n.toLowerCase().includes(q)) : pool).slice(0, 200); if (!filtered.length) { list.innerHTML = '
기업풀에 일치하는 기업이 없습니다.
아래 \'입력한 이름으로 추가\'로 신규 등록하세요.
'; return; } list.innerHTML = filtered.map(n => '
' + escHtml(n) + '
' ).join(''); } function plAddPick(name) { const ov = document.getElementById('pl-add-overlay'); if (ov) ov.remove(); openPipelineEdit(name); } function plAddNewTyped() { const v = (document.getElementById('pl-add-search')?.value || '').trim(); if (!v) { alert('기업명을 입력하거나 목록에서 선택하세요.'); return; } plAddPick(v); } function closePipelineModal() { document.getElementById('pipeline-modal').classList.remove('open'); } function plToggleProd(pr) { const btn = document.getElementById('pl-prod-' + pr); const isActive = btn.classList.contains('active-' + pr); btn.className = 'pl-prod-btn' + (isActive ? '' : ' active-' + pr); } function plGetSelectedProducts() { return ['IN','AI','TEST'].filter(pr => document.getElementById('pl-prod-' + pr).classList.contains('active-' + pr)); } function plAddActivity() { const date = document.getElementById('pl-act-date').value; const type = document.getElementById('pl-act-type').value; const note = document.getElementById('pl-act-note').value.trim(); if (!date) { alert('날짜를 선택하세요'); return; } const name = document.getElementById('pl-modal-company').value; const p = plGet(name); (p.activities = p.activities || []).unshift({ date, type, note }); plSet(name, p); plRenderActivityList(p.activities); document.getElementById('pl-act-note').value = ''; } function plRenderActivityList(activities) { const el = document.getElementById('pl-activity-list'); el.innerHTML = (activities || []).map((a, i) => `
${a.date} ${PL_ACT_LABELS[a.type] || a.type} ${a.note ? '— ' + a.note : ''}
` ).join('') || '

활동 로그가 없습니다.

'; } function plDeleteActivity(idx) { const name = document.getElementById('pl-modal-company').value; const p = plGet(name); p.activities.splice(idx, 1); plSet(name, p); plRenderActivityList(p.activities); } function deletePipelineCompany() { const name = document.getElementById('pl-modal-company').value; if (!name) return; if (!confirm(`"${name}" 의 파이프라인 데이터를 삭제할까요?`)) return; const d = plData(); delete d[name]; plSave(d); closePipelineModal(); renderMergedTable(); renderPipelineTab(); } function resetPipelineData() { const d = plData(); const count = Object.keys(d).length; if (count === 0) { alert('초기화할 데이터가 없습니다.'); return; } if (!confirm(`파이프라인에 등록된 기업 ${count}개를 모두 초기화할까요?\n이 작업은 되돌릴 수 없습니다.`)) return; localStorage.removeItem('gtelp_pipeline'); renderMergedTable(); renderPipelineTab(); } function savePipelineModal() { const name = document.getElementById('pl-modal-company').value; const p = plGet(name); p.products = plGetSelectedProducts(); p.stage = document.getElementById('pl-stage').value; p.amount = parseInt(document.getElementById('pl-amount').value) || 0; p.contact = document.getElementById('pl-contact').value.trim(); p.proposalSent = document.getElementById('pl-proposal-sent').checked; p.proposalDate = document.getElementById('pl-proposal-date').value; p.nextAction = document.getElementById('pl-next-action').value.trim(); p.nextActionDate = document.getElementById('pl-next-date').value; p.memo = document.getElementById('pl-memo').value; plSet(name, p); closePipelineModal(); renderMergedTable(); renderPipelineTab(); } // 파이프라인 탭 렌더링 var _plFilter = 'all'; function setPipelineFilter(f, btn) { _plFilter = f; document.querySelectorAll('.pl-product-tab').forEach(b => b.classList.remove('active')); if (btn) btn.classList.add('active'); renderPipelineTab(); } function renderPipelineTab() { const all = plData(); const companies = Object.entries(all).filter(([, p]) => _plFilter === 'all' || p.products.includes(_plFilter) ); // 요약 카드 const totalAmount = companies.reduce((s, [, p]) => s + (p.amount || 0), 0); const byStage = {}; PL_STAGES.forEach(s => { byStage[s.id] = 0; }); companies.forEach(([, p]) => { byStage[p.stage] = (byStage[p.stage] || 0) + 1; }); const contracted = (byStage['contract'] || 0) + (byStage['done'] || 0); document.getElementById('pl-summary-cards').innerHTML = [ { label:'총 관리 기업', value: companies.length + '개사', color:'#4f46e5', border:'#4f46e5' }, { label:'예상 계약금액', value: totalAmount ? '₩' + totalAmount.toLocaleString() : '-', color:'#10b981', border:'#10b981' }, { label:'미팅 이상', value: ((byStage['meeting']||0)+(byStage['demo']||0)+(byStage['proposal']||0)+(byStage['contract']||0)+(byStage['done']||0)) + '개사', color:'#8b5cf6', border:'#8b5cf6' }, { label:'계약/완료', value: contracted + '개사', color:'#f59e0b', border:'#f59e0b' }, ].map(c => `
${c.label}
${c.value}
`).join(''); // 칸반 보드 const board = document.getElementById('pl-board'); board.innerHTML = PL_STAGES.map(st => { const cards = companies.filter(([, p]) => p.stage === st.id); return `
${st.label} ${cards.length}
${cards.map(([nm, p]) => `
${nm}
${p.products.map(pr => `${pr}`).join('')}
${p.amount ? `
₩${p.amount.toLocaleString()}
` : ''} ${p.nextAction ? `
→ ${p.nextAction}
` : ''}
`).join('')}
`; }).join(''); // 최근 활동 로그 const recentActs = companies.flatMap(([nm, p]) => (p.activities || []).slice(0,3).map(a => ({ ...a, company: nm })) ).sort((a, b) => b.date.localeCompare(a.date)).slice(0, 10); document.getElementById('pl-activity-log').innerHTML = recentActs.length ? ` ${recentActs.map(a => ``).join('')}
날짜기업활동메모
${a.date} ${a.company} ${PL_ACT_LABELS[a.type] || a.type} ${a.note || ''}
` : '

활동 로그가 없습니다.

'; // 제안서 발송 현황 const proposals = companies.filter(([, p]) => p.products.length > 0); document.getElementById('pl-proposal-status').innerHTML = proposals.length ? ` ${proposals.map(([nm, p]) => ``).join('')}
기업제품발송발송일
${nm} ${p.products.map(pr => `${pr}`).join('')} ${p.proposalSent ? '✓ 발송' : '✕ 미발송'} ${p.proposalDate || '-'}
` : '

등록된 기업이 없습니다.

'; } // 모달 외부 클릭 시 닫기 document.getElementById('pipeline-modal').addEventListener('click', function(e) { if (e.target === this) closePipelineModal(); }); // ── 초기화 ───────────────────────────────────────────── (async () => { await Promise.all([loadSaved(), loadChecks(), loadMemos(), loadGtelpMemos(), loadCustomTasks(), loadGtelpEmojis(), loadCrmSet(), (window.GB ? GB.load() : Promise.resolve())]); renderAll(); // 메모·커스텀 태스크 로드 완료 후 대시보드 재렌더링 if (window.GB) GB.renderAll(); // GTELP 데시보드 렌더 splitStartDates(); extract2025Data(); addCheckboxesToTables(); render2026Companies(); addCrmBadges(); // 2025+2026 통합 통계 업데이트 render2026Months(); updateStats(); document.getElementById('companyTable').classList.add('hidden'); document.getElementById('merged-view').classList.remove('hidden'); renderMergedTable(); // 히어로 헤더 접기 상태 복원 if (localStorage.getItem('heroCollapsed') === '1') { const h = document.getElementById('hero-header'); const btn = document.getElementById('hero-toggle-btn'); if (h) h.classList.add('hero-collapsed'); if (btn) btn.textContent = '펼치기 ▼'; } // 마지막으로 보던 탭 복원 (기본값: 마케팅 대시보드) const savedTab = localStorage.getItem('activeTab') || 'by-gtelp'; const savedBtn = document.querySelector(`.tab-btn[onclick*="${savedTab}"]`); showTab(savedTab, savedBtn || document.querySelector('.tab-btn')); })(); // ── CRM 탭 ────────────────────────────────────────────── function escHtml(s) { if (s === null || s === undefined) return ''; return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,'''); } const CRM_STAGES = [ { id: 'lead', label: '리드', hex: '#888780' }, { id: 'contact', label: '컨택', hex: '#378ADD' }, { id: 'meeting', label: '미팅/시연', hex: '#7F77DD' }, { id: 'proposal', label: '제안', hex: '#BA7517' }, { id: 'closed', label: '계약', hex: '#1D9E75' } ]; const CRM_TYPES = [ { id: 'target', label: '타겟 250사' }, { id: 'trial', label: '무료체험' }, { id: 'paid', label: '유료고객' }, { id: 'partner', label: '제휴/파트너' }, { id: 'large', label: '1000대기업' } ]; const CRM_TYPE_HEX = { target: '#378ADD', trial: '#BA7517', paid: '#1D9E75', partner: '#D85A30', large: '#6C5CE7' }; const CRM_SAMPLE_DATA = [ { id: 1, name: '한국대학교', type: 'target', stage: 'contact', contact: '김인사', phone: '02-1234-5678', email: 'hr@uni.kr', nextDate: '2026-05-28', nextAction: '제안서 발송', memo: '인사팀장 미팅 요청', logs: [{date: '2026-05-15', type: '통화', note: '담당자 첫 컨택, 자료 요청'}]}, { id: 2, name: '글로벌상사', type: 'trial', stage: 'meeting', contact: '이채용', phone: '02-2345-6789', email: 'recruit@global.co.kr', nextDate: '2026-05-25', nextAction: '시연 미팅', memo: '무료체험 진행 중, 만족도 높음', logs: [{date: '2026-05-10', type: '미팅', note: '제품 시연 완료'}]}, { id: 3, name: '미래테크', type: 'paid', stage: 'closed', contact: '박부장', phone: '02-3456-7890', email: 'park@mirai.com', nextDate: '2026-06-01', nextAction: '온보딩 미팅', memo: '유료 전환 완료, 월 3건 채용', logs: [{date: '2026-05-20', type: '계약', note: '연간 계약 체결'}]}, { id: 4, name: '원티드', type: 'partner', stage: 'proposal', contact: '최제휴', phone: '02-4567-8901', email: 'partner@wanted.co.kr', nextDate: '2026-05-30', nextAction: '제휴 조건 협의', memo: 'API 연동 가능성 논의', logs: [{date: '2026-05-12', type: '미팅', note: '제휴 방향성 협의'}]} ]; let crmCompanies = []; let crmFilter = { type: 'all', stage: 'all', search: '' }; let crmEditingId = null; function crmFromRow(row) { const logsData = row.logs; let entries = [], nextDate = '', nextAction = ''; if (Array.isArray(logsData)) { entries = logsData; } else if (logsData && typeof logsData === 'object') { entries = logsData.entries || []; nextDate = logsData.nextDate || ''; nextAction = logsData.nextAction || ''; } return { id: row.id, name: row.company_name || '', contact: row.contact_name || '', phone: row.contact_phone || '', email: row.contact_email || '', email2: row.email2 || '', website: row.website || '', address: row.address || '', stage: row.stage || 'lead', type: row.priority || 'target', memo: row.memo || '', logs: entries, nextDate, nextAction }; } function crmToRow(c) { return { company_name: c.name || '', contact_name: c.contact || null, contact_phone: c.phone || null, contact_email: c.email || null, email2: c.email2 || null, website: c.website || null, address: c.address || null, stage: c.stage || 'lead', priority: c.type || 'target', memo: c.memo || null, logs: { entries: c.logs || [], nextDate: c.nextDate || null, nextAction: c.nextAction || null }, updated_at: new Date().toISOString() }; } async function crmLoadData() { const { data, error } = await _sb.from('gtelp_crm').select('*').order('created_at', { ascending: false }); if (error) { console.error('CRM load error:', error); crmCompanies = []; return; } crmCompanies = (data || []).map(crmFromRow); } function crmGetTypeInfo(id) { return CRM_TYPES.find(t => t.id === id) || CRM_TYPES[0]; } function crmGetStageInfo(id) { return CRM_STAGES.find(s => s.id === id) || CRM_STAGES[0]; } function crmDaysUntil(dateStr) { if (!dateStr) return null; const today = new Date(); today.setHours(0,0,0,0); return Math.round((new Date(dateStr) - today) / 86400000); } function crmRenderMetrics() { const total = crmCompanies.length; const paid = crmCompanies.filter(c => c.type === 'paid').length; const trial = crmCompanies.filter(c => c.type === 'trial').length; const conversion = trial + paid > 0 ? Math.round((paid / (trial + paid)) * 100) : 0; document.getElementById('crm-metrics').innerHTML = `
전체 고객사
${total}
무료체험
${trial}
유료 전환
${paid}
전환율
${conversion}%
`; } function crmPillBtn(label, isActive, onclick, color) { const btn = document.createElement('button'); btn.textContent = label; btn.style.cssText = `padding:4px 10px;font-size:12px;cursor:pointer;border-radius:var(--border-radius-md); border:0.5px solid ${isActive ? (color||'var(--color-border-primary)') : 'var(--color-border-tertiary)'}; background:${isActive ? 'var(--color-background-primary)' : 'transparent'}; color:${isActive && color ? color : 'var(--color-text-primary)'}; font-weight:${isActive ? 500 : 400};`; btn.onclick = onclick; return btn; } function crmRenderFilters() { const tf = document.getElementById('crm-type-filter'); tf.innerHTML = ''; tf.appendChild(crmPillBtn('전체', crmFilter.type === 'all', () => { crmFilter.type = 'all'; crmRenderAll(); })); CRM_TYPES.forEach(t => tf.appendChild(crmPillBtn(t.label, crmFilter.type === t.id, () => { crmFilter.type = t.id; crmRenderAll(); }, CRM_TYPE_HEX[t.id]))); const sf = document.getElementById('crm-stage-filter'); sf.innerHTML = ''; sf.appendChild(crmPillBtn('전체', crmFilter.stage === 'all', () => { crmFilter.stage = 'all'; crmRenderAll(); })); CRM_STAGES.forEach(s => sf.appendChild(crmPillBtn(s.label, crmFilter.stage === s.id, () => { crmFilter.stage = s.id; crmRenderAll(); }, s.hex))); } function crmRenderPipeline() { const pipe = document.getElementById('crm-pipeline'); pipe.innerHTML = ''; CRM_STAGES.forEach(s => { const count = crmCompanies.filter(c => c.stage === s.id).length; const card = document.createElement('div'); card.style.cssText = `background:var(--color-background-secondary);border-top:3px solid ${s.hex}; border-radius:0 0 var(--border-radius-md) var(--border-radius-md);padding:10px;text-align:center;cursor:pointer;`; card.innerHTML = `
${s.label}
${count}
`; card.onclick = () => { crmFilter.stage = s.id; crmRenderAll(); }; pipe.appendChild(card); }); } function crmRenderUpcoming() { const upcoming = crmCompanies .filter(c => { const d = crmDaysUntil(c.nextDate); return d !== null && d <= 7 && d >= -3; }) .sort((a,b) => new Date(a.nextDate) - new Date(b.nextDate)); document.getElementById('crm-upcoming-count').textContent = `· ${upcoming.length}건`; const list = document.getElementById('crm-upcoming-list'); list.innerHTML = ''; if (upcoming.length === 0) { list.innerHTML = '
예정된 액션이 없습니다
'; return; } upcoming.forEach(c => { const days = crmDaysUntil(c.nextDate); let urgency, urgencyColor, urgencyBg; if (days < 0) { urgency = `${-days}일 지남`; urgencyColor = 'var(--color-text-danger)'; urgencyBg = 'var(--color-background-danger)'; } else if (days === 0) { urgency = '오늘'; urgencyColor = 'var(--color-text-danger)'; urgencyBg = 'var(--color-background-danger)'; } else if (days <= 2) { urgency = `D-${days}`; urgencyColor = 'var(--color-text-warning)'; urgencyBg = 'var(--color-background-warning)'; } else { urgency = `D-${days}`; urgencyColor = 'var(--color-text-info)'; urgencyBg = 'var(--color-background-info)'; } const row = document.createElement('div'); row.style.cssText = `background:var(--color-background-primary);border:0.5px solid var(--color-border-tertiary); border-radius:var(--border-radius-md);padding:8px 12px;display:grid;grid-template-columns:60px 1fr auto;gap:10px;align-items:center;cursor:pointer;`; row.innerHTML = ` ${urgency}
${escHtml(c.name)}
${escHtml(c.nextAction)||'액션 미정'}
${escHtml(c.nextDate)}`; row.onclick = () => crmOpenEdit(c.id); list.appendChild(row); }); } function crmRenderCompanies() { const filtered = crmCompanies.filter(c => { if (crmFilter.type !== 'all' && c.type !== crmFilter.type) return false; if (crmFilter.stage !== 'all' && c.stage !== crmFilter.stage) return false; if (crmFilter.search) { const q = crmFilter.search.toLowerCase(); if (!(c.name?.toLowerCase().includes(q) || c.contact?.toLowerCase().includes(q) || c.memo?.toLowerCase().includes(q))) return false; } return true; }); document.getElementById('crm-list-count').textContent = `· ${filtered.length}건`; const list = document.getElementById('crm-company-list'); list.innerHTML = ''; if (filtered.length === 0) { list.innerHTML = '
등록된 고객사가 없습니다. 상단의 "고객사 추가" 또는 "데이터 업로드"를 눌러보세요.
'; return; } filtered.forEach(c => { const t = crmGetTypeInfo(c.type); const s = crmGetStageInfo(c.stage); const typeColor = CRM_TYPE_HEX[c.type] || '#888'; const logsCount = (c.logs||[]).length; const card = document.createElement('div'); card.style.cssText = `background:${c.email ? '#1d4ed8' : 'var(--color-background-primary)'};border:0.5px solid ${c.email ? '#3b82f6' : 'var(--color-border-tertiary)'}; border-left:3px solid ${c.email ? '#93c5fd' : typeColor};padding:12px 14px;cursor:pointer;${c.email ? 'color:white;' : ''}`; const em = !!c.email; card.innerHTML = `
${escHtml(c.name) || '(이름없음)'} ${t.label}
${escHtml(c.contact)||'담당자 미정'} · ${escHtml(c.phone)||'연락처 없음'}
${s.label}
${c.memo ? `
${escHtml(c.memo)}
` : ''}
${c.nextDate ? `${escHtml(c.nextDate)} ${escHtml(c.nextAction)||''}` : ''} 활동 ${logsCount}건
`; card.onclick = () => crmOpenEdit(c.id); list.appendChild(card); }); } async function crmOpenEdit(id) { crmEditingId = id; let c; if (id) { // 클릭 시마다 최신 데이터를 DB에서 다시 조회 const { data } = await _sb.from('gtelp_crm').select('*').eq('id', id); const fresh = data?.[0]; if (fresh) { c = crmFromRow(fresh); // 메모리 캐시도 최신으로 갱신 const idx = crmCompanies.findIndex(x => x.id === id); if (idx >= 0) crmCompanies[idx] = c; } else { c = crmCompanies.find(x => x.id === id) || { id: null, name: '', type: 'target', stage: 'lead', contact: '', phone: '', email: '', email2: '', website: '', address: '', nextDate: '', nextAction: '', memo: '', logs: [] }; } } else { c = { id: null, name: '', type: 'target', stage: 'lead', contact: '', phone: '', email: '', email2: '', website: '', address: '', nextDate: '', nextAction: '', memo: '', logs: [] }; } const bg = document.getElementById('crm-modal-bg'); const content = document.getElementById('crm-modal-content'); const logsHtml = (c.logs||[]).map(log => `
${escHtml(log.type)} ${escHtml(log.date)}
${escHtml(log.note)}
`).join(''); const LBL = 'font-size:12px;color:#94b8d8;display:block;margin-bottom:5px;'; const INP = 'width:100%;padding:8px 10px;font-size:14px;box-sizing:border-box;border-radius:6px;border:1px solid #1e3f63;background:#122d4e;color:#e8f0fb;'; const SEL = INP; content.innerHTML = `

${id ? '고객사 편집' : '신규 고객사'}

활동 로그 (${(c.logs||[]).length}건)
${logsHtml}
솔루션 분석 데이터 확인 중...
`; bg.style.display = 'block'; crmLoadSolAnalysis(c.name); document.getElementById('crm-m-close').onclick = crmCloseModal; document.getElementById('crm-m-cancel').onclick = crmCloseModal; document.getElementById('crm-m-save').onclick = () => crmSaveForm(); document.getElementById('crm-m-delete').onclick = async () => { if (!id || !confirm('이 고객사를 삭제하시겠습니까?')) return; const btn = document.getElementById('crm-m-delete'); btn.disabled = true; btn.textContent = '삭제 중...'; const { error } = await _sb.from('gtelp_crm').delete().eq('id', id); if (error) { alert('삭제 실패: ' + error.message); btn.disabled = false; btn.textContent = '삭제'; return; } crmCompanies = crmCompanies.filter(x => x.id !== id); crmCloseModal(); crmRenderAll(); }; document.getElementById('crm-log-add').onclick = async () => { const date = document.getElementById('crm-log-date').value; const type = document.getElementById('crm-log-type').value; const note = document.getElementById('crm-log-note').value; if (!note.trim()) { alert('활동 내용을 입력해주세요'); return; } const tc = id ? crmCompanies.find(x => x.id === id) : null; if (!tc) { alert('먼저 저장한 뒤 활동 로그를 추가해주세요'); return; } tc.logs = tc.logs || []; tc.logs.unshift({ date, type, note }); const logPayload = { entries: tc.logs, nextDate: tc.nextDate || null, nextAction: tc.nextAction || null }; const { data, error } = await _sb.from('gtelp_crm').update({ logs: logPayload, updated_at: new Date().toISOString() }).eq('id', id).select(); if (error) { alert('저장 실패: ' + error.message); return; } const idx = crmCompanies.findIndex(x => x.id === id); if (idx >= 0) crmCompanies[idx] = crmFromRow(data?.[0]); crmOpenEdit(id); }; } async function crmLoadSolAnalysis(companyName) { const badge = document.getElementById('crm-sol-badge'); const content = document.getElementById('crm-sol-content'); if (!badge || !content) return; try { const { data } = await _sb.from('gtelp_solution_db').select('*') .ilike('company_name', companyName.trim()); if (!data || !data.length) { badge.textContent = '데이터 없음'; badge.style.background = '#1a2a3a'; badge.style.color = '#6b7280'; content.innerHTML = `솔루션 분석 데이터가 없습니다. → 솔루션분석 탭에서 추가`; return; } const r = data[0]; badge.textContent = '✓ 분석 있음'; badge.style.background = '#0d3321'; badge.style.color = '#4ade80'; const totalFeatures = (typeof SOL_CATEGORIES !== 'undefined' ? SOL_CATEGORIES : []).reduce((s, c) => s + c.features.length, 0) || 28; const totalHas = ['ats','exam','aptitude','language'].reduce((s, cat) => s + ((r[cat+'_features'] || []).length), 0); const coverRate = totalFeatures ? Math.round(totalHas / totalFeatures * 100) : 0; const totalLack = totalFeatures - totalHas; const catRows = ['ats','exam','aptitude','language'].map(cat => { const catInfo = (typeof SOL_CATEGORIES !== 'undefined' ? SOL_CATEGORIES : []).find(c => c.id === cat); const label = catInfo ? catInfo.label : cat; const product = catInfo ? catInfo.product : ''; const feats = r[cat + '_features'] || []; const total = catInfo ? catInfo.features.length : 0; const pct = total ? Math.round(feats.length / total * 100) : 0; const barW = pct; return `
${label} ${feats.length}/${total} (${pct}%)
${feats.length ? `
${feats.join(' · ')}
` : ''}
`; }).join(''); // 갭분석: 솔루션분석 탭과 동일한 4열 구조 const _cats = typeof SOL_CATEGORIES !== 'undefined' ? SOL_CATEGORIES : []; const _totalLackCount = _cats.reduce((s, cat) => { const feats = r[cat.id + '_features'] || []; return s + cat.features.filter(f => !feats.includes(f)).length; }, 0); const gapCatRows = _cats.map((cat, i) => { const feats = r[cat.id + '_features'] || []; const lacks = cat.features.filter(f => !feats.includes(f)); const hasHtml = feats.length ? feats.map(f => `
✓ ${f}
`).join('') : '없음'; const lackHtml = lacks.length ? lacks.map(f => `
✗ ${f}
`).join('') : '모두 보유'; const improveHtml = lacks.length ? `
${cat.product}에서
${lacks.length}개 기능 제공
` : '추가 개선 없음'; return ` ${cat.icon} ${cat.label} ${hasHtml} ${lackHtml} ${improveHtml} `; }).join(''); const gapSection = `
갭분석 — 부재 기능 & 개선 제안 → 상세 페이지
${gapCatRows}
카테고리 보유 기능 부재 기능 (페인포인트) 개선 솔루션
${_totalLackCount ? `
총 ${_totalLackCount}개 기능 미보유 → G-TELP 솔루션으로 보완 가능
` : `
모든 기능 커버 — 페인포인트 없음
`}
`; content.innerHTML = `
${coverRate}%
기능 커버율
${totalLack}개
페인포인트
솔루션: ${r.solution_name || '-'} / 공급사: ${r.vendor || '-'}
${r.notes ? `
${r.notes}
` : ''}
${catRows} ${gapSection}
`; } catch(e) { if (content) content.innerHTML = `로드 실패: ${e.message}`; } } function crmSolGoAnalyze(name) { crmCloseModal(); const btn = document.querySelector('.tab-btn[onclick*="by-solution"]'); showTab('by-solution', btn); setTimeout(() => { const items = document.querySelectorAll('.sol-company-item'); for (const el of items) { if (el.querySelector('span')?.textContent === name) { el.click(); break; } } }, 400); } async function crmSolProposal(name) { const { data } = await _sb.from('gtelp_solution_db').select('*').ilike('company_name', name); if (!data || !data.length) { alert('분석 데이터가 없습니다.'); return; } document.getElementById('sol-json-input').value = JSON.stringify(data[0]); solLoadJson(); solProposal(); } async function crmSaveForm() { const name = document.getElementById('crm-f-name').value.trim(); if (!name) { alert('회사명을 입력해주세요'); return; } const id = crmEditingId; const isNew = !id; const saveBtn = document.getElementById('crm-m-save'); saveBtn.disabled = true; saveBtn.textContent = '저장 중...'; const localData = { name, contact: document.getElementById('crm-f-contact').value.trim(), phone: document.getElementById('crm-f-phone').value.trim(), email: document.getElementById('crm-f-email').value.trim(), email2: document.getElementById('crm-f-email2').value.trim(), website: document.getElementById('crm-f-website').value.trim(), address: document.getElementById('crm-f-address').value.trim(), type: document.getElementById('crm-f-type').value, stage: document.getElementById('crm-f-stage').value, nextDate: document.getElementById('crm-f-nextDate').value, nextAction: document.getElementById('crm-f-nextAction').value.trim(), memo: document.getElementById('crm-f-memo').value.trim(), logs: isNew ? [] : (crmCompanies.find(x => x.id === id)?.logs || []) }; const row = crmToRow(localData); let result; if (isNew) { result = await _sb.from('gtelp_crm').insert(row).select(); } else { result = await _sb.from('gtelp_crm').update(row).eq('id', id).select(); } if (result.error) { alert('저장 실패: ' + result.error.message); saveBtn.disabled = false; saveBtn.textContent = '저장'; return; } const saved = crmFromRow(result.data?.[0]); if (isNew) { crmCompanies.unshift(saved); } else { const idx = crmCompanies.findIndex(x => x.id === id); if (idx >= 0) crmCompanies[idx] = saved; } crmCloseModal(); crmRenderAll(); } // ═══════════════════════════════════════════════ // HR뉴스 기능 // ═══════════════════════════════════════════════ let newsResults = []; let allSavedNews = []; // ═══════════════════════════════════════════════ // 월간뉴스 작성 (다중 입력 → AI 종합·재작성 → 표절 유사도 → 기사화) // ═══════════════════════════════════════════════ let _nmArticle = null; // 관리자 비밀번호 SHA-256 해시 (평문 비저장 · 역산 불가). 입력값과 비교만 함. const NM_PW_HASH = 'f6f730f0fdfbcdf82220e69960481e0c0197b865a27184ba063a19230df619c2'; async function nmSha256(s) { const b = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s)); return [...new Uint8Array(b)].map(x => x.toString(16).padStart(2, '0')).join(''); } function nmInputBlock(i) { return '
' + '' + i + '' + '' + '' + '
'; } function nmRenumber() { document.querySelectorAll('#nm-inputs .nm-row').forEach((row, idx) => { row.querySelector('.nm-no').textContent = idx + 1; row.querySelector('textarea').placeholder = '기사 ' + (idx + 1) + ' 원문을 붙여넣으세요'; }); } function nmAddInput() { const wrap = document.getElementById('nm-inputs'); if (!wrap) return; const tmp = document.createElement('div'); tmp.innerHTML = nmInputBlock(wrap.children.length + 1); wrap.appendChild(tmp.firstChild); } function nmRemoveInput(btn) { const row = btn.closest('.nm-row'); if (document.querySelectorAll('#nm-inputs .nm-row').length <= 1) { row.querySelector('textarea').value = ''; return; } row.remove(); nmRenumber(); } function nmInit() { const wrap = document.getElementById('nm-inputs'); if (wrap && !wrap.children.length) { nmAddInput(); nmAddInput(); } nmSavedLoad(); } // ── 월간뉴스 저장 (Supabase: gtelp_monthly_news) + 기사 댓글(gtelp_news_comments) ── let _nmSaved = []; async function nmSavedLoad() { const el = document.getElementById('nm-saved'); try { await nmMigrateLocal(); // 과거 localStorage 보관분 1회 이전 const { data, error } = await _sb.from('gtelp_monthly_news').select('*').order('created_at', { ascending: false }); if (error) throw error; _nmSaved = data || []; nmSavedList(); } catch(e) { if (el) el.innerHTML = '
저장 목록 불러오기 실패: ' + escHtml(e.message) + '
gtelp_monthly_news / gtelp_news_comments 테이블이 없으면 안내 SQL(supabase_monthly_news.sql)을 Supabase에서 먼저 실행하세요.
'; } } // 기존 localStorage 보관분을 Supabase로 1회 이전(성공 시 로컬 삭제) async function nmMigrateLocal() { let old = []; try { old = JSON.parse(localStorage.getItem('gtelp_monthly_news') || '[]'); } catch(e) {} if (!old.length) return; try { for (const it of old) { const { error } = await _sb.from('gtelp_monthly_news').insert({ date: it.date || new Date().toISOString().slice(0, 10), headline: (it.art && it.art.headline) || '(제목 없음)', art: it.art || it }); if (error) throw error; } localStorage.removeItem('gtelp_monthly_news'); } catch(e) { /* 이전 실패 시 다음 기회에 재시도 */ } } async function nmSave() { if (!_nmArticle) return; const s = document.getElementById('nm-status'); try { const { error } = await _sb.from('gtelp_monthly_news').insert({ date: new Date().toISOString().slice(0, 10), headline: _nmArticle.headline || '(제목 없음)', art: _nmArticle }); if (error) throw error; if (s) { s.textContent = '저장됨 (아래 목록)'; s.style.color = '#16a34a'; } await nmSavedLoad(); } catch(e) { if (s) { s.textContent = '저장 실패: ' + e.message; s.style.color = '#dc2626'; } } } async function nmSavedDelete(id) { if (!confirm('이 월간뉴스를 삭제할까요? (댓글도 함께 삭제됩니다)')) return; try { const { error } = await _sb.from('gtelp_monthly_news').delete().eq('id', id); if (error) throw error; await nmSavedLoad(); } catch(e) { alert('삭제 실패: ' + e.message); } } function nmSavedView(id) { const it = _nmSaved.find(x => String(x.id) === String(id)); if (it) { _nmArticle = it.art; nmOpenHtml(); } } function nmSavedList() { const el = document.getElementById('nm-saved'); if (!el) return; if (!_nmSaved.length) { el.innerHTML = '
저장된 월간뉴스가 없습니다.
'; return; } el.innerHTML = '
' + '

저장된 월간뉴스 ' + _nmSaved.length + '건

' + _nmSaved.map(it => { const head = escHtml((it.art && it.art.headline) || it.headline || '(제목 없음)'); const dt = it.date || (it.created_at || '').slice(0, 10); return '
' + '
' + '' + dt + '' + '' + head + '' + '' + '' + '' + '
' + '' + '
'; }).join('') + '
'; } // ── 기사 댓글 (gtelp_news_comments) ── function nmcToggle(id) { const wrap = document.getElementById('nmc-wrap-' + id); if (!wrap) return; if (wrap.style.display === 'none') { wrap.style.display = 'block'; nmcLoad(id); } else wrap.style.display = 'none'; } async function nmcLoad(newsId) { const box = document.getElementById('nmc-list-' + newsId); if (!box) return; box.innerHTML = '
댓글 불러오는 중...
'; try { const { data, error } = await _sb.from('gtelp_news_comments').select('*').eq('news_id', newsId).order('created_at', { ascending: true }); if (error) throw error; nmcRender(newsId, data || []); } catch(e) { box.innerHTML = '
댓글 불러오기 실패: ' + escHtml(e.message) + '
gtelp_news_comments 테이블이 없으면 SQL을 먼저 실행하세요.
'; } } function nmcRender(newsId, comments) { const box = document.getElementById('nmc-list-' + newsId); if (!box) return; if (!comments.length) { box.innerHTML = '
아직 댓글이 없습니다.
'; return; } box.innerHTML = comments.map(c => { const date = (c.created_at || '').slice(0, 16).replace('T', ' '); const edited = (c.updated_at && c.created_at && c.updated_at.slice(0,16) !== c.created_at.slice(0,16)) ? ' (수정됨)' : ''; return '
' + '' + escHtml(c.author || '-') + '' + '
' + '
' + escHtml(c.content || '') + '
' + '
' + date + edited + '
' + '
' + '' + '' + '' + '' + '
'; }).join(''); } async function nmcSave(newsId) { const author = document.getElementById('nmc-author-' + newsId).value.trim(); const content = document.getElementById('nmc-input-' + newsId).value.trim(); if (!content) { alert('댓글 내용을 입력하세요.'); return; } try { const { error } = await _sb.from('gtelp_news_comments').insert({ news_id: newsId, author, content }); if (error) throw error; document.getElementById('nmc-input-' + newsId).value = ''; nmcLoad(newsId); } catch(e) { alert('댓글 등록 실패: ' + e.message); } } async function nmcDelete(newsId, cid) { if (!confirm('댓글을 삭제할까요?')) return; try { const { error } = await _sb.from('gtelp_news_comments').delete().eq('id', cid); if (error) throw error; nmcLoad(newsId); } catch(e) { alert('삭제 실패: ' + e.message); } } function nmcEdit(newsId, cid) { const el = document.getElementById('nmc-' + cid); if (!el) return; if (el.querySelector('.nmc-editbox')) return; const textDiv = el.querySelector('.nmc-text'); const cur = textDiv.textContent; textDiv.style.display = 'none'; const box = document.createElement('div'); box.className = 'nmc-editbox'; box.style.marginTop = '4px'; box.innerHTML = '' + '
' + '' + '' + '
'; textDiv.parentNode.insertBefore(box, textDiv.nextSibling); const ta = box.querySelector('textarea'); ta.value = cur; ta.focus(); box.querySelector('.cmt-cancel').onclick = () => { box.remove(); textDiv.style.display = ''; }; box.querySelector('.cmt-save').onclick = async () => { const v = ta.value.trim(); if (!v) return; try { const { error } = await _sb.from('gtelp_news_comments').update({ content: v, updated_at: new Date().toISOString() }).eq('id', cid); if (error) throw error; nmcLoad(newsId); } catch(e) { alert('수정 실패: ' + e.message); } }; } function nmCollect() { return [...document.querySelectorAll('#nm-inputs .nm-src')].map(t => t.value.trim()).filter(Boolean); } function nmToken() { return new Promise(async (resolve) => { try { const { data } = await _sb.auth.getSession(); if (data && data.session && data.session.access_token) { resolve(data.session.access_token); return; } } catch(e){} let ov = document.getElementById('nm-login-overlay'); if (ov) ov.remove(); ov = document.createElement('div'); ov.id = 'nm-login-overlay'; ov.style.cssText = 'position:fixed;inset:0;z-index:3000;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;padding:16px;'; ov.innerHTML = '
' + '
관리자 로그인
' + '
AI 생성을 위해 Supabase 인증이 필요합니다.
' + '' + '' + '
' + '
' + '' + '' + '
' + '
'; document.body.appendChild(ov); const pwEl = document.getElementById('nm-login-pw'); const errEl = document.getElementById('nm-login-err'); const goBtn = document.getElementById('nm-login-go'); const close = (val) => { ov.remove(); resolve(val); }; document.getElementById('nm-login-cancel').onclick = () => close(null); ov.onclick = (e) => { if (e.target === ov) close(null); }; const doLogin = async () => { const email = document.getElementById('nm-login-email').value.trim(); const pw = pwEl.value; if (!email || !pw) { errEl.textContent = '이메일과 비밀번호를 입력하세요.'; return; } goBtn.disabled = true; goBtn.textContent = '확인 중...'; errEl.textContent = ''; // 1) 해시 게이트 (로컬 검증 — 소스엔 해시만 존재) const h = await nmSha256(pw); if (h !== NM_PW_HASH) { errEl.textContent = '비밀번호가 올바르지 않습니다.'; goBtn.disabled = false; goBtn.textContent = '로그인'; return; } // 2) Supabase 인증으로 실제 토큰 발급 const { data, error } = await _sb.auth.signInWithPassword({ email, password: pw }); if (error) { errEl.textContent = 'Supabase 인증 실패: ' + error.message + ' (해시는 통과 — 비번이 Supabase 계정과 달라요)'; goBtn.disabled = false; goBtn.textContent = '로그인'; return; } close(data.session.access_token); }; goBtn.onclick = doLogin; pwEl.onkeydown = (e) => { if (e.key === 'Enter') doLogin(); }; setTimeout(() => pwEl.focus(), 50); }); } // n-gram(3) 겹침 비율: 출력의 몇 %가 원문과 겹치는가 (표절 유사도) function nmGrams(s) { const t = (s || '').replace(/\s+/g, '').toLowerCase(); const set = new Set(); for (let i = 0; i < t.length - 2; i++) set.add(t.slice(i, i + 3)); return set; } function nmOverlap(out, src) { const O = nmGrams(out), S = nmGrams(src); if (!O.size) return 0; let inter = 0; O.forEach(g => { if (S.has(g)) inter++; }); return Math.round(inter / O.size * 100); } function nmBuildPrompt(srcs) { const joined = srcs.map((t, i) => '--- 기사 ' + (i + 1) + ' ---\n' + t).join('\n\n'); return '당신은 베테랑 방송 뉴스 작가입니다. 아래 여러 기사 원문을 종합하여 하나의 월간 HR 뉴스 기사를 작성하세요.\n\n' + '[요구사항]\n' + '1. 여러 원문의 핵심을 종합·요약해 하나의 일관된 기사로 작성한다.\n' + '2. 저작권 안전(매우 중요): 원문의 단어와 어순을 적극적으로 바꿔 표현을 완전히 새로 쓰되 사실과 맥락은 유지한다. ' + '원문 문장을 그대로 베끼지 않으며, 원문 문구를 3어절 이상 연속으로 동일하게 쓰지 않는다. 동의어·다른 문장구조로 바꿔 원본 대비 표절 유사도가 15% 이하가 되도록 작성한다.\n' + '3. 아나운서 화법: 신뢰감 있고 명료한 방송 뉴스 톤으로 쓴다(예: "~로 나타났습니다", "전해드립니다", "~할 전망입니다").\n' + '4. 한국어로 작성한다.\n' + '5. 출처 명시(중요): 직접 인용문과 구체적인 수치·통계(예: "24% 감축", "○○% 증가")는 반드시 1차 출처(각 기업 보도자료, 기관 발표 등)를 본문에 함께 밝힌다. ' + '원문에 출처가 명시되어 있으면 그 출처를 그대로 인용하고, 원문에 출처가 없으면 해당 수치·인용 뒤에 "(출처 확인 필요)"로 표기한다. 출처를 임의로 지어내지 않는다.\n' + '6. 기사에서 인용·참고한 출처를 sources 배열에 정리한다(원문에 출처가 없으면 "출처 확인 필요" 항목을 포함).\n\n' + '반드시 아래 JSON 형식으로만 응답한다(설명 없이 JSON만):\n' + '{\n "headline": "기사 제목",\n "lead": "리드문 1-2문장",\n "body": "본문(문단 구분은 \\n\\n)",\n "tags": ["키워드1","키워드2","키워드3"],\n "sources": ["출처1","출처2"]\n}\n\n' + '[원문들]\n' + joined; } // AI 호출(JSON 파싱까지) — 공통 헬퍼 async function nmCallAI(prompt, token) { const resp = await fetch('/api/ai-insights', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ prompt }) }); const data = await resp.json(); if (!resp.ok) throw new Error(data.error || ('HTTP ' + resp.status)); let raw = ((data.content && data.content[0] && data.content[0].text) || '').trim(); raw = raw.replace(/^```json\s*/i, '').replace(/^```\s*/, '').replace(/```$/, '').trim(); try { return JSON.parse(raw); } catch(e) { return { headline: '월간 HR 뉴스', lead: '', body: raw, tags: [] }; } } // 기사 ↔ 원문들 최대 유사도 산출 function nmMaxSim(art, srcs) { const bodyText = (art.lead ? art.lead + '\n\n' : '') + (art.body || ''); const sims = srcs.map((s, i) => ({ i: i + 1, pct: nmOverlap(bodyText, s) })); return { sims, max: sims.length ? Math.max(...sims.map(s => s.pct)) : 0 }; } // 유사도 낮추기용 재작성 프롬프트 function nmReducePrompt(srcs, prevArt, curPct, target) { const joined = srcs.map((t, i) => '--- 기사 ' + (i + 1) + ' ---\n' + t).join('\n\n'); const prevText = (prevArt.headline || '') + '\n' + (prevArt.lead || '') + '\n' + (prevArt.body || ''); return '아래 [현재기사]는 [원문들]과의 표절 유사도가 ' + curPct + '%로 목표(' + target + '% 이하)보다 높습니다. ' + '사실·고유명사·수치·출처는 그대로 유지하면서 표현만 더 강하게 바꿔, 원문과 겹치는 표현을 최소화한 새 기사를 작성하세요.\n\n' + '[재작성 지침]\n' + '1. 문장 구조와 어순을 전면 재배열하고, 동의어·다른 표현으로 바꾼다(사실·고유명사·수치·출처는 유지).\n' + '2. 원문 문구를 3어절 이상 연속으로 동일하게 쓰지 않는다. 원본 대비 유사도 ' + target + '% 이하를 목표로 한다.\n' + '3. 직접 인용문과 구체 수치는 1차 출처를 계속 명시한다(원문에 출처 없으면 "(출처 확인 필요)").\n' + '4. 아나운서 톤·한국어를 유지한다.\n\n' + '반드시 아래 JSON 형식으로만 응답한다(설명 없이 JSON만):\n' + '{\n "headline": "기사 제목",\n "lead": "리드문 1-2문장",\n "body": "본문(문단 구분은 \\n\\n)",\n "tags": ["키워드1","키워드2","키워드3"],\n "sources": ["출처1","출처2"]\n}\n\n' + '[현재기사]\n' + prevText + '\n\n[원문들]\n' + joined; } async function nmGenerate() { const srcs = nmCollect(); const status = document.getElementById('nm-status'); if (!srcs.length) { status.textContent = '기사 원문을 1개 이상 입력하세요.'; status.style.color = '#dc2626'; return; } const prompt = nmBuildPrompt(srcs); if (prompt.length > 23000) { status.textContent = '원문이 너무 깁니다(약 ' + Math.round(prompt.length/1000) + 'k자). 일부 줄여 주세요.'; status.style.color = '#dc2626'; return; } status.textContent = '관리자 인증 확인 중...'; status.style.color = '#6b7280'; const token = await nmToken(); if (!token) { status.textContent = '관리자 로그인이 필요합니다.'; status.style.color = '#dc2626'; return; } const TARGET = 15, MAX_TRY = 4; try { status.textContent = 'AI가 종합·재작성 중... (10~30초)'; let best = await nmCallAI(prompt, token); let bestPct = nmMaxSim(best, srcs).max; let tries = 0; // 목표 유사도 초과 시, 더 강하게 재작성 반복 (가장 낮은 결과 채택) while (bestPct > TARGET && tries < MAX_TRY) { tries++; status.textContent = '표절 유사도 ' + bestPct + '% → ' + TARGET + '% 이하로 재작성 중... (' + tries + '/' + MAX_TRY + ')'; const rprompt = nmReducePrompt(srcs, best, bestPct, TARGET); if (rprompt.length > 24000) break; let next; try { next = await nmCallAI(rprompt, token); } catch(e) { break; } const npct = nmMaxSim(next, srcs).max; if (npct < bestPct) { best = next; bestPct = npct; } // 더 낮아진 경우만 채택 } _nmArticle = best; nmRenderResult(best, srcs); if (bestPct <= TARGET) { status.textContent = '생성 완료 · 표절 유사도 ' + bestPct + '% (목표 ' + TARGET + '% 이하 달성)'; status.style.color = '#16a34a'; } else { status.textContent = '생성 완료 · 표절 유사도 ' + bestPct + '% (재작성 ' + tries + '회, 최저값 채택 — 다시 작성으로 추가 시도 가능)'; status.style.color = '#d97706'; } } catch(e) { status.textContent = '생성 실패: ' + e.message; status.style.color = '#dc2626'; } } function nmRenderResult(art, srcs) { const el = document.getElementById('nm-result'); el.style.display = 'block'; const bodyText = (art.lead ? art.lead + '\n\n' : '') + (art.body || ''); const sims = srcs.map((s, i) => ({ i: i + 1, pct: nmOverlap(bodyText, s) })); const maxPct = sims.length ? Math.max(...sims.map(s => s.pct)) : 0; art._sim = { max: maxPct, list: sims.map(s => ({ i: s.i, pct: s.pct })) }; // 표절검사 결과를 기사에 보존(저장·HTML 출력용) const col = p => p < 20 ? '#16a34a' : p < 40 ? '#d97706' : '#dc2626'; const lab = p => p < 20 ? '안전' : p < 40 ? '주의' : '위험'; const paras = (art.body || '').split(/\n{2,}/).filter(Boolean).map(p => '

' + escHtml(p) + '

').join(''); const tags = (art.tags || []).map(t => '#' + escHtml(t) + '').join(''); const srcList = Array.isArray(art.sources) ? art.sources.filter(Boolean) : []; const sourcesHtml = srcList.length ? '
출처
    ' + srcList.map(s => '
  1. ' + escHtml(s) + '
  2. ').join('') + '
' : ''; el.innerHTML = '
' + '
표절 유사도 (원본 대비)
' + '
' + maxPct + '%
' + '' + lab(maxPct) + '' + '' + sims.map(s => '기사' + s.i + ' ' + s.pct + '%').join(' · ') + '' + '
' + '
' + '
MONTHLY HR NEWS
' + '

' + escHtml(art.headline || '') + '

' + (art.lead ? '

' + escHtml(art.lead) + '

' : '') + paras + (tags ? '
' + tags + '
' : '') + sourcesHtml + '
' + '
' + '' + '' + '' + '' + '
'; } function nmCopy() { const a = _nmArticle; if (!a) return; const txt = (a.headline || '') + '\n\n' + (a.lead ? a.lead + '\n\n' : '') + (a.body || ''); navigator.clipboard.writeText(txt).then(() => { const s = document.getElementById('nm-status'); s.textContent = '복사됨'; s.style.color = '#16a34a'; }); } function nmOpenHtml() { const a = _nmArticle; if (!a) return; const today = new Date().toLocaleDateString('ko-KR'); const paras = (a.body || '').split(/\n{2,}/).filter(Boolean).map(p => '

' + escHtml(p) + '

').join(''); const tags = (a.tags || []).map(t => '#' + escHtml(t) + '').join(''); const srcList = Array.isArray(a.sources) ? a.sources.filter(Boolean) : []; const sourcesHtml = srcList.length ? '
출처
    ' + srcList.map(s => '
  1. ' + escHtml(s) + '
  2. ').join('') + '
' : ''; const sim = a._sim; const simHtml = sim ? '
표절검사 결과 · 원본 대비 최대 유사도 ' + sim.max + '% (' + (sim.max < 20 ? '안전' : sim.max < 40 ? '주의' : '위험') + ')' + (sim.list && sim.list.length ? ' · ' + sim.list.map(s => '기사' + s.i + ' ' + s.pct + '%').join(' · ') : '') + '
' : ''; const html = '' + escHtml(a.headline || '월간 HR 뉴스') + '' + '' + '
MONTHLY HR NEWS
' + '

' + escHtml(a.headline || '') + '

' + '
GTELP HR · ' + today + '
' + (a.lead ? '
' + escHtml(a.lead) + '
' : '') + paras + (tags ? '
' + tags + '
' : '') + sourcesHtml + simHtml + ' '; const w = window.open('', '_blank'); w.document.write(html); w.document.close(); } // ═══════════════════════════════════════════════ // 업무보고 게시판 (Supabase: gtelp_work_reports) // ═══════════════════════════════════════════════ let _wrData = []; let _wrAtt = []; // 현재 폼의 첨부 목록 [{name,url,path,size}] const WR_BUCKET = 'work-reports'; function wrRenderAttForm() { const box = document.getElementById('wr-att-list'); if (!box) return; box.innerHTML = _wrAtt.map((a, i) => '' + '📎 ' + escHtml(a.name) + '' + '' + '' ).join(''); } function wrRemoveAtt(i) { _wrAtt.splice(i, 1); wrRenderAttForm(); } async function wrLoad() { const list = document.getElementById('wr-list'); if (list) list.innerHTML = '
불러오는 중...
'; try { const { data, error } = await _sb.from('gtelp_work_reports').select('*').order('created_at', { ascending: false }); if (error) throw error; _wrData = data || []; wrRender(); } catch(e) { if (list) list.innerHTML = '
불러오기 실패: ' + escHtml(e.message) + '
gtelp_work_reports 테이블이 없으면 안내된 SQL을 Supabase에서 먼저 실행하세요.
'; } } function wrRender() { const list = document.getElementById('wr-list'); if (!list) return; const q = (document.getElementById('wr-search') ? document.getElementById('wr-search').value : '').trim().toLowerCase(); let rows = _wrData; if (q) rows = rows.filter(r => ((r.title||'') + (r.author||'') + (r.content||'')).toLowerCase().includes(q)); const cnt = document.getElementById('wr-count'); if (cnt) cnt.textContent = _wrData.length + '건'; if (!rows.length) { list.innerHTML = '
' + (q ? '검색 결과가 없습니다.' : '등록된 업무보고가 없습니다. 글쓰기를 눌러 작성하세요.') + '
'; return; } list.innerHTML = rows.map(r => { const date = (r.created_at || '').slice(0, 10); const edited = (r.updated_at && r.created_at && r.updated_at.slice(0,16) !== r.created_at.slice(0,16)) ? ' (수정됨)' : ''; return '
' + '
' + '' + escHtml(r.title || '(제목 없음)') + '' + '' + escHtml(r.author || '-') + '' + '' + date + edited + '' + '' + '' + '' + '' + '
' + '' + '
'; }).join(''); } function wrToggle(id) { const el = document.getElementById('wr-body-' + id); if (!el) return; const opening = el.style.display === 'none'; el.style.display = opening ? 'block' : 'none'; if (opening) wrCommentsLoad(id); } function wrOpenForm(id) { document.getElementById('wr-form-msg').textContent = ''; const r = id ? _wrData.find(x => x.id === id) : null; document.getElementById('wr-edit-id').value = r ? r.id : ''; document.getElementById('wr-title').value = r ? (r.title || '') : ''; document.getElementById('wr-author').value = r ? (r.author || '') : ''; document.getElementById('wr-content').value = r ? (r.content || '') : ''; _wrAtt = r && Array.isArray(r.attachments) ? r.attachments.slice() : []; const fileInput = document.getElementById('wr-files'); if (fileInput) fileInput.value = ''; wrRenderAttForm(); const form = document.getElementById('wr-form'); form.style.display = 'block'; form.scrollIntoView({ behavior: 'smooth', block: 'center' }); setTimeout(() => document.getElementById('wr-title').focus(), 60); } function wrCancelForm() { document.getElementById('wr-form').style.display = 'none'; } async function wrSave() { const id = document.getElementById('wr-edit-id').value; const title = document.getElementById('wr-title').value.trim(); const author = document.getElementById('wr-author').value.trim(); const content = document.getElementById('wr-content').value.trim(); const msg = document.getElementById('wr-form-msg'); if (!title) { msg.textContent = '제목을 입력하세요.'; msg.style.color = '#dc2626'; return; } msg.textContent = '저장 중...'; msg.style.color = '#6b7280'; try { // 새로 선택한 파일 업로드 → Storage const fileInput = document.getElementById('wr-files'); const files = fileInput && fileInput.files ? Array.from(fileInput.files) : []; const attachments = _wrAtt.slice(); for (let i = 0; i < files.length; i++) { const f = files[i]; msg.textContent = `파일 업로드 중... (${i + 1}/${files.length})`; const safe = f.name.replace(/[^\w.\-]/g, '_'); const path = `${Date.now()}-${i}-${safe}`; const { error: upErr } = await _sb.storage.from(WR_BUCKET).upload(path, f, { upsert: false }); if (upErr) throw new Error('업로드 실패(' + f.name + '): ' + upErr.message); const { data: pub } = _sb.storage.from(WR_BUCKET).getPublicUrl(path); attachments.push({ name: f.name, url: pub.publicUrl, path, size: f.size }); } msg.textContent = '저장 중...'; if (id) { const { error } = await _sb.from('gtelp_work_reports').update({ title, author, content, attachments, updated_at: new Date().toISOString() }).eq('id', id); if (error) throw error; } else { const { error } = await _sb.from('gtelp_work_reports').insert({ title, author, content, attachments }); if (error) throw error; } _wrAtt = []; wrCancelForm(); await wrLoad(); } catch(e) { msg.textContent = '저장 실패: ' + e.message; msg.style.color = '#dc2626'; } } async function wrDelete(id) { if (!confirm('이 업무보고를 삭제할까요?')) return; try { const { error } = await _sb.from('gtelp_work_reports').delete().eq('id', id); if (error) throw error; await wrLoad(); } catch(e) { alert('삭제 실패: ' + e.message); } } // ── 댓글 (gtelp_work_comments) ── async function wrCommentsLoad(rid) { const box = document.getElementById('wr-comments-' + rid); if (!box) return; box.innerHTML = '
댓글 불러오는 중...
'; try { const { data, error } = await _sb.from('gtelp_work_comments').select('*').eq('report_id', rid).order('created_at', { ascending: true }); if (error) throw error; wrCommentsRender(rid, data || []); } catch(e) { box.innerHTML = '
댓글 불러오기 실패: ' + escHtml(e.message) + '
gtelp_work_comments 테이블이 없으면 SQL을 먼저 실행하세요.
'; } } function wrCommentsRender(rid, comments) { const box = document.getElementById('wr-comments-' + rid); if (!box) return; if (!comments.length) { box.innerHTML = '
아직 댓글이 없습니다.
'; return; } box.innerHTML = comments.map(c => { const date = (c.created_at || '').slice(0, 16).replace('T', ' '); const edited = (c.updated_at && c.created_at && c.updated_at.slice(0,16) !== c.created_at.slice(0,16)) ? ' (수정됨)' : ''; return '
' + '' + escHtml(c.author || '-') + '' + '
' + '
' + escHtml(c.content || '') + '
' + '
' + date + edited + '
' + '
' + '' + '' + '' + '' + '
'; }).join(''); } async function wrCommentSave(rid) { const author = document.getElementById('wr-cmt-author-' + rid).value.trim(); const content = document.getElementById('wr-cmt-input-' + rid).value.trim(); if (!content) { alert('댓글 내용을 입력하세요.'); return; } try { const { error } = await _sb.from('gtelp_work_comments').insert({ report_id: rid, author, content }); if (error) throw error; document.getElementById('wr-cmt-input-' + rid).value = ''; wrCommentsLoad(rid); } catch(e) { alert('댓글 등록 실패: ' + e.message); } } async function wrCommentDelete(rid, cid) { if (!confirm('댓글을 삭제할까요?')) return; try { const { error } = await _sb.from('gtelp_work_comments').delete().eq('id', cid); if (error) throw error; wrCommentsLoad(rid); } catch(e) { alert('삭제 실패: ' + e.message); } } function wrCommentEdit(rid, cid) { const el = document.getElementById('wr-cmt-' + cid); if (!el) return; if (el.querySelector('.wr-cmt-editbox')) return; const textDiv = el.querySelector('.wr-cmt-text'); const cur = textDiv.textContent; textDiv.style.display = 'none'; const box = document.createElement('div'); box.className = 'wr-cmt-editbox'; box.style.marginTop = '4px'; box.innerHTML = '' + '
' + '' + '' + '
'; textDiv.parentNode.insertBefore(box, textDiv.nextSibling); const ta = box.querySelector('textarea'); ta.value = cur; ta.focus(); box.querySelector('.cmt-cancel').onclick = () => { box.remove(); textDiv.style.display = ''; }; box.querySelector('.cmt-save').onclick = async () => { const v = ta.value.trim(); if (!v) return; try { const { error } = await _sb.from('gtelp_work_comments').update({ content: v, updated_at: new Date().toISOString() }).eq('id', cid); if (error) throw error; wrCommentsLoad(rid); } catch(e) { alert('수정 실패: ' + e.message); } }; } // ── 페이지 로그인 게이트 (해시 검증 + Supabase 세션) ── (function () { const ov = document.getElementById('page-login'); if (!ov) return; if (sessionStorage.getItem('hr_authed') === '1') { ov.style.display = 'none'; return; } const pw = document.getElementById('page-login-pw'); const err = document.getElementById('page-login-err'); const btn = document.getElementById('page-login-btn'); const go = async () => { const v = pw.value; if (!v) { err.textContent = '비밀번호를 입력하세요.'; return; } btn.disabled = true; btn.textContent = '확인 중...'; const h = await nmSha256(v); if (h !== NM_PW_HASH) { err.textContent = '비밀번호가 올바르지 않습니다.'; btn.disabled = false; btn.textContent = '로그인'; pw.value = ''; pw.focus(); return; } sessionStorage.setItem('hr_authed', '1'); try { await _sb.auth.signInWithPassword({ email: 'a9723992@gmail.com', password: v }); } catch (e) {} ov.style.display = 'none'; }; btn.onclick = go; pw.onkeydown = (e) => { if (e.key === 'Enter') go(); }; setTimeout(() => pw.focus(), 100); })(); async function newsFetch() { const keyword = document.getElementById('news-keyword').value.trim() || 'HR 채용'; const count = document.getElementById('news-count').value; const status = document.getElementById('news-status'); status.textContent = '뉴스를 가져오는 중...'; status.style.color = '#6b7280'; try { const rssUrl = 'https://news.google.com/rss/search?q=' + encodeURIComponent(keyword) + '&hl=ko&gl=KR&ceid=KR:ko'; const apiUrl = 'https://api.rss2json.com/v1/api.json?rss_url=' + encodeURIComponent(rssUrl) + '&count=' + count; const resp = await fetch(apiUrl); const data = await resp.json(); if (data.status !== 'ok') throw new Error('RSS 파싱 실패'); newsResults = data.items.map(item => ({ title: item.title.replace(/ - [^-]+$/, '').trim(), url: item.link, source: item.author || newsExtractSource(item.title), published_at: item.pubDate ? item.pubDate.replace(' ', 'T') : null, category: 'HR' })); newsRenderResults(); status.textContent = newsResults.length + '건 수집 완료'; status.style.color = '#16a34a'; } catch(e) { status.textContent = '수집 실패: ' + e.message; status.style.color = '#ef4444'; } } function newsExtractSource(title) { const m = title.match(/ - ([^-]+)$/); return m ? m[1].trim() : ''; } function newsRenderResults() { const body = document.getElementById('news-result-body'); document.getElementById('news-result-section').style.display = 'block'; document.getElementById('news-result-count').textContent = '· ' + newsResults.length + '건'; body.innerHTML = newsResults.map((item, i) => { const date = item.published_at ? item.published_at.slice(0, 10) : ''; return '' + '' + '' + date + '' + '' + escHtml(item.title) + '' + '' + escHtml(item.source) + '' + '' + ''; }).join(''); } async function newsSaveOne(idx) { await newsSaveItems([newsResults[idx]]); } async function newsSaveSelected() { const items = [...document.querySelectorAll('.news-result-cb:checked')].map(cb => newsResults[+cb.dataset.idx]); if (!items.length) { alert('선택된 항목이 없습니다.'); return; } await newsSaveItems(items); } async function newsSaveAll() { await newsSaveItems(newsResults); } async function newsSaveItems(items) { const status = document.getElementById('news-status'); status.textContent = items.length + '건 저장 중...'; try { const { error } = await _sb.from('gtelp_news').upsert( items.map(n => ({ title: n.title, url: n.url, source: n.source || '', published_at: n.published_at || null, category: n.category || 'HR' })), { onConflict: 'url', ignoreDuplicates: true } ); if (error) throw error; status.textContent = '저장 완료 ✓'; status.style.color = '#16a34a'; await newsLoadSaved(); } catch(e) { status.textContent = '저장 실패: ' + e.message; status.style.color = '#ef4444'; } } async function newsLoadSaved() { const { data } = await _sb.from('gtelp_news').select('*').order('published_at', { ascending: false }); allSavedNews = data || []; newsFilterSaved(); } function newsFilterSaved() { const q = (document.getElementById('news-saved-search')?.value || '').toLowerCase(); const list = q ? allSavedNews.filter(n => n.title.toLowerCase().includes(q) || (n.source||'').toLowerCase().includes(q)) : allSavedNews; const body = document.getElementById('news-saved-body'); document.getElementById('news-saved-count').textContent = '· ' + allSavedNews.length + '건'; if (!list.length) { body.innerHTML = '저장된 뉴스가 없습니다'; return; } body.innerHTML = list.map(item => { const date = item.published_at ? item.published_at.slice(0, 10) : ''; return '' + '' + '' + date + '' + '' + escHtml(item.title) + '' + '' + escHtml(item.source||'') + '' + '' + ''; }).join(''); } async function newsDeleteOne(id) { if (!confirm('삭제하시겠습니까?')) return; const { error } = await _sb.from('gtelp_news').delete().eq('id', id); if (!error) await newsLoadSaved(); } async function newsDeleteSelected() { const ids = [...document.querySelectorAll('.saved-cb:checked')].map(cb => cb.dataset.id); if (!ids.length) { alert('삭제할 항목을 선택하세요.'); return; } if (!confirm(ids.length + '건을 삭제하시겠습니까?')) return; const { error } = await _sb.from('gtelp_news').delete().in('id', ids); if (!error) await newsLoadSaved(); } function newsCheckAll(cb) { document.querySelectorAll('.news-result-cb').forEach(c => c.checked = cb.checked); } function savedCheckAll(cb) { document.querySelectorAll('.saved-cb').forEach(c => c.checked = cb.checked); } function crmCloseModal() { document.getElementById('crm-modal-bg').style.display = 'none'; crmEditingId = null; } document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && document.getElementById('crm-modal-bg').style.display !== 'none') { crmCloseModal(); } }); function crmExportCsv() { if (crmCompanies.length === 0) { alert('내보낼 데이터가 없습니다'); return; } const headers = ['회사명','유형','단계','담당자','연락처','이메일','다음액션날짜','다음액션','메모','활동건수']; const rows = crmCompanies.map(c => [ c.name, crmGetTypeInfo(c.type).label, crmGetStageInfo(c.stage).label, c.contact||'', c.phone||'', c.email||'', c.nextDate||'', c.nextAction||'', c.memo||'', (c.logs||[]).length ]); const csv = [headers,...rows].map(r => r.map(v => `"${String(v).replace(/"/g,'""')}"`).join(',')).join('\n'); const blob = new Blob([''+csv], {type:'text/csv;charset=utf-8;'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `crm_${new Date().toISOString().slice(0,10)}.csv`; a.click(); URL.revokeObjectURL(url); } function crmRenderAll() { crmRenderMetrics(); crmRenderFilters(); crmRenderPipeline(); crmRenderUpcoming(); crmRenderCompanies(); } document.getElementById('crm-btn-add').onclick = () => crmOpenEdit(null); // ── 업로드 모달 ────────────────────────────────────────── let _uploadParsed = []; function crmParseUploadText(raw) { raw = raw.trim(); if (!raw) return []; // JSON 배열 형식 if (raw.startsWith('[')) { try { const arr = JSON.parse(raw); return arr.map(o => ({ name: o.name || o.company_name || o['회사명'] || '', type: _mapType(o.type || o['유형'] || ''), stage: _mapStage(o.stage || o['단계'] || ''), contact: o.contact || o.contact_name || o['담당자'] || '', phone: o.phone || o.contact_phone || o['연락처'] || '', email: o.email || o.contact_email || o['이메일'] || '', nextDate: o.nextDate || o.next_date || o['다음액션날짜'] || '', nextAction: o.nextAction || o.next_action || o['다음액션'] || '', memo: o.memo || o['메모'] || '', logs: o.logs || [] })).filter(o => o.name); } catch(e) { throw new Error('JSON 파싱 오류: ' + e.message); } } // CSV 형식 const lines = raw.split('\n').map(l => l.trim()).filter(Boolean); if (lines.length === 0) return []; let dataLines = lines; // 헤더 행 감지 (BOM 제거 후 첫 번째 셀이 '회사명' 또는 'name'이면 스킵) const firstCell = crmCsvSplit(lines[0])[0].replace(/^"|"$/g, '').replace(/^/, '').toLowerCase(); if (firstCell === '회사명' || firstCell === 'name' || firstCell === 'company_name') dataLines = lines.slice(1); return dataLines.map(line => { const cols = crmCsvSplit(line).map(c => c.replace(/^"|"$/g, '').trim()); return { name: cols[0] || '', type: _mapType(cols[1] || ''), stage: _mapStage(cols[2] || ''), contact: cols[3] || '', phone: cols[4] || '', email: cols[5] || '', nextDate: cols[6] || '', nextAction: cols[7] || '', memo: cols[8] || '', logs: [] }; }).filter(o => o.name); } function crmCsvSplit(line) { const result = []; let cur = ''; let inQ = false; for (let i = 0; i < line.length; i++) { const ch = line[i]; if (ch === '"') { inQ = !inQ; } else if (ch === ',' && !inQ) { result.push(cur); cur = ''; } else { cur += ch; } } result.push(cur); return result; } function _mapType(v) { const m = { '타겟 250사':'target','타겟':'target','target':'target','무료체험':'trial','trial':'trial','유료고객':'paid','paid':'paid','제휴/파트너':'partner','파트너':'partner','partner':'partner','1000대기업':'large','1000 대기업':'large','large':'large' }; return m[v] || 'target'; } function _mapStage(v) { const m = { '리드':'lead','lead':'lead','컨택':'contact','contact':'contact','미팅/시연':'meeting','미팅':'meeting','시연':'meeting','meeting':'meeting','제안':'proposal','proposal':'proposal','계약':'closed','계약완료':'closed','closed':'closed' }; return m[v] || 'lead'; } function crmDownloadSampleCsv() { const rows = [ ['회사명','유형','단계','담당자','연락처','이메일','다음액션날짜','다음액션','메모'], ['삼성전자','1000대기업','리드','홍길동','010-1234-5678','hong@samsung.com','2026-06-10','미팅 요청','인사팀 담당자 컨택 예정'], ['카카오','타겟 250사','컨택','이채용','010-2345-6789','lee@kakao.com','2026-06-15','제안서 발송','채용 솔루션 관심 있음'], ['네이버','타겟 250사','미팅/시연','박부장','02-1111-2222','park@naver.com','2026-06-20','시연 미팅','HR팀 3명 참석 예정'], ['토스','무료체험','제안','최인사','010-3456-7890','choi@toss.com','2026-07-01','계약 검토','무료체험 만족도 높음'], ['쿠팡','유료고객','계약','강팀장','02-3333-4444','kang@coupang.com','2026-07-10','온보딩','월 5건 채용 계약 완료'], ['원티드랩','제휴/파트너','제안','윤제휴','02-5555-6666','yoon@wanted.co.kr','2026-06-30','제휴 조건 협의','API 연동 논의 중'], ]; const bom = ''; const csv = bom + rows.map(r => r.map(c => `"${String(c).replace(/"/g,'""')}"`).join(',')).join('\r\n'); const a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([csv], { type: 'text/csv;charset=utf-8;' })); a.download = 'crm_sample.csv'; a.click(); URL.revokeObjectURL(a.href); } document.getElementById('crm-btn-sample').onclick = () => { _uploadParsed = []; document.getElementById('crm-upload-file').value = ''; document.getElementById('crm-upload-text').value = ''; document.getElementById('crm-upload-preview').textContent = ''; document.getElementById('crm-upload-confirm').disabled = true; document.getElementById('crm-upload-bg').style.display = 'block'; }; document.getElementById('crm-upload-close').onclick = () => { document.getElementById('crm-upload-bg').style.display = 'none'; }; document.getElementById('crm-upload-cancel').onclick = () => { document.getElementById('crm-upload-bg').style.display = 'none'; }; function crmRunParse() { const raw = document.getElementById('crm-upload-text').value; const preview = document.getElementById('crm-upload-preview'); if (!raw.trim()) { _uploadParsed = []; preview.textContent = ''; document.getElementById('crm-upload-confirm').disabled = true; return; } try { _uploadParsed = crmParseUploadText(raw); if (_uploadParsed.length === 0) { preview.style.color = 'var(--color-text-danger)'; preview.textContent = '파싱된 데이터가 없습니다. 형식을 확인해주세요.'; document.getElementById('crm-upload-confirm').disabled = true; } else { preview.style.color = 'var(--color-text-info)'; preview.textContent = `✓ ${_uploadParsed.length}개 항목 — "${_uploadParsed[0].name}"${_uploadParsed.length > 1 ? ` 외 ${_uploadParsed.length - 1}건` : ''}`; document.getElementById('crm-upload-confirm').disabled = false; } } catch(e) { preview.style.color = 'var(--color-text-danger)'; preview.textContent = '파싱 오류: ' + e.message; document.getElementById('crm-upload-confirm').disabled = true; } } document.getElementById('crm-upload-file').onchange = function() { const file = this.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = e => { document.getElementById('crm-upload-text').value = e.target.result; crmRunParse(); }; reader.readAsText(file, 'UTF-8'); }; document.getElementById('crm-upload-text').oninput = () => crmRunParse(); document.getElementById('crm-upload-parse').onclick = crmRunParse; document.getElementById('crm-upload-confirm').onclick = async () => { // 파싱 안 했으면 먼저 파싱 if (_uploadParsed.length === 0) crmRunParse(); if (_uploadParsed.length === 0) return; const confirmBtn = document.getElementById('crm-upload-confirm'); const preview = document.getElementById('crm-upload-preview'); confirmBtn.disabled = true; let successCount = 0, failCount = 0, lastError = ''; for (let i = 0; i < _uploadParsed.length; i++) { confirmBtn.textContent = `저장 중... (${i + 1}/${_uploadParsed.length})`; const row = crmToRow(_uploadParsed[i]); const { data, error } = await _sb.from('gtelp_crm').insert(row).select(); if (error) { failCount++; lastError = error.message; console.error('insert error:', error, row); } else if (data?.[0]) { crmCompanies.unshift(crmFromRow(data[0])); successCount++; } } confirmBtn.disabled = false; confirmBtn.textContent = '업로드 저장'; if (failCount > 0) { preview.style.color = 'red'; preview.textContent = `${successCount}개 성공, ${failCount}개 실패 — ${lastError}`; } else { document.getElementById('crm-upload-bg').style.display = 'none'; crmRenderAll(); alert(`${successCount}개 항목이 저장되었습니다.`); } }; document.getElementById('crm-btn-export').onclick = crmExportCsv; document.getElementById('crm-btn-clear').onclick = async () => { if (!confirm('모든 데이터를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.')) return; const btn = document.getElementById('crm-btn-clear'); btn.disabled = true; btn.textContent = '삭제 중...'; const { error } = await _sb.from('gtelp_crm').delete().not('id', 'is', null); if (error) { alert('삭제 실패: ' + error.message); btn.disabled = false; btn.textContent = '전체삭제'; return; } crmCompanies = []; btn.disabled = false; btn.textContent = '전체삭제'; crmRenderAll(); }; document.getElementById('crm-search').oninput = e => { crmFilter.search = e.target.value; crmRenderAll(); }; (async () => { await crmLoadData(); crmRenderAll(); })(); function toggleHero() { const h = document.getElementById('hero-header'); const btn = document.getElementById('hero-toggle-btn'); const isNowCollapsed = h.classList.toggle('hero-collapsed'); btn.textContent = isNowCollapsed ? '펼치기 ▼' : '접기 ▲'; localStorage.setItem('heroCollapsed', isNowCollapsed ? '1' : '0'); } function crmReload() { if (typeof crmLoadData === 'function') { crmLoadData().then(() => crmRenderAll()); } }