172 lines
4.5 KiB
JavaScript
172 lines
4.5 KiB
JavaScript
// js/main.js
|
|
|
|
// EventBus
|
|
const EventBus = {
|
|
listeners: {},
|
|
|
|
on(event, callback) {
|
|
if (!this.listeners[event]) {
|
|
this.listeners[event] = [];
|
|
}
|
|
this.listeners[event].push(callback);
|
|
},
|
|
|
|
emit(event, data) {
|
|
if (this.listeners[event]) {
|
|
this.listeners[event].forEach(callback => callback(data));
|
|
}
|
|
}
|
|
};
|
|
|
|
// NotificationService
|
|
class NotificationService {
|
|
constructor() {
|
|
this.toastElement = document.getElementById('toast');
|
|
}
|
|
|
|
showMessage(message, type = 'info') {
|
|
this.toastElement.textContent = message;
|
|
this.toastElement.className = `fixed bottom-4 right-4 px-6 py-3 rounded shadow-lg ${
|
|
type === 'error' ? 'bg-red-500' : 'bg-green-500'
|
|
} text-white`;
|
|
|
|
this.toastElement.classList.remove('hidden');
|
|
|
|
setTimeout(() => {
|
|
this.toastElement.classList.add('hidden');
|
|
}, 3000);
|
|
}
|
|
|
|
showError(message) {
|
|
this.showMessage(message, 'error');
|
|
}
|
|
|
|
showSuccess(message) {
|
|
this.showMessage(message, 'success');
|
|
}
|
|
}
|
|
|
|
// ApiClient
|
|
class ApiClient {
|
|
constructor({ baseUrl, authToken, csrfToken }) {
|
|
this.baseUrl = baseUrl;
|
|
this.authToken = authToken;
|
|
this.csrfToken = csrfToken;
|
|
}
|
|
|
|
async request(endpoint, options = {}) {
|
|
const url = `${this.baseUrl}${endpoint}`;
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Token ${this.authToken}`,
|
|
'X-CSRF-Token': this.csrfToken
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
...headers,
|
|
...options.headers
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const contentType = response.headers.get("content-type");
|
|
if (contentType && contentType.includes("application/json")) {
|
|
return await response.json();
|
|
}
|
|
|
|
return await response.text();
|
|
} catch (error) {
|
|
console.error('API request failed:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// API methods
|
|
async getEvents() {
|
|
return this.request('/new-events/');
|
|
}
|
|
|
|
async getZekkenNumbers(eventCode) {
|
|
return this.request(`/zekken_numbers/${eventCode}`);
|
|
}
|
|
|
|
async getTeamInfo(zekkenNumber) {
|
|
return this.request(`/team_info/${zekkenNumber}/`);
|
|
}
|
|
|
|
// ... その他のAPI methods
|
|
}
|
|
|
|
// PointsCalculator
|
|
class PointsCalculator {
|
|
calculate({ checkins, latePoints = 0 }) {
|
|
const totalPoints = this.calculateTotalPoints(checkins);
|
|
const buyPoints = this.calculateBuyPoints(checkins);
|
|
|
|
return {
|
|
totalPoints,
|
|
buyPoints,
|
|
latePoints,
|
|
finalPoints: totalPoints + buyPoints + latePoints
|
|
};
|
|
}
|
|
|
|
calculateTotalPoints(checkins) {
|
|
return checkins.reduce((total, checkin) => {
|
|
if (checkin.validate_location && !checkin.buy_flag) {
|
|
return total + (checkin.checkin_point || 0);
|
|
}
|
|
return total;
|
|
}, 0);
|
|
}
|
|
|
|
calculateBuyPoints(checkins) {
|
|
return checkins.reduce((total, checkin) => {
|
|
if (checkin.validate_location && checkin.buy_flag) {
|
|
return total + (checkin.buy_point || 0);
|
|
}
|
|
return total;
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
// SupervisorPanel - メインアプリケーションクラス
|
|
class SupervisorPanel {
|
|
constructor(options) {
|
|
this.element = options.element;
|
|
this.apiClient = new ApiClient(options.apiConfig);
|
|
this.notification = new NotificationService();
|
|
this.pointsCalculator = new PointsCalculator();
|
|
this.eventBus = EventBus;
|
|
|
|
this.state = {
|
|
currentEvent: null,
|
|
currentZekken: null,
|
|
teamData: null,
|
|
checkins: []
|
|
};
|
|
}
|
|
|
|
// ... SupervisorPanelの実装 ...
|
|
}
|
|
|
|
// アプリケーションの初期化
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const app = new SupervisorPanel({
|
|
element: document.getElementById('app'),
|
|
apiConfig: {
|
|
baseUrl: '/api',
|
|
authToken: localStorage.getItem('authToken'),
|
|
csrfToken: document.querySelector('meta[name="csrf-token"]').content
|
|
}
|
|
});
|
|
|
|
app.initialize();
|
|
});
|