From 61f5720af3048a088038b963dcef58598775bb37 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Sun, 26 Oct 2025 11:39:30 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B4=80=EB=A6=AC=ED=95=A8=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=EC=A4=91=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=A0=95=EB=B3=B4=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐ŸŽฏ ๊ด€๋ฆฌํ•จ ์ง„ํ–‰์ค‘ ํŽ˜์ด์ง€ ์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ ์‹œ์Šคํ…œ: ๐Ÿ“Š DB ๊ตฌ์กฐ ํ™•์žฅ: - responsible_person_detail: ํ•ด๋‹น์ž ์ƒ์„ธ ์ •๋ณด (VARCHAR 200) - cause_detail: ์›์ธ ์ƒ์„ธ ์ •๋ณด (TEXT) - additional_info_updated_at: ์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ ์‹œ๊ฐ„ - additional_info_updated_by_id: ์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ์ž ID - 018_add_additional_info_fields.sql ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํ–‰ ์™„๋ฃŒ ๐Ÿ”ง ๋ฐฑ์—”๋“œ API: - /api/management/{issue_id}/additional-info (PUT): ์ถ”๊ฐ€ ์ •๋ณด ์—…๋ฐ์ดํŠธ - /api/management/{issue_id}/additional-info (GET): ์ถ”๊ฐ€ ์ •๋ณด ์กฐํšŒ - AdditionalInfoUpdateRequest ์Šคํ‚ค๋งˆ ์ถ”๊ฐ€ - management.py ๋ผ์šฐํ„ฐ ์ƒ์„ฑ ๋ฐ ๋“ฑ๋ก ๐ŸŽจ ํ”„๋ก ํŠธ์—”๋“œ UI: - ์ง„ํ–‰์ค‘ ํƒญ ์ƒ๋‹จ์— '์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ' ๋ฒ„ํŠผ ์ถ”๊ฐ€ - ์™„๋ฃŒ๋จ ํƒญ์—์„œ๋Š” ๋ฒ„ํŠผ ์ž๋™ ์ˆจ๊น€ - ์„ธ๋ จ๋œ ๋ชจ๋‹ฌ ๋””์ž์ธ (์˜ค๋ Œ์ง€ ํ…Œ๋งˆ) - ์›์ธ๋ถ€์„œ ๋“œ๋กญ๋‹ค์šด (์ƒ์‚ฐ/ํ’ˆ์งˆ/๊ตฌ๋งค/์„ค๊ณ„/์˜์—…) - ํ•ด๋‹น์ž ์ƒ์„ธ ์ž…๋ ฅ ํ•„๋“œ - ์›์ธ ์ƒ์„ธ ํ…์ŠคํŠธ ์˜์—ญ ๐Ÿ’ก ํ•ต์‹ฌ ํŠน์ง•: - ๋ชจ๋“  ํ•„๋“œ ์„ ํƒ์‚ฌํ•ญ (NULL ํ—ˆ์šฉ) - ๊ธฐ๋ก์šฉ ์ •๋ณด๋กœ ์™ธ๋ถ€ ๋…ธ์ถœ ์—†์Œ - ๊ธฐ์กด ๋ฐ์ดํ„ฐ ์ž๋™ ๋กœ๋“œ ๋ฐ ์ˆ˜์ • ๊ฐ€๋Šฅ - ์ž…๋ ฅ ์‹œ๊ฐ„/์ž…๋ ฅ์ž ์ž๋™ ์ถ”์  - ์ง„ํ–‰์ค‘ ์ƒํƒœ ์ด์Šˆ๋งŒ ๋Œ€์ƒ ๐Ÿ” ๊ถŒํ•œ ๊ด€๋ฆฌ: - issues_management ํŽ˜์ด์ง€ ๊ถŒํ•œ ํ•„์š” - ์ง„ํ–‰์ค‘ ์ƒํƒœ ์ด์Šˆ๋งŒ ์ˆ˜์ • ๊ฐ€๋Šฅ - ์‚ฌ์šฉ์ž๋ณ„ ์ž…๋ ฅ ์ด๋ ฅ ์ถ”์  ๐ŸŽฏ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค: 1. ๊ด€๋ฆฌํ•จ > ์ง„ํ–‰์ค‘ ํƒญ ์ ‘๊ทผ 2. '์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ' ๋ฒ„ํŠผ ํด๋ฆญ 3. ์›์ธ๋ถ€์„œ, ํ•ด๋‹น์ž, ์›์ธ์ƒ์„ธ ์ž…๋ ฅ 4. ์ €์žฅ ํ›„ ๋‚ด๋ถ€ ๊ธฐ๋ก์œผ๋กœ ๋ณด๊ด€ Expected Result: โœ… ๊ด€๋ฆฌํ•จ์—์„œ ์ƒ์„ธํ•œ ์›์ธ ์ •๋ณด ๊ธฐ๋ก ๊ฐ€๋Šฅ โœ… ์ฒด๊ณ„์ ์ธ ์ด์Šˆ ์ถ”์  ๋ฐ ๋ถ„์„ ๊ธฐ๋ฐ˜ ๋งˆ๋ จ โœ… ์„ ํƒ์  ์ •๋ณด ์ž…๋ ฅ์œผ๋กœ ์œ ์—ฐํ•œ ์šด์˜ โœ… ๊น”๋”ํ•œ UI๋กœ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ํ–ฅ์ƒ --- backend/__pycache__/main.cpython-311.pyc | Bin 3499 -> 3601 bytes .../__pycache__/models.cpython-311.pyc | Bin 11240 -> 11554 bytes .../__pycache__/schemas.cpython-311.pyc | Bin 18293 -> 19110 bytes backend/database/models.py | 6 + backend/database/schemas.py | 12 + backend/main.py | 3 +- .../018_add_additional_info_fields.sql | 85 +++++++ .../__pycache__/management.cpython-311.pyc | Bin 0 -> 5395 bytes backend/routers/management.py | 103 +++++++++ frontend/issues-management.html | 212 +++++++++++++++++- 10 files changed, 409 insertions(+), 12 deletions(-) create mode 100644 backend/migrations/018_add_additional_info_fields.sql create mode 100644 backend/routers/__pycache__/management.cpython-311.pyc create mode 100644 backend/routers/management.py diff --git a/backend/__pycache__/main.cpython-311.pyc b/backend/__pycache__/main.cpython-311.pyc index 8c6c584099b396bba6f813de572b77a7287106d7..ba44a634813131001969816c8fa1aeda61ae8216 100644 GIT binary patch delta 838 zcmZ22JyC{tIWI340}yz1{>^wbkynyQie;ikkyx&1lqe%Z3PTDWg z#Cvj+_1FaXKx~jE5Lh5J*^p6q;%@_1=~U?jG9b=mXGSe%=>@VNHY-CaUzXhD4~&vX zBK#O4A{Zh97$SlgB0?AjN-b4AMLL@aBv2&E#E{CKr2&&n zm7e^Lxtx(>avF;p&n>Rp#Jt4x)ZEm(lFe&amNPO6O%7o*Vbubv)|uSPRum!vHUda! zGTma&O)V}4sxAVB_ezE$eUO|sh|mNQw^)ku^Gk{hfJ|c`E(Ym*0fY?<55(0rm|x(w z1|b&fBJIh+?7mK5&1fd@WTYnMlw`ywXQU=)7nuMJumG7Ph%kvqWJ2ZzZiNdh3P58X zu^$&Q1|gChXbSbWO+_4M$O4yoEzneKqlQ1Elw>e z%S=u!)=Mk}S_b762~8H^iVy(#{1$V1D#Rm2CX;KplpH{&-QtLk&r8frjgP;@TvVEe z=J{V7Ho5sJr8%i~MWH~&pjaw?4Rp~5W=2NF8a$9vN-dBE2~Kur)MA!eAOm8vGNkfl$xc4ND2XJ(k0Bz0 zAtHbwB8VX(gdrjf7m)+IM4efMRUYUr1u!oe$Ww&#<^y?3K%O#4&YK}sWf>y_!)hRg zfE0;TrWDCkl{A(VsTP)HK*7~8DTXN3RJ9c8Y$lLEkth>GDtneXOfpq!vKmV{Bm3le zEN+`WuqUH5GNEFPd>_}WDe4Fiz7ZhFEKYYKK>SSQE48Uvwv~e}KJu#xYZ5YrQu$p`riH=7F|U}k4wVn}6A;hX$HRF=_f z@&!>*adV&uORCs1Mh1q}Knwv<7L#uYYt~x=<*ZWpQy5c)(;3$YEMo?$0b-~cYlv*B zayny*;2I$`SsSpda0=rZk!4IkeLxJ=XA72LNM%cBOw|CID~hJmE=4SuK~ucQe{+#I zJ0sJ}6O+p%oEhyWf0UP+EGNjd`JO~DQ_3yLqSWGo{Ji4Kq@2|Fg4Cko{Ji*-)RM%^ zoLfA}iKWGCz* zXm~}@@B)k64Hc~gZY#_;cx~|7QFYP8>xzljMHTNWD&7}Z6gMl&9cN@*Hu<&uJjThJ zyA;@&8COr9q-?;raPwj17$(NGlNHo_jn@H#tcVpvaD#{r5WxW=L_x%A5FrC15Sr&6Cwx85y@to~a?rxPS9@jcg_(6UIcw4-DAJ4wsK$ OnJ>ulIg>-QrvLzAKD4m_ delta 430 zcmZ1!^&*^aIWI340}yPD`IAv5zme~o5K|h<9k4_4Q9|3EAj`bFWUS?oSAX*9|;FW>&bQMDw`7}gPA5v$apgHZcdU}&9pf|{s<%c zLZC`NO;Ml%smZR2b&S26k0`P;GcKEaM#X?}_U6ATF-(jrCP%6JhOPve$qFL4K}0)< z-~bV#AYvJakO2{iAVL5{fXprm1rd@ULJCAkgNThVV$I|~>K7O{Za%BQ$|w&OMOFEW r!zMRBr8Fniu4vchkDA#`MtY2ij2{@VlN~M}!7^Wv}@nF<=5 zVkX)hemIoK9||}W(Gqn(bhtP}BE}NgLWl|3k3Wn&H%u^D%-nX*6;WY(?fvB3^F8mr zbI-Z&J#Hg?9VEDax1Zzm=g(Quf5Ga&Kkpy^O9%Unaa*i9M_;T>-u-=vlumBU<^##^A7mo*8p>b0Um^wU1y2q*GFOfH>K z#kfp~T~Jb}67)PaO`}VEK3iQQ2zBndhWZ+Zy{>*sgS~OPP~#Q_ zdyRWq_kUXLPJ5jIb9@BcPS=7%XV88|)99qbS&2|1Hc}YOFr>SyI)L+oh*rcQsL0T$ z9B3l8(&3WJy{FggkwqxDv@9R5JNEH_{KRe_pGp4{d?utvha0CXHXpyH*MC4Wsn787 zbYh#}ZBv<6A0N}3J@CejZCwz1i8`>KH9iw&7C{-LN}WAZ^}XVj~GT0#D*n z0zXI19}xgMg49Y6nuuN~i*F_#*sIoh@5jrC>If>a2yBA01D+(LE8EdT^n)ewQ_{}D ze@rYQksZ`&P&q>|K!pfJ9D&s29MZua)rAhkc{q^#4e7#rNiD>LsUajTrzzm2&ie@~ zo}CHWUd43O>x=y=rR{o`b*oa`(I~pyjm309=~DZH;by(m+cE1M(Mw(XXAcicJtGef zUC~S3?b5|_`s4>A&9i-HA9f7rrT&(OovqR-kJNQkYB`~o_MMfw&lon8Irm|Li+wW$ zF53+1EJ%Tt8Nq79?#aRFLELHi7ic2BqQmtbMe|F)DZb3dmrbQxe0=!Pt;hCEMx^?9 zINq@I8&4Y>Yb;kDr*kLbJNU$Sj~vJ9 z!j6<5sBAT*C{Ln{xC7_YR>3|~F*ylW&8479?NXgZk>$^}GsN1}hfc&4Os3ZIXtCp8 zVJ=Y)qlUN#C(SyT&j^Lv=3T0Obe}_Bj`ZP(C2R=Bi?{?f3o6h z>X?O5s~Ji%;zBNA4B}ThTyBWTUJag%&Eyi>OK|4>)uR|ug}9DjZTKFo4_V6JqKWte zOj!;dt%a0V!B|!pxqwmH8yJOnjK)O-dwFkwpJlN08qP-%>=C&7@{_uLPNq~n=Ovq0gr8vOhVpzjq)z)h+wd}2oTN3<}^A=e0LSZI80J_x{=**2ESK(Z4iSiysBXsaru8l`) zvCKlAcA?BO7=?(XYra(G8Tc}j#M796` delta 1402 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 literal 0 HcmV?d00001 diff --git a/backend/routers/management.py b/backend/routers/management.py new file mode 100644 index 0000000..4ed9f44 --- /dev/null +++ b/backend/routers/management.py @@ -0,0 +1,103 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from datetime import datetime +from typing import List + +from database.database import get_db +from database.models import Issue, User, ReviewStatus +from database.schemas import ( + ManagementUpdateRequest, AdditionalInfoUpdateRequest, Issue as IssueSchema +) +from routers.auth import get_current_user +from routers.page_permissions import check_page_access + +router = APIRouter(prefix="/api/management", tags=["management"]) + +@router.get("/", response_model=List[IssueSchema]) +async def get_management_issues( + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db) +): + """ + ๊ด€๋ฆฌํ•จ - ์ง„ํ–‰ ์ค‘ ๋ฐ ์™„๋ฃŒ๋œ ๋ถ€์ ํ•ฉ ๋ชฉ๋ก ์กฐํšŒ + """ + # ๊ด€๋ฆฌํ•จ ํŽ˜์ด์ง€ ๊ถŒํ•œ ํ™•์ธ + if not check_page_access(current_user.id, 'issues_management', db): + raise HTTPException(status_code=403, detail="๊ด€๋ฆฌํ•จ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.") + + # ์ง„ํ–‰ ์ค‘ ๋˜๋Š” ์™„๋ฃŒ๋œ ์ด์Šˆ๋“ค ์กฐํšŒ + issues = db.query(Issue).filter( + Issue.review_status.in_([ReviewStatus.in_progress, ReviewStatus.completed]) + ).order_by(Issue.reviewed_at.desc()).all() + + return issues + +@router.put("/{issue_id}/additional-info") +async def update_additional_info( + issue_id: int, + additional_info: AdditionalInfoUpdateRequest, + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db) +): + """ + ์ถ”๊ฐ€ ์ •๋ณด ์—…๋ฐ์ดํŠธ (์›์ธ๋ถ€์„œ, ํ•ด๋‹น์ž ์ƒ์„ธ, ์›์ธ ์ƒ์„ธ) + """ + # ๊ด€๋ฆฌํ•จ ํŽ˜์ด์ง€ ๊ถŒํ•œ ํ™•์ธ + if not check_page_access(current_user.id, 'issues_management', db): + raise HTTPException(status_code=403, detail="๊ด€๋ฆฌํ•จ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.") + + # ์ด์Šˆ ์กฐํšŒ + issue = db.query(Issue).filter(Issue.id == issue_id).first() + if not issue: + raise HTTPException(status_code=404, detail="๋ถ€์ ํ•ฉ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + + # ์ง„ํ–‰ ์ค‘ ์ƒํƒœ์ธ์ง€ ํ™•์ธ + if issue.review_status != ReviewStatus.in_progress: + raise HTTPException(status_code=400, detail="์ง„ํ–‰ ์ค‘ ์ƒํƒœ์˜ ๋ถ€์ ํ•ฉ๋งŒ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.") + + # ์ถ”๊ฐ€ ์ •๋ณด ์—…๋ฐ์ดํŠธ + update_data = additional_info.dict(exclude_unset=True) + + for field, value in update_data.items(): + setattr(issue, field, value) + + # ์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ ์‹œ๊ฐ„ ๋ฐ ์ž…๋ ฅ์ž ๊ธฐ๋ก + issue.additional_info_updated_at = datetime.now() + issue.additional_info_updated_by_id = current_user.id + + db.commit() + db.refresh(issue) + + return { + "message": "์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", + "issue_id": issue.id, + "updated_at": issue.additional_info_updated_at, + "updated_by": current_user.username + } + +@router.get("/{issue_id}/additional-info") +async def get_additional_info( + issue_id: int, + current_user: User = Depends(get_current_user), + db: Session = Depends(get_db) +): + """ + ์ถ”๊ฐ€ ์ •๋ณด ์กฐํšŒ + """ + # ๊ด€๋ฆฌํ•จ ํŽ˜์ด์ง€ ๊ถŒํ•œ ํ™•์ธ + if not check_page_access(current_user.id, 'issues_management', db): + raise HTTPException(status_code=403, detail="๊ด€๋ฆฌํ•จ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.") + + # ์ด์Šˆ ์กฐํšŒ + issue = db.query(Issue).filter(Issue.id == issue_id).first() + if not issue: + raise HTTPException(status_code=404, detail="๋ถ€์ ํ•ฉ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + + return { + "issue_id": issue.id, + "cause_department": issue.cause_department.value if issue.cause_department else None, + "responsible_person_detail": issue.responsible_person_detail, + "cause_detail": issue.cause_detail, + "additional_info_updated_at": issue.additional_info_updated_at, + "additional_info_updated_by_id": issue.additional_info_updated_by_id + } diff --git a/frontend/issues-management.html b/frontend/issues-management.html index aa22894..af8ae33 100644 --- a/frontend/issues-management.html +++ b/frontend/issues-management.html @@ -247,17 +247,27 @@ - -
- - + +
+ + + @@ -518,13 +528,18 @@ // ํƒญ ๋ฒ„ํŠผ ์Šคํƒ€์ผ ์—…๋ฐ์ดํŠธ const inProgressTab = document.getElementById('inProgressTab'); const completedTab = document.getElementById('completedTab'); + const additionalInfoBtn = document.getElementById('additionalInfoBtn'); if (tab === 'in_progress') { inProgressTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-blue-500 text-white'; completedTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900'; + // ์ง„ํ–‰ ์ค‘ ํƒญ์—์„œ๋งŒ ์ถ”๊ฐ€ ์ •๋ณด ๋ฒ„ํŠผ ํ‘œ์‹œ + additionalInfoBtn.style.display = 'block'; } else { inProgressTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900'; completedTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-green-500 text-white'; + // ์™„๋ฃŒ๋จ ํƒญ์—์„œ๋Š” ์ถ”๊ฐ€ ์ •๋ณด ๋ฒ„ํŠผ ์ˆจ๊น€ + additionalInfoBtn.style.display = 'none'; } filterIssues(); // ์ด๋ฏธ updateStatistics()๊ฐ€ ํฌํ•จ๋จ @@ -1392,6 +1407,181 @@ console.error('โŒ API ์Šคํฌ๋ฆฝํŠธ ๋กœ๋“œ ์‹คํŒจ'); }; document.head.appendChild(script); + + // ์ถ”๊ฐ€ ์ •๋ณด ๋ชจ๋‹ฌ ๊ด€๋ จ ํ•จ์ˆ˜๋“ค + let selectedIssueId = null; + + function openAdditionalInfoModal() { + // ์ง„ํ–‰ ์ค‘ ํƒญ์—์„œ ์„ ํƒ๋œ ์ด์Šˆ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ + const inProgressIssues = allIssues.filter(issue => issue.review_status === 'in_progress'); + + if (inProgressIssues.length === 0) { + alert('์ง„ํ–‰ ์ค‘์ธ ๋ถ€์ ํ•ฉ์ด ์—†์Šต๋‹ˆ๋‹ค.'); + return; + } + + // ์ฒซ ๋ฒˆ์งธ ์ง„ํ–‰ ์ค‘ ์ด์Šˆ๋ฅผ ๊ธฐ๋ณธ ์„ ํƒ (์ถ”ํ›„ ๊ฐœ์„  ๊ฐ€๋Šฅ) + selectedIssueId = inProgressIssues[0].id; + + // ๊ธฐ์กด ๋ฐ์ดํ„ฐ ๋กœ๋“œ + loadAdditionalInfo(selectedIssueId); + + document.getElementById('additionalInfoModal').classList.remove('hidden'); + } + + function closeAdditionalInfoModal() { + document.getElementById('additionalInfoModal').classList.add('hidden'); + selectedIssueId = null; + + // ํผ ์ดˆ๊ธฐํ™” + document.getElementById('additionalInfoForm').reset(); + } + + async function loadAdditionalInfo(issueId) { + try { + const response = await fetch(`/api/management/${issueId}/additional-info`, { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, + 'Content-Type': 'application/json' + } + }); + + if (response.ok) { + const data = await response.json(); + + // ํผ์— ๊ธฐ์กด ๋ฐ์ดํ„ฐ ์ฑ„์šฐ๊ธฐ + document.getElementById('causeDepartment').value = data.cause_department || ''; + document.getElementById('responsiblePersonDetail').value = data.responsible_person_detail || ''; + document.getElementById('causeDetail').value = data.cause_detail || ''; + } + } catch (error) { + console.error('์ถ”๊ฐ€ ์ •๋ณด ๋กœ๋“œ ์‹คํŒจ:', error); + } + } + + // ์ถ”๊ฐ€ ์ •๋ณด ํผ ์ œ์ถœ ์ฒ˜๋ฆฌ + document.getElementById('additionalInfoForm').addEventListener('submit', async function(e) { + e.preventDefault(); + + if (!selectedIssueId) { + alert('์„ ํƒ๋œ ๋ถ€์ ํ•ฉ์ด ์—†์Šต๋‹ˆ๋‹ค.'); + return; + } + + const formData = { + cause_department: document.getElementById('causeDepartment').value || null, + responsible_person_detail: document.getElementById('responsiblePersonDetail').value || null, + cause_detail: document.getElementById('causeDetail').value || null + }; + + try { + const response = await fetch(`/api/management/${selectedIssueId}/additional-info`, { + method: 'PUT', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(formData) + }); + + if (response.ok) { + const result = await response.json(); + alert('์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); + closeAdditionalInfoModal(); + + // ๋ชฉ๋ก ์ƒˆ๋กœ๊ณ ์นจ + loadIssues(); + } else { + const error = await response.json(); + alert(`์ €์žฅ ์‹คํŒจ: ${error.detail || '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜'}`); + } + } catch (error) { + console.error('์ถ”๊ฐ€ ์ •๋ณด ์ €์žฅ ์‹คํŒจ:', error); + alert('์ €์žฅ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + }); + + +