From 82d0e559454684761c8e609ffa13041dd0884d7f Mon Sep 17 00:00:00 2001 From: hayano Date: Wed, 30 Oct 2024 08:12:31 +0000 Subject: [PATCH] =?UTF-8?q?Supervisor:=20=E6=AE=8B=3D=E6=96=B0=E8=A6=8F?= =?UTF-8?q?=E3=83=BB=E4=BF=9D=E5=AD=98=E3=83=BB=E5=8D=B0=E5=88=B7=E3=83=BB?= =?UTF-8?q?=E6=99=82=E8=A8=88=E8=A1=A8=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yaml | 5 +- rog/{.views.py.swp => .models.py.swp} | Bin 16384 -> 16384 bytes rog/.serializers.py.swp | Bin 16384 -> 0 bytes rog/.urls.py.swp | Bin 16384 -> 0 bytes rog/models.py | 2 + rog/views.py | 9 +- supervisor/html/.index.html.swp | Bin 16384 -> 77824 bytes supervisor/html/index.html | 538 ++++++++++++++++++++++---- 8 files changed, 466 insertions(+), 88 deletions(-) rename rog/{.views.py.swp => .models.py.swp} (56%) delete mode 100644 rog/.serializers.py.swp delete mode 100644 rog/.urls.py.swp diff --git a/docker-compose.yaml b/docker-compose.yaml index 44e07a1..7bda0b7 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -53,7 +53,9 @@ services: - type: volume source: nginx_logs target: /var/log/nginx - - media_data:/app/media:ro + - type: bind + source: ./media + target: /usr/share/nginx/html/media ports: - "80:80" depends_on: @@ -73,4 +75,3 @@ volumes: geoserver-data: static_volume: nginx_logs: - media_data: diff --git a/rog/.views.py.swp b/rog/.models.py.swp similarity index 56% rename from rog/.views.py.swp rename to rog/.models.py.swp index d010457559dd8ff51111f170086a58952fe612f2..e03a7478d78c55a3bef64a30288a376580d0b750 100644 GIT binary patch literal 16384 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 TVOPSrxEX44_f}%Ndt(0qG}}#t literal 16384 zcmeHOZEPGz8D1z!`D!UtNc~j}F4o!7W#gnNf}jY3?KqC=*tL_iB!t!8?%dtRw;$b^ zb?lTt6RR|;L%-!zz z;so*wX-|4|d++nkJ2US)`_7kL8`?EKK|X1&H}JW|Fn&fzW8*$zyjZ)@NNP#I6G5!} ziNl8N1zyltS4DM%r3Xq6lpgqh^8k--H@<>KzgsqZM1H?Z`~J85 z)TMk>}Z%h6Q zlJ_wEsKFtM)&v@fS4yjK-gr{IImY>Agk!=On*X@(*hKlH_+u{^uHh zR`P26-2T3z{ohJn_3xm@w4DM%r3Xq6lpZKOPakF8(3OoXQ23QTO0xsTU7_R}xfg`|e zz~v7b#v8!1z%#&?fW5%Sfy*C&E#N7@22Q=-FdhTG0dQaoumSskpfEi)q;`yOLn7<5#}*#z}#G@guiP}`r}AJAeItO-Xr z3GWn$Y2a!)+24nBYGbCu;<{?Nc(&*~^&{!Ym@;nFW80_u!+6$=?3mGR)3?n`Zl6j; zRWgyZxQ8D+6J%Z2ig#;O721(!i568!x4V|pvKgbSr-`)rs`Tcm@m(m~OHrwG%`z48 zY#6yU(+?5hj<4=1L@PJSlqoUT3OdV7OxW`Ug=O(*P;P~_ebm8MY;73Ykg01e*#W0d zh_*=R?Lq(PBUJO@vV+dNTk%xndc_k2kgEs2BE11yzeMh$x??_b1(?lV+0w zKO6>iFV1C`Uc*}-a`JU4CgQQsZl#^WI8+YqKBYq^_frm-D%lnVn_b@vCNNZ{FjDZk zvrde=;e$~bm@4UJr%X8u4RmuY$a@=QRi^Fc*DR~Tm`tRpPUlCOyi^Q?YL+9bSwhW1 zg9;-i>&ZOQS?a{J*Q84*%^r?mnQ5zAbSoLVYutwZsmn26r6gklX5Xx zn)rFmnbqvE&`EPm){vrQ6|rs_&P_(0Oq^eJE}P%B6gueElu0CmfMr=u4u)dYCY^U^ zlqNw{WEU11hzL^1XdH(zu^Abe-l9njxh75$&n;AqS-7*7M9x4OZOA2)nJ#}-Eez{Y zYYwBhE+$u0W>IALRyCD-!JLQbN0V{{+S-RTeqI&b!HO!9nKNSw4NBtf0xzbhQBBeE z4eR=9Jit0A_V_~D@09|DQLE-U<%l>-j*Ju+B`a+YY73kqpRBZ3$S*QPN9;PaYBr;v z*kGkw4q7FeSd2SYEsD)KpzG<^& zZWZd=v$W%VP4feTg#hKvtI<&`kg03y4;6j$C-|#rB~S z=YR6!vyVKdH3ixB+TMtC3!%RhV*fvdJ^5)s?ElsM;%V&nzYS~!-oYOKG;j*|0q`>L z1h5Fyfl1&J_WW-FUjr6^d0-E)8yEwIfE$393edVY0K(gXji2M9hf66Jch?qXr#5uwyIMaDa(#*_Ec~?MlSMdJcCodl z+;5rbcV=D~4ig?F9OqBAJ1|%^gh=%gJ=ltih-rB=HIR~0pHVtHFqE|qJLJXhwh#X( z-5b9o9uA#6_swUQj(k0Ho`_&A3};QJ6*7t)dTL12B$%{4=6;-w(1AF_Ro#Xvak4XL zGYu*0dZDNOomEmf^PQs=;?+9^=dyDqYPICO2*FhxC6&rmY_0Fs?TD))YT57~kL%*X ycA(P#`8ECintqq`Z{65Gv9W)qGI$k(>v9Go8R4rG8R`~^Y~I9G9xho2jsF0jM+9;J diff --git a/rog/.serializers.py.swp b/rog/.serializers.py.swp deleted file mode 100644 index cb59a7d2a317ef7346346fef68fa2e91d09bbbdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHOON<;x8Lqr=5-JmnW>p+Z$HLW z-MiUXCI~_f96;j2kw_rraU@6xPKXOaf)hdu{IGw36aT8HV~ zhaTOR7T3u!;23ZWI0hU8jseGjW56-s82JBWAe-Jvo`&f+8}qrj-_*FjZLY^m{iq@T zmyu6Q{ZAV5e;WB0O?}%8V8{7KL;h?-e$B|wn*M)k$lo&ZCycyn9J2b~G;+H~@vVmZ z4I^JS{oicJUpMj(8TrLqbiwL3)$ZmPa11yG90QI4$ADwNG2j?*3^)cH1CD|JNe0-E z5Ve$jSuJF7{%_a+Kfa5Q9|2zn1aKMPz(c@?fw$ieIq)p-HDCaI5_tU}A-@EE{XRmT z1HJ>ocLA@xhY$$};4-iTd=&T~@Xgx@`3CSA;IFq5@(l1akOHf~-$3-QfR}))z-Ivp z+y~qX{2hA^KLt221U?7c58MP4@zEJXYnNc5VSRONMF*WfAwP z;K%8ZM;LiImsuJ=iYzTm7(k1pD?DR55Jja;o-W$g(|LKq#0eGo_Lc}0`$@FjQ&juZ za&I0@UZz6!)^_BmNl81(yEcgSO}ToWkMXjJ;!V6z{=5l^R{hdxMe$R~>WQaA)LZky zp$Y;U#*4uvRu-oNbTv;$1D=${vdz(;-lki1?pDpawKjsYAc?*8GD(Wy_2|iPls^oi z+z~qMs+Cu6%yW?(q4t{b(&Jg6y+uKU<4LBxLOJ52q6iYYK~%bGON(XQVjxPXEp^Mf zh;Q-;4pzf!7f(-Poa16-g!K$PLiN+>b7zAon*8UEnsAm;dlw_StG5^O{vLdl zd0+XvcXxLU>VL`CW?I^qt>AZug)eIGdeo|z;e#@Hr-5s@(h33=MM2OaRxsviP$X~9 zLoxPBfljG2>7aP;gJ~LVkJF?O?=-L3tj6_8o}S<=%LSkRA+dk+qA=m}Y*TIaYFJ5w zd9n9x*&L(xYtNd8xbSf*wmrX@QZ^WKhF)e_ZFG6#PxB}pkGa5?jVj>xv7Ir`&J=a+ zAW-vyAXvckRHQLg-=)}mX;2~-U7 ztZapGgS3B%4{#H~vBhJ=3}Xz_y*owrmYr6)%!=%@CTit_G|5ER@31_ZSSwVSCt0ZI z-Bnj@3UH)uXrQYJXS3DXZhCg zO;A=Ax;|ayEcPiRNU|bJ(Z4Jm2kYBDrcH5Q4Y^-gvsOip0D z?H99+YOUr|WX52lT)Ppq{$Id){6#>m|LytqpRvaOKJY!@yTBKK&jZWABfzb|AF$qk z1$Yh^0d2qo?f`y)J%DF`Rp24uQ^0M&Z!ykGX1o{FnC@~6I0hU8jseGjW56-s7;p?Y z1{?!B7@)Y+`9m~VDz-z4Jpe4IREJ`PRUC3Ow)~H)0~Fg*Z_TNN z*%=I=*6&Ksg>rLeW=p%Ou5Z{2j?KD6ZPu`2U^V!TmJo;%j#b5y{8V1 zJp??@vG88j)>m7O$ezb2LZ?#zn>qsj!meuURokQK=xsQuwgS~& z+yG}Q8E+Szdc|L##>E~_Pv5XXXw|5D6=hqCb4->;ne1KhLK$S(7fJ=g4(Afpx`(re Pn5tWbji#RZMOr5 zx_>D8cKgbsTlJ+FPz)#r6a$I@#eiZ!F`yVw3@8Q^1BwB~z<+@Ov#MzyMcfJ6@Z
uAA#$D z1MCNWhnEn)1ug(ppaQG_|HR9UEnpKk1)Knm1D^#ZfpOq1wEqR50T35DFz{jcv`qix z*r;WfoxrXh7}ePkr(*h+V=vf;g-B<%+2qrsjYw_?&CzjP8!#WVetX7VP;POzmNNGi z>|;TB3Bmynv2tGp$U!mdA!WWdsXgiKg)M%ffu{T1wLSL8G<#gjNT!+V1Sl-fFFDXt zt(HM7uxU1m-*=2MHp04Rp6#A~_Rb5h?wtExxOMjKFJJ3Ea~Twmu=%+aRy12y(dTB< zD^AguVO0+no4i@(t~aq}`6nj=kGsW5cIWiZySFZco43NwX4v^f*tv}B?o&6y&Xut9 za@aXT!p$4u<`0F=^K`rQQ~cfTJk`DY6GZMlcdq;T57Kd?IK?S>Az}}POZ!Lk-8`38 zE!Sjm6C-L|Ubj4OH0F-le2urc?Nk1=ExzUz9_4FuLUIDP$GAVP4O$`3c-?U=?o9|I z?!z30Gg7{hnC93@YR5jel(73m^^x(IVfa}TTt_Z+RyI8@^O!6rB8Eousuh>*;zO$B zT8oMy{tChjiJof*_S_BF&Cz#`p)4Oqehm^yWni(-dOS~cNaJ#KbD9D@B$`O>C}?r2 zwR*6~CQ^yKh2%x%J{@*$isZc|Gc-K4xqb1K?Q<{TqI>$8o%7fFUBOE@V0`;$r|v#~ zJ#w*mvsYK@Sxn~VxKU9OP<*wlcLwUhdkFt0=hqqn25OI4(LxS%9 z7`9wqv(~3aD<^qn6~A9=nsttpXw&n^{plGgULbK!er2o%AB)&|-7y>ep64MO=C-Fl z+^6rFmDN;Dk7Hz9A(@v`PpLfI8IA8o6Tja}Is9VFHWnc=Xhz8KN$Lg}<~*5k!+R5m z)7YpxY4`DrX|!ZfPJ{vL;SESs8Hi(D0YV#5x9lHP>mf>XW8jcM289u8GOE;Q3g7RG8IlIj+y--GFLR%zYm} z)Wj4$BD@val2@P?VX)i57VqIFT>CCb#jiAc0*vM)0 zKxf7RBa=9Zv_EO{AC_1h3p09%Fi)-fm;pZTxXC&#x>&I3QR`FciBgUdOHBAgkIt6G zlEM}1&(hKYEk^5>Ev{%#=v^d~Vr0`9l`Wd9yvKARo<#>(ws7b{u~o&|;;38Y?!ZD< zM}juE&r=pUn+ZJMX_j1WCiT|YJoihD#=KPvr~qzzT90Cp2mvj&X1Q;f4GKCqoT0&o zH)bq<1GXoT|9r{xyfw$IN*V?S)ZD>4>4H?@h5ysaQmjvQkx&Mq=v!w&-i2kj^F{SmDhU=?xStbF2=l3wGP0!N;+CjSED^ z7y+yd%dRuv4mI+?WLvqj8X}mW0dWARiDlZ3hL+qWz2<4)gM$N^;fh1oo$Q5idsAVPwIizI` z;?Xa)XOn8)M&d-y(;Dsn-~0gf;~&K6i2Z+jet!x3{)@l`;2XdUa6fSMLz?y_V0(|I zod@;-4+DRI{hPoWz;A%F0Qo!wsE=YmF`yVw3@8Q^1BwB~fMP%~@PEPp9crca8FV%z z-$9LG$0pu26&B}a7fQzQf`Tck~|3z0G;- zr6 start_datetime = -1(ロゲ開始)のcreate_at") + # チームのゴール時間を取得 goal_record = GoalImages.objects.filter( team_name=entry.team.team_name, @@ -2373,7 +2379,8 @@ def get_team_info(request, zekken_number): 'members': ', '.join([f"{m.lastname} {m.firstname}" for m in members]), 'event_code': entry.event.event_name, 'start_datetime': entry.event.start_datetime, - 'end_datetime': goal_record.goaltime if goal_record else None + 'end_datetime': goal_record.goaltime if goal_record else None, + 'duration': entry.category.duration.total_seconds() }) def create(self, request, *args, **kwargs): diff --git a/supervisor/html/.index.html.swp b/supervisor/html/.index.html.swp index 56342d9b5ae84155f32f1b585d0bfaea8e892995..bbe3145d2e4284e3a51f38abe868d529907fa967 100644 GIT binary patch literal 77824 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 G;`~2gO|}yN delta 754 zcmZ9}Pe>GD7{~GF-Pvtcb8=nEfjl_rR>QJs|BNmbQILwe5yD1#S(hXe1C2Z+)Gkz) zz|ba`kb;8fP=}H|Ob|j)5kZuvE*+Ajgdh*mrN8zadOg?+AKrQ2-}4T<&s(00mdmQ4 zxHaFAb#}LG7e+!P=Qt-i2OXIzn$r!hjmbi+vS_TWsf|mCf=F1!IONqO?5ZU_y1XL^ zyYxq|y8o5PH9adm|JM0_yZJ18TbrW;+xCj5nrwffRSj2$ zTCS_X7)={R*yiPzn5z|ej&Y2k3u%~mOY>)N0VC+cQRLBv@L_Jk!zG+U`2RCjWkb@m O{DZb?3~t$KDDoG0x1uQk diff --git a/supervisor/html/index.html b/supervisor/html/index.html index 7fed476..e9ddc9b 100755 --- a/supervisor/html/index.html +++ b/supervisor/html/index.html @@ -6,24 +6,25 @@ スーパーバイザーパネル +
-

スーパーバイザーパネル

+

通過審査管理画面

@@ -44,7 +45,11 @@
ゴール時刻
-
+
+ + +
ゴール時計
@@ -80,14 +85,15 @@ - - - - - - - - + + + + + + + + + @@ -115,9 +121,9 @@ // APIのベースURLを環境に応じて設定 const API_BASE_URL = '/api'; - + // イベントリスナーの設定 document.addEventListener('DOMContentLoaded', function() { - // Sortable初期化 + // Sortable初期化これで、通過順序を変更できる const checkinList = document.getElementById('checkinList'); new Sortable(checkinList, { animation: 150, @@ -126,7 +132,7 @@ } }); - // イベントコードのドロップダウン要素を取得 + // 選択されたイベントコード・ゼッケン番号を取得 const eventCodeSelect = document.getElementById('eventCode'); const zekkenNumberSelect = document.getElementById('zekkenNumber'); @@ -146,11 +152,11 @@ }); // チェックボックス変更時の処理 - checkinList.addEventListener('change', function(e) { - if (e.target.type === 'checkbox') { - updateValidation(e.target); - } - }); + //checkinList.addEventListener('change', function(e) { + // if (e.target.type === 'checkbox') { + // updateValidation(e.target); + // } + //}); // 保存ボタンの処理 document.getElementById('saveButton').addEventListener('click', saveChanges); @@ -163,6 +169,195 @@ loadEventCodes(); }); + // editGoalTime関数の修正 + function editGoalTime(element) { + const container = element.closest('.goal-time-container'); + if (!container) { + console.error('Goal time container not found'); + return; + } + + const display = container.querySelector('.goal-time-display'); + const input = container.querySelector('.goal-time-input'); + + if (!display || !input) { + console.error('Goal time elements not found'); + return; + } + + if (display.textContent && display.textContent !== '-') { + try { + const date = new Date(display.textContent); + input.value = date.toISOString().slice(0, 19); + } catch (e) { + console.error('Error parsing date:', e); + } + } + + // input要素のstep属性を1秒に設定 + input.setAttribute('step', '1'); // 1秒単位で入力可能に設定 + + display.classList.add('hidden'); + input.classList.remove('hidden'); + input.focus(); + } + + // ゴール時刻編集機能 + function old_editGoalTime(element) { + const display = element.getElementById('goalTimeDisplay'); + const input = element.getElementById('goalTimeInput'); + + + if (!display || !input) { + console.error('Goal time elements not found'); + return; + } + + // 現在の表示時刻をinputの初期値として設定 + const currentTime = display.textContent; + if (currentTime && currentTime !== '-') { + try { + const date = new Date(currentTime); + input.value = date.toISOString().slice(0, 19); // YYYY-MM-DDThh:mm:ss 形式に変換 + } catch (e) { + console.error('Error parsing date:', e); + } + } + + // input要素のstep属性を1秒に設定 + input.setAttribute('step', '1'); // 1秒単位で入力可能に設定 + + display.classList.add('hidden'); + input.classList.remove('hidden'); + input.focus(); + + } + + function updateGoalTime(input) { + + const display = document.getElementById('goalTimeDisplay'); + const validateElement = document.getElementById('validate'); + + if (!display) { + console.error('Goal time display element not found'); + return; + } + + try { + const newTime = new Date(input.value); + display.textContent = newTime.toLocaleString(); + + const eventCodeSelect = document.getElementById('eventCode'); + const event_code = eventCodeSelect.value; + const zekkenNumberSelect = document.getElementById('zekkenNumber'); + const zekkenNumber = zekkenNumberSelect.value + + // イベントとチェックインデータを取得 + fetch(`${API_BASE_URL}/team_info/${zekkenNumber}`,{ + headers: { + 'Content-Type': 'application/json' + } + }) + .then(response => response.json()) + .then(team => { + if (team.self_rogaining) { + // セルフロゲイニングの場合 + fetch(`${API_BASE_URL}/checkins/${zekkenNumber}/${eventCode}/`,{ + headers: { + 'Content-Type': 'application/json', + } + }) + .then(response => response.json()) + .then(checkins => { + const startCheckin = checkins.find(c => c.cp_number === -1); + if (startCheckin) { + const startTime = new Date(startCheckin.create_at); + const timeDiff = (newTime - startTime) / 1000; // 秒単位の差 + const maxTime = team.duration + 15*60; // 制限時間+15分 + updateValidation(timeDiff, maxTime ); + const overtime = ((newTime - startTime) / 1000 - team.duration/1000 + 60 ) // 60; + if( overtime>0 ){ + late_point = overtime*(-50); + lateElement = document.getElementById('latePoints'); + lateElement.textContent = late_point; + lateElement.classList.add('text-red-600'); + }else{ + lateElement = document.getElementById('latePoints'); + lateElement.textContent = 0; + lateElement.classList.remove('text-red-600'); + } + } + }) + .catch(error => handleApiError(error)); + + } else { + // 通常のロゲイニングの場合 + const startTime = new Date(team.start_datetime); + const timeDiff = (newTime - startTime) / 1000; // 分単位の差 + const maxTime = team.duration + 15*60; // 制限時間+15分 + + console.info('startTime=',startTime,',goalTime=',newTime,',timeDiff=',timeDiff,'duration=',team.duration,',maxTime=',maxTime); + updateValidation(timeDiff, maxTime ); + + // 1秒でも遅刻すると、1分につき-50点 + const overtime = ((newTime - startTime) / 1000 - team.duration ); + if( overtime>0 ){ + console.info('overtime=',overtime); + late_point = Math.ceil(overtime/60)*(-50); + lateElement = document.getElementById('latePoints'); + lateElement.textContent = late_point; + lateElement.classList.add('text-red-600'); + }else{ + lateElement = document.getElementById('latePoints'); + lateElement.textContent = 0; + lateElement.classList.remove('text-red-600'); + } + } + }); + + } catch (e) { + console.error('Error updating goal time:', e); + alert('無効な日時形式です。'); + return; + } + + display.classList.remove('hidden'); + input.classList.add('hidden'); + } + + // 判定の更新を行う補助関数 + function updateValidation(timeDiff, maxTime) { + console.log('updateValidation',timeDiff,' > ',maxTime) + const validateElement = document.getElementById('validate'); + if (validateElement) { + if (timeDiff > maxTime) { + validateElement.textContent = '失格'; + validateElement.classList.add('text-red-600'); + validateElement.classList.remove('text-green-600'); + } else { + validateElement.textContent = '合格'; + validateElement.classList.add('text-green-600'); + validateElement.classList.remove('text-red-600'); + } + } + } + + + function validateGoalTime(goalTime) { + const eventEndTime = new Date(document.getElementById('eventEndTime').value); + const goalDateTime = new Date(goalTime); + const timeDiff = (goalDateTime - eventEndTime) / (1000 * 60); // 分単位の差 + + const validateElement = document.getElementById('validate'); + if (timeDiff > 15) { + validateElement.textContent = '失格'; + validateElement.classList.add('text-red-600'); + } else { + validateElement.textContent = '正常'; + validateElement.classList.remove('text-red-600'); + } + } + async function loadEventCodes() { try { const response = await fetch(`${API_BASE_URL}/events/`); @@ -177,7 +372,7 @@ const data = await response.json(); const select = document.getElementById('eventCode'); // 既存のオプションをクリア - select.innerHTML = ''; + select.innerHTML = ''; data.forEach(event => { const option = document.createElement('option'); @@ -201,7 +396,7 @@ .then(response => response.json()) .then(data => { const select = document.getElementById('zekkenNumber'); - select.innerHTML = ''; + select.innerHTML = ''; data.forEach(number => { const option = document.createElement('option'); option.value = number; @@ -229,6 +424,9 @@ const teamData = await teamResponse.json(); const checkinsData = await checkinsResponse.json(); + // ゴール時刻の表示を更新 + updateGoalTimeDisplay(teamData.end_datetime); + // イベントコードに対応するイベントを検索 //const event = eventData.find(e => e.code === document.getElementById('eventCode').value); @@ -236,10 +434,22 @@ document.getElementById('members').textContent = teamData.members || '-'; document.getElementById('startTime').textContent = teamData.start_datetime ? new Date(teamData.start_datetime).toLocaleString() : '-'; - document.getElementById('goalTime').textContent = - teamData.end_datetime ? new Date(teamData.end_datetime).toLocaleString() : '-'; + //document.getElementById('goalTime').textContent = + // teamData.end_datetime ? new Date(teamData.end_datetime).toLocaleString() : '-'; //'(未ゴール)'; + const goalTimeDisplay = document.getElementById('goalTimeDisplay'); + const goalTime = teamData.end_datetime ? + new Date(teamData.end_datetime).toLocaleString() : + '未ゴール'; + goalTimeDisplay.textContent = goalTime; + + if (goalTime === '-') { + goalTimeDisplay.classList.add('cursor-pointer'); + goalTimeDisplay.onclick = () => editGoalTime(goalTimeDisplay); + } + + // チェックインリストの更新 const tbody = document.getElementById('checkinList'); tbody.innerHTML = ''; // 既存のデータをクリア @@ -251,63 +461,65 @@ const tr = document.createElement('tr'); tr.dataset.id = checkin.id; tr.dataset.cpNumber = checkin.cp_number; - - const bgColor = checkin.buy_point > 0 ? 'bg-blue-100' : 'bg-red-100'; + tr.dataset.buyPoint = checkin.buy_point; + tr.dataset.checkinPoint = checkin.checkin_point; + const bgColor = checkin.buy_point > 0 ? 'bg-blue-100' : ''; tr.innerHTML = ` - - + + - - - - + + - - + `; tbody.appendChild(tr); - if (checkin.points) { - if (checkin.buy_flag) { - buyPoints += checkin.points; - } else { - totalPoints += checkin.points; - } - } + // 合計計算 + //if (checkin.points) { + // if (checkin.buy_flag) { + // buyPoints += checkin.points; + // } else { + // totalPoints += checkin.points; + // } + //} }); + updatePathOrders(); // 合計ポイントの更新 - document.getElementById('totalPoints').textContent = totalPoints; - document.getElementById('buyPoints').textContent = buyPoints; - document.getElementById('latePoints').textContent = teamData.late_points || 0; - document.getElementById('finalPoints').textContent = - totalPoints + buyPoints - (teamData.late_points || 0); + //document.getElementById('totalPoints').textContent = totalPoints; + //document.getElementById('buyPoints').textContent = buyPoints; + //document.getElementById('latePoints').textContent = teamData.late_points || 0; + //document.getElementById('finalPoints').textContent = + // totalPoints + buyPoints + (teamData.late_points || 0); + calculatePoints(); // 総合ポイントの計算 } catch (error) { console.error('Error loading team info:', error); @@ -329,20 +541,61 @@ } } - function loadTeamData_old(zekkenNumber) { - // チーム情報とチェックインデータを取得 - Promise.all([ - fetch(`${API_BASE_URL}/team_info/${zekkenNumber}`), - fetch(`${API_BASE_URL}/checkins/${zekkenNumber}`) - ]).then(responses => Promise.all(responses.map(r => r.json()))) - .then(([teamInfo, checkins]) => { - updateTeamInfo(teamInfo); - updateCheckinList(checkins); - calculatePoints(); - }); + // ゴール時刻表示を更新する関数 + function updateGoalTimeDisplay(endDateTime) { + const goalTimeDisplay = document.getElementById('goalTimeDisplay'); + const goalTimeInput = document.getElementById('goalTimeInput'); + + if (!goalTimeDisplay || !goalTimeInput) { + console.error('Goal time elements not found'); + return; + } + + let displayText = '-'; + if (endDateTime) { + try { + const date = new Date(endDateTime); + displayText = date.toLocaleString(); + // input要素の値も更新 + goalTimeInput.value = date.toISOString().slice(0, 16); + } catch (e) { + console.error('Error formatting date:', e); + } + } + + goalTimeDisplay.textContent = displayText; + goalTimeDisplay.onclick = () => editGoalTime(goalTimeDisplay); } - function updateTeamInfo(teamInfo) { + // UI要素をリセットする関数 + function resetUIElements() { + const elements = { + 'goalTimeDisplay': '-', + 'teamName': '-', + 'members': '-', + 'startTime': '-', + 'totalPoints': '0', + 'buyPoints': '0', + 'latePoints': '0', + 'finalPoints': '0' + }; + + for (const [id, defaultValue] of Object.entries(elements)) { + const element = document.getElementById(id); + if (element) { + element.textContent = defaultValue; + } + } + + // チェックインリストをクリア + const checkinList = document.getElementById('checkinList'); + if (checkinList) { + checkinList.innerHTML = ''; + } + } + + // チーム情報の表示...使われていない + function nouse_updateTeamInfo(teamInfo) { document.getElementById('teamName').textContent = teamInfo.team_name; document.getElementById('members').textContent = teamInfo.members; document.getElementById('startTime').textContent = teamInfo.start_time; @@ -350,7 +603,8 @@ document.getElementById('latePoints').textContent = teamInfo.late_points; } - function updateCheckinList(checkins) { + // 通過リストの表示...呼ばれていない + function nouse_updateCheckinList(checkins) { const tbody = document.getElementById('checkinList'); tbody.innerHTML = ''; @@ -395,8 +649,46 @@ calculateTotalPoints(); } + // 削除機能 + async function deleteCheckin(id) { + if (!confirm('このチェックインを削除してもよろしいですか?')) { + return; + } + + try { + const response = await fetch(`${API_BASE_URL}/checkins/${id}`, { + method: 'DELETE', + }) + + if (response.ok) { + const row = document.querySelector(`tr[data-id="${id}"]`); + row.remove(); + calculatePoints(); // 総合ポイントを再計算 + } else { + throw new Error('Delete failed'); + } + } catch (error) { + console.error('Error deleting checkin:', error); + alert('削除に失敗しました'); + } + } + + // ポイント計算関数 + function calculatePointsForCheckin(checkin) { + let points = 0; + if (checkin.validate_location) { + if(checkin.buy_flag){ + points += Number(checkin.buy_point) || 0; + }else{ + points += Number(checkin.checkin_point) || 0; + } + } + return points; + } + + // ポイント更新関数 - function updatePoints(checkbox) { + function old_updatePoints(checkbox) { const tr = checkbox.closest('tr'); const pointCell = tr.querySelector('.point-value'); const cpNumber = tr.dataset.cpNumber; @@ -410,8 +702,41 @@ }); } + // 審査チェックボックス更新関数 + function updatePoints(checkbox) { + const tr = checkbox.closest('tr'); + const pointCell = tr.querySelector('.point-value'); + const cpNumber = tr.dataset.cpNumber; + const buyPoint = tr.dataset.buyPoint; + const checkinPoint = tr.dataset.checkinPoint; + const validateCheckbox = tr.querySelector('.validate-checkbox'); + const buyCheckbox = tr.querySelector('.buy-checkbox'); + let checkin = { + validate_location: validateCheckbox ? validateCheckbox.checked : false, + buy_flag: buyCheckbox ? buyCheckbox.checked : false, + points: 0 + }; + + if (checkin.validate_location) { + // チェックボックスがONの場合 + if (checkin.buy_flag) { + checkin.points = buyPoint || 0; + } else { + checkin.points = checkinPoint || 0; + } + + } else { + // チェックボックスがOFFの場合 + checkin.points = 0; + } + // ポイントを表示 + pointCell.textContent = checkin.points; + calculatePoints(); // 総合ポイントの計算 + + } + // 買い物ポイント更新関数 - function updateBuyPoints(checkbox) { + function old_updateBuyPoints(checkbox) { const tr = checkbox.closest('tr'); const pointCell = tr.querySelector('.point-value'); const cpNumber = tr.dataset.cpNumber; @@ -425,6 +750,36 @@ }); } + // 買い物チェックボックス更新関数 + function updateBuyPoints(checkbox) { + const tr = checkbox.closest('tr'); + const pointCell = tr.querySelector('.point-value'); + const cpNumber = tr.dataset.cpNumber; + const validateCheckbox = tr.querySelector('.validate-checkbox'); + let checkin = { + validate_location: validateCheckbox.checked, + buy_flag: checkbox.checked, + points: 0 + }; + + fetch(`${API_BASE_URL}/location/${cpNumber}/`) + .then(response => response.json()) + .then(location => { + if (checkin.validate_location) { + // 通過審査がONの場合 + checkin.points = checkbox.checked ? location.buy_point : location.checkin_point; + } else { + // 通過審査がOFFの場合 + checkin.points = 0; + } + + // ポイントを表示 + pointCell.textContent = checkin.points; + calculatePoints(); // 総合ポイントの計算 + }) + } + + // 画像拡大表示用のモーダル関数 function showLargeImage(src) { const modal = document.createElement('div'); @@ -505,29 +860,42 @@ function updatePathOrders() { const rows = Array.from(document.getElementById('checkinList').children); rows.forEach((row, index) => { - row.children[0].textContent = index + 1; + row.children[1].textContent = index + 1; }); } + // 総合ポイントの計算 function calculatePoints() { + console.info('calculatePoints'); const rows = Array.from(document.getElementById('checkinList').children); - let totalPoints = 0; - let buyPoints = 0; + let totalPoints = 0; // チェックインポイントの合計をクリア + let cpPoints = 0; // チェックインポイントの合計をクリア + let buyPoints = 0; // 買い物ポイントの合計をクリア + // 各行のチェックインポイント及び買い物ポイントを合算 rows.forEach(row => { - const points = parseInt(row.children[4].textContent); - if (!isNaN(points)) { - totalPoints += points; - if (row.dataset.buyFlag === 'true') { - buyPoints += points; - } + const buybox = row.children[6].querySelector('input[type="checkbox"]'); + const checkbox = row.children[7].querySelector('input[type="checkbox"]'); + const point = parseInt(row.children[8].textContent); + if (checkbox) { + totalPoints += point; + if (buybox && buybox.checked) { + buyPoints += point; + }else{ + cpPoints += point; + } } }); + // 遅刻ポイントの計算=ゴール時刻がEventのゴール時刻を超えていたら1分につき-50点を加算する。 const latePoints = parseInt(document.getElementById('latePoints').textContent) || 0; - const finalPoints = totalPoints + buyPoints - latePoints; + // 総合得点を計算 + const finalPoints = totalPoints + latePoints; - document.getElementById('totalPoints').textContent = totalPoints; + // 判定を更新。順位を表示、ゴール時刻を15分経過したら失格 + console.info('calculatePoints:totalPoints=',cpPoints,',buyPoints=',buyPoints,',finalPoints=',finalPoints); + + document.getElementById('totalPoints').textContent = cpPoints; document.getElementById('buyPoints').textContent = buyPoints; document.getElementById('finalPoints').textContent = finalPoints; }
走行順規定写真撮影写真CP名称通過時刻通過審査買物審査獲得点数 走行順規定写真撮影写真CP名称通過時刻買物申請通過審査獲得点数
${checkin.path_order} + + + ${checkin.path_order} ${checkin.photos ? `` : ''} -
${checkin.photos}
+ ${checkin.image_address ? - `` : ''} - ${checkin.receipt_address && checkin.buy_flag ? - `` : ''} -
${checkin.image_address}
-
${checkin.receipt_address}
+ `` : ''}
+
${checkin.sub_loc_id}
${checkin.location_name}
${checkin.create_at || '不明'} + ${checkin.create_at || '不明'} + ${checkin.buy_point > 0 ? ` + + ` : ''} + - ${checkin.buy_point > 0 ? ` - - ` : ''} - ${checkin.points}${calculatePointsForCheckin(checkin)}