diff --git a/rog/views.py b/rog/views.py
index c686b88..164921b 100644
--- a/rog/views.py
+++ b/rog/views.py
@@ -2406,11 +2406,11 @@ def get_team_info(request, zekken_number):
# start_datetime = -1(ロゲ開始)のcreate_at
logger.debug(f"self.rogaining={entry.event.self_rogaining} => start_datetime = -1(ロゲ開始)のcreate_at")
- # チームのゴール時間を取得
+ # チームの最初のゴール時間を取得
goal_record = GoalImages.objects.filter(
team_name=entry.team.team_name,
event_code=entry.event.event_name
- ).order_by('-goaltime').first()
+ ).order_by('goaltime').first()
# Nullチェックを追加してからログ出力
goalimage_url = None
@@ -2771,7 +2771,7 @@ def update_goal_time(request):
# 既存の記録を更新
goal_record.goaltime = goal_time
goal_record.save()
- logger.info(f"Updated goal time for team {team_name} in event {event_code}")
+ logger.info(f"Updated goal time as {goal_time} for team {team_name} in event {event_code}")
else:
# 新しい記録を作成
entry = Entry.objects.get(zekken_number=zekken_number, event__event_name=event_code)
diff --git a/supervisor/html/index.html b/supervisor/html/index.html
index 6b795d6..e86d25d 100755
--- a/supervisor/html/index.html
+++ b/supervisor/html/index.html
@@ -4,9 +4,10 @@
スーパーバイザーパネル
+
-
+
@@ -170,7 +171,7 @@
// Excel出力ボタンの処理
document.getElementById('exportButton').addEventListener('click', exportExcel);
- console.log('Page loaded, attempting to load events...');
+ //console.log('Page loaded, attempting to load events...');
// 初期データ読み込み
loadEventCodes();
});
@@ -194,7 +195,8 @@
if (display.textContent && display.textContent !== '-') {
try {
const date = new Date(display.textContent);
- input.value = date.toISOString().slice(0, 19);
+ const jstDate = new Date(date.getTime() + (9 * 60 * 60 * 1000));
+ input.value = jstDate.toISOString().slice(0, 19);
} catch (e) {
console.error('Error parsing date:', e);
}
@@ -302,13 +304,13 @@
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);
+ //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);
+ //console.info('overtime=',overtime);
late_point = Math.ceil(overtime/60)*(-50);
lateElement = document.getElementById('latePoints');
lateElement.textContent = late_point;
@@ -333,7 +335,7 @@
// 判定の更新を行う補助関数
function updateValidation(timeDiff, maxTime) {
- console.log('updateValidation',timeDiff,' > ',maxTime)
+ //console.log('updateValidation',timeDiff,' > ',maxTime)
const validateElement = document.getElementById('validate');
if (validateElement) {
if (timeDiff > maxTime) {
@@ -458,23 +460,23 @@
goalTimeDisplay.onclick = () => editGoalTime(goalTimeDisplay);
}
- console.info("step 0");
+ //console.info("step 0");
// ゴール時計の表示を更新
const goalTimeElement = document.getElementById('goalTime');
if (teamData.goal_photo) {
// 画像要素を作成
- console.info("step 1");
+ //console.info("step 1");
const img = document.createElement('img');
img.src = teamData.goal_photo;
img.classList.add('h-32', 'w-auto', 'object-contain', 'cursor-pointer');
img.onclick = () => showLargeImage(teamData.goal_photo);
- console.info("step 2");
+ //console.info("step 2");
// 既存の内容をクリアして画像を追加
goalTimeElement.innerHTML = '';
goalTimeElement.appendChild(img);
- console.info("Goal photo displayed: ",teamData.goal_photo);
+ //console.info("Goal photo displayed: ",teamData.goal_photo);
} else {
goalTimeElement.textContent = '画像なし';
console.info("No goal photo available");
@@ -812,12 +814,63 @@ function deleteRow(rowIndex) {
const img = document.createElement('img');
img.src = src;
img.classList.add('max-w-3xl', 'max-h-[90vh]', 'object-contain');
-
+
+ // 画像の向きを補正
+ applyImageOrientation(img);
+
modal.appendChild(img);
modal.onclick = () => modal.remove();
document.body.appendChild(modal);
}
+// 画像の向きを取得して適用する関数
+function applyImageOrientation(imgElement) {
+ return new Promise((resolve) => {
+ const img = new Image();
+ img.onload = function() {
+ // 仮想キャンバスを作成
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ // EXIF情報を取得
+ EXIF.getData(img, function() {
+ const orientation = EXIF.getTag(this, 'Orientation') || 1;
+ let width = img.width;
+ let height = img.height;
+
+ // 向きに応じてキャンバスのサイズを調整
+ if (orientation > 4 && orientation < 9) {
+ canvas.width = height;
+ canvas.height = width;
+ } else {
+ canvas.width = width;
+ canvas.height = height;
+ }
+
+ // 向きに応じて回転を適用
+ switch (orientation) {
+ case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
+ case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
+ case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
+ case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
+ case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
+ case 7: ctx.transform(0, -1, -1, 0, height, width); break;
+ case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
+ default: break;
+ }
+
+ // 画像を描画
+ ctx.drawImage(img, 0, 0);
+
+ // 回転済みの画像をソースとして設定
+ imgElement.src = canvas.toDataURL();
+ resolve();
+ });
+ };
+ img.src = imgElement.src;
+ });
+}
+
// 新規CP追加のための関数
function showAddCPDialog() {
const cpInput = prompt('追加するCPをカンマ区切りで入力してください(例:CP1,CP2,CP3)');
@@ -833,12 +886,12 @@ function deleteRow(rowIndex) {
const existingCheckins = getCurrentCheckins(); // 現在の表示データを取得する関数
const newCheckins = [];
- console.info('existingCheckins.length =',existingCheckins.length);
+ //console.info('existingCheckins.length =',existingCheckins.length);
cpList.forEach((cp,index) => {
cploc = findLocationByCP(cp);
- console.info('location=',cploc);
- console.info('index = ',index);
+ //console.info('location=',cploc);
+ //console.info('index = ',index);
newCheckins.push({
id: cploc.id,
order: existingCheckins.length + index + 1,
@@ -855,7 +908,7 @@ function deleteRow(rowIndex) {
});
});
- console.info('newCheckins=',newCheckins);
+ //console.info('newCheckins=',newCheckins);
// 新しいCPを表に追加
addCheckinsToTable(newCheckins);
@@ -930,7 +983,7 @@ function deleteRow(rowIndex) {
function updatePathOrders() {
const rows = Array.from(document.getElementById('checkinList').children);
rows.forEach((row, index) => {
- console.info('row=',row);
+ //console.info('row=',row);
row.children[1].textContent = index + 1;
row.dataset.path_order = index + 1;
});
@@ -938,7 +991,7 @@ function deleteRow(rowIndex) {
// 総合ポイントの計算
function calculatePoints() {
- console.info('calculatePoints');
+ //console.info('calculatePoints');
const rows = Array.from(document.getElementById('checkinList').children);
let totalPoints = 0; // チェックインポイントの合計をクリア
let cpPoints = 0; // チェックインポイントの合計をクリア
@@ -965,7 +1018,7 @@ function deleteRow(rowIndex) {
const finalPoints = totalPoints + latePoints;
// 判定を更新。順位を表示、ゴール時刻を15分経過したら失格
- console.info('calculatePoints:totalPoints=',cpPoints,',buyPoints=',buyPoints,',finalPoints=',finalPoints);
+ //console.info('calculatePoints:totalPoints=',cpPoints,',buyPoints=',buyPoints,',finalPoints=',finalPoints);
document.getElementById('totalPoints').textContent = cpPoints;
document.getElementById('buyPoints').textContent = buyPoints;
@@ -1046,7 +1099,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
.replace(/\//g, '-') // スラッシュをハイフンに変換
.replace(' ', 'T'); // スペースをTに変換
- console.log(formattedDateTime); // "2024-10-26T12:59:13"
+ //console.log(formattedDateTime); // "2024-10-26T12:59:13"
console.info('goaltime=',formattedDateTime);
@@ -1151,7 +1204,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
checkins.forEach(checkin => {
const row = document.createElement('tr');
- console.info('checkin=',checkin);
+ //console.info('checkin=',checkin);
row.dataset.id = 0;
row.dataset.local_id = checkin.order; // Unique
@@ -1214,7 +1267,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
// チェックポイントデータをロードする関数
async function loadLocations(eventCode) {
try {
- console.info('loadLocations-1:',eventCode);
+ //console.info('loadLocations-1:',eventCode);
if (!eventCode) {
console.error('Event code is required');
return;
@@ -1226,7 +1279,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
return loadedLocations;
}
- console.info('loadLocations-2:',eventCode);
+ //console.info('loadLocations-2:',eventCode);
// group__containsフィルターを使用してクエリパラメータを構築
const params = new URLSearchParams({
@@ -1244,7 +1297,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
// レスポンスをJSONとして解決
const data = await response.json();
- console.info('loadLocations-3:', data);
+ //console.info('loadLocations-3:', data);
if (!response.ok) {
console.info('loadLocations-3: Bad Response :',response);
@@ -1252,7 +1305,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
throw new Error(`HTTP error! status: ${response.status}`);
}
- console.info('loadLocations-4:',eventCode);
+ //console.info('loadLocations-4:',eventCode);
// 取得したデータを処理して保存
loadedLocations = data.features.map(feature => ({
cp: feature.properties.cp,
@@ -1268,9 +1321,9 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
})).filter(location => location.group && location.group.includes(eventCode));
currentEventCode = eventCode;
- console.info(`Loaded ${loadedLocations.length} locations for event ${eventCode}`);
+ //console.info(`Loaded ${loadedLocations.length} locations for event ${eventCode}`);
- console.info('loadedLocation[0]=',loadedLocations[0]);
+ //console.info('loadedLocation[0]=',loadedLocations[0]);
return loadedLocations;
@@ -1282,7 +1335,7 @@ async function saveGoalTime(goalTimeStr, zekkenNumber, eventCode) {
// イベント選択時のハンドラー
async function handleEventSelect(eventCode) {
- console.info('handleEventSelect : ',eventCode);
+ //console.info('handleEventSelect : ',eventCode);
try {
//document.getElementById('loading').style.display = 'block';
await loadLocations(eventCode);
@@ -1315,7 +1368,7 @@ function findLocationByCP(cpNumber) {
return null;
}
- console.info(`Found location with CP ${cpNumber}:`, found);
+ //console.info(`Found location with CP ${cpNumber}:`, found);
return found;
}