Finish basic API implementation
This commit is contained in:
332
templates/location_checkin_test.html
Normal file
332
templates/location_checkin_test.html
Normal file
@ -0,0 +1,332 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ロケーションチェックイン テスト</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input, select, textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.result {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
.location-info {
|
||||
background-color: #e9ecef;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.interaction-requirements {
|
||||
background-color: #fff3cd;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
border-left: 4px solid #ffc107;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ロケーションチェックイン テスト</h1>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="locationSelect">ロケーション選択:</label>
|
||||
<select id="locationSelect" onchange="updateLocationInfo()">
|
||||
<option value="">ロケーションを選択してください</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="locationInfo" class="location-info" style="display:none;">
|
||||
<h3>ロケーション情報</h3>
|
||||
<div id="locationDetails"></div>
|
||||
<div id="interactionRequirements" class="interaction-requirements"></div>
|
||||
</div>
|
||||
|
||||
<form id="checkinForm" onsubmit="submitCheckin(event)">
|
||||
<div class="form-group">
|
||||
<label for="latitude">緯度:</label>
|
||||
<input type="number" id="latitude" step="any" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="longitude">経度:</label>
|
||||
<input type="number" id="longitude" step="any" required>
|
||||
</div>
|
||||
|
||||
<div id="photoGroup" class="form-group" style="display:none;">
|
||||
<label for="photo">写真撮影 (Base64):</label>
|
||||
<input type="file" id="photoFile" accept="image/*" onchange="handlePhotoUpload()">
|
||||
<textarea id="photo" rows="3" placeholder="Base64エンコードされた写真データ"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="qrGroup" class="form-group" style="display:none;">
|
||||
<label for="qrCodeData">QRコードデータ:</label>
|
||||
<textarea id="qrCodeData" rows="3" placeholder='{"quiz_id": 1, "correct_answer": "正解"}'></textarea>
|
||||
</div>
|
||||
|
||||
<div id="quizGroup" class="form-group" style="display:none;">
|
||||
<label for="quizAnswer">クイズ回答:</label>
|
||||
<input type="text" id="quizAnswer" placeholder="回答を入力してください">
|
||||
</div>
|
||||
|
||||
<button type="submit">チェックイン実行</button>
|
||||
</form>
|
||||
|
||||
<div id="result" class="result" style="display:none;"></div>
|
||||
|
||||
<script>
|
||||
let locations = [];
|
||||
|
||||
// 初期化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadLocations();
|
||||
getCurrentLocation();
|
||||
});
|
||||
|
||||
// ロケーション一覧を取得
|
||||
async function loadLocations() {
|
||||
try {
|
||||
const response = await fetch('/api/inbound2');
|
||||
const data = await response.json();
|
||||
locations = data.features || [];
|
||||
|
||||
const select = document.getElementById('locationSelect');
|
||||
select.innerHTML = '<option value="">ロケーションを選択してください</option>';
|
||||
|
||||
locations.forEach((location, index) => {
|
||||
const props = location.properties;
|
||||
const option = document.createElement('option');
|
||||
option.value = index;
|
||||
option.textContent = `${props.location_name} (ID: ${props.id}) - evaluation_value: ${props.evaluation_value || '0'}`;
|
||||
select.appendChild(option);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('ロケーション取得エラー:', error);
|
||||
showResult('ロケーション一覧の取得に失敗しました', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 現在地を取得
|
||||
function getCurrentLocation() {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
document.getElementById('latitude').value = position.coords.latitude;
|
||||
document.getElementById('longitude').value = position.coords.longitude;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ロケーション情報を更新
|
||||
function updateLocationInfo() {
|
||||
const select = document.getElementById('locationSelect');
|
||||
const index = select.value;
|
||||
|
||||
if (index === '') {
|
||||
document.getElementById('locationInfo').style.display = 'none';
|
||||
hideInteractionInputs();
|
||||
return;
|
||||
}
|
||||
|
||||
const location = locations[index];
|
||||
const props = location.properties;
|
||||
const evaluationValue = props.evaluation_value || '0';
|
||||
|
||||
// ロケーション詳細表示
|
||||
const detailsDiv = document.getElementById('locationDetails');
|
||||
detailsDiv.innerHTML = `
|
||||
<p><strong>名前:</strong> ${props.location_name}</p>
|
||||
<p><strong>ID:</strong> ${props.id}</p>
|
||||
<p><strong>評価値:</strong> ${evaluationValue}</p>
|
||||
<p><strong>カテゴリ:</strong> ${props.sub_category_name || 'N/A'}</p>
|
||||
<p><strong>説明:</strong> ${props.text || 'N/A'}</p>
|
||||
`;
|
||||
|
||||
// インタラクション要件表示
|
||||
const requirementsDiv = document.getElementById('interactionRequirements');
|
||||
let requirementText = '';
|
||||
|
||||
switch (evaluationValue) {
|
||||
case '0':
|
||||
requirementText = '📍 通常ポイント: 位置情報のみでチェックイン可能';
|
||||
hideInteractionInputs();
|
||||
break;
|
||||
case '1':
|
||||
requirementText = '📸 写真撮影ポイント: 写真撮影が必要(買い物ポイント)';
|
||||
showPhotoInput();
|
||||
break;
|
||||
case '2':
|
||||
requirementText = '🔍 QRコードポイント: QRコードスキャンとクイズ回答が必要';
|
||||
showQRInput();
|
||||
break;
|
||||
default:
|
||||
requirementText = '❓ 不明な評価値: 通常ポイントとして処理';
|
||||
hideInteractionInputs();
|
||||
break;
|
||||
}
|
||||
|
||||
requirementsDiv.textContent = requirementText;
|
||||
document.getElementById('locationInfo').style.display = 'block';
|
||||
}
|
||||
|
||||
// インタラクション入力フィールドの表示制御
|
||||
function hideInteractionInputs() {
|
||||
document.getElementById('photoGroup').style.display = 'none';
|
||||
document.getElementById('qrGroup').style.display = 'none';
|
||||
document.getElementById('quizGroup').style.display = 'none';
|
||||
}
|
||||
|
||||
function showPhotoInput() {
|
||||
hideInteractionInputs();
|
||||
document.getElementById('photoGroup').style.display = 'block';
|
||||
}
|
||||
|
||||
function showQRInput() {
|
||||
hideInteractionInputs();
|
||||
document.getElementById('qrGroup').style.display = 'block';
|
||||
document.getElementById('quizGroup').style.display = 'block';
|
||||
}
|
||||
|
||||
// 写真アップロード処理
|
||||
function handlePhotoUpload() {
|
||||
const file = document.getElementById('photoFile').files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const base64 = e.target.result.split(',')[1]; // data:image/jpeg;base64, を除去
|
||||
document.getElementById('photo').value = base64;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
// チェックイン実行
|
||||
async function submitCheckin(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const select = document.getElementById('locationSelect');
|
||||
const index = select.value;
|
||||
|
||||
if (index === '') {
|
||||
showResult('ロケーションを選択してください', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const location = locations[index];
|
||||
const locationId = location.properties.id;
|
||||
const evaluationValue = location.properties.evaluation_value || '0';
|
||||
|
||||
const data = {
|
||||
location_id: locationId,
|
||||
latitude: parseFloat(document.getElementById('latitude').value),
|
||||
longitude: parseFloat(document.getElementById('longitude').value)
|
||||
};
|
||||
|
||||
// evaluation_valueに応じたデータ追加
|
||||
if (evaluationValue === '1') {
|
||||
const photo = document.getElementById('photo').value;
|
||||
if (!photo) {
|
||||
showResult('写真撮影が必要です', 'error');
|
||||
return;
|
||||
}
|
||||
data.photo = photo;
|
||||
} else if (evaluationValue === '2') {
|
||||
const qrData = document.getElementById('qrCodeData').value;
|
||||
const quizAnswer = document.getElementById('quizAnswer').value;
|
||||
|
||||
if (!qrData || !quizAnswer) {
|
||||
showResult('QRコードデータとクイズ回答が必要です', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
data.qr_code_data = qrData;
|
||||
data.quiz_answer = quizAnswer;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/location-checkin/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showResult(`チェックイン成功!\n${JSON.stringify(result, null, 2)}`, 'success');
|
||||
} else {
|
||||
showResult(`チェックイン失敗: ${result.error}\n${JSON.stringify(result, null, 2)}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('チェックインエラー:', error);
|
||||
showResult('チェックイン処理でエラーが発生しました', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 結果表示
|
||||
function showResult(message, type) {
|
||||
const resultDiv = document.getElementById('result');
|
||||
resultDiv.textContent = message;
|
||||
resultDiv.className = `result ${type}`;
|
||||
resultDiv.style.display = 'block';
|
||||
}
|
||||
|
||||
// CSRFトークン取得
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
const cookie = cookies[i].trim();
|
||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user