(new) track the new quizstore.js for manage the current Vulture Session
This commit is contained in:
166
VApp/src/store/quizStore.js
Normal file
166
VApp/src/store/quizStore.js
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
import { reactive, computed } from 'vue';
|
||||||
|
import mqtt from 'mqtt';
|
||||||
|
import config from '@/config.js';
|
||||||
|
import sessionConfig from '@/quizz/vulture-session-2026-01/session-configuration.json';
|
||||||
|
|
||||||
|
// Reactive state
|
||||||
|
const state = reactive({
|
||||||
|
currentQuestionIndex: 0,
|
||||||
|
questions: [],
|
||||||
|
isMediaHidden: true,
|
||||||
|
packTitle: '',
|
||||||
|
timer: 0 // Timer in seconds
|
||||||
|
});
|
||||||
|
|
||||||
|
// MQTT Client
|
||||||
|
let client = null;
|
||||||
|
let timerInterval = null;
|
||||||
|
let initialized = false;
|
||||||
|
|
||||||
|
// Initialize Store
|
||||||
|
function init() {
|
||||||
|
if (initialized) {
|
||||||
|
console.log('QuizStore: Already initialized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
// Load local config immediately
|
||||||
|
state.questions = sessionConfig.Questions || [];
|
||||||
|
state.packTitle = sessionConfig.PackTitle || '';
|
||||||
|
|
||||||
|
// Connect MQTT
|
||||||
|
client = mqtt.connect(config.mqttBrokerUrl);
|
||||||
|
|
||||||
|
client.on('connect', () => {
|
||||||
|
console.log('QuizStore: MQTT Connected');
|
||||||
|
client.subscribe('game/quiz/control');
|
||||||
|
client.subscribe('/display/control');
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('message', (topic, message) => {
|
||||||
|
const msgStr = message.toString();
|
||||||
|
console.log('QuizStore: MQTT Message Received', topic, msgStr);
|
||||||
|
if (topic === 'game/quiz/control') {
|
||||||
|
try {
|
||||||
|
const payload = JSON.parse(msgStr);
|
||||||
|
handleRemoteCommand(payload);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('QuizStore: JSON Parse Error', e);
|
||||||
|
}
|
||||||
|
} else if (topic === '/display/control') {
|
||||||
|
// Handle raw string commands from MqttButtons
|
||||||
|
if (msgStr === 'next') {
|
||||||
|
_nextQuestion(true);
|
||||||
|
} else if (msgStr === 'previous') {
|
||||||
|
_prevQuestion(true);
|
||||||
|
} else if (msgStr === 'play') {
|
||||||
|
// Start timer for picture questions
|
||||||
|
const currentQ = state.questions[state.currentQuestionIndex];
|
||||||
|
if (currentQ?.Type === 'picture') {
|
||||||
|
const playTime = currentQ.Settings?.PlayTime;
|
||||||
|
if (playTime && playTime > 0) {
|
||||||
|
console.log('QuizStore: Starting timer for picture', playTime);
|
||||||
|
actions.startTimer(playTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (msgStr === 'pause') {
|
||||||
|
stopTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemoteCommand(cmd) {
|
||||||
|
if (cmd.action === 'next') {
|
||||||
|
_nextQuestion(false);
|
||||||
|
} else if (cmd.action === 'prev') {
|
||||||
|
_prevQuestion(false);
|
||||||
|
} else if (cmd.action === 'setIndex') {
|
||||||
|
state.currentQuestionIndex = cmd.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal actions (boolean publish determines if we send MQTT)
|
||||||
|
function _nextQuestion(publish = true) {
|
||||||
|
if (state.currentQuestionIndex < state.questions.length - 1) {
|
||||||
|
state.currentQuestionIndex++;
|
||||||
|
if (publish && client) {
|
||||||
|
client.publish('game/quiz/control', JSON.stringify({ action: 'setIndex', index: state.currentQuestionIndex }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _prevQuestion(publish = true) {
|
||||||
|
if (state.currentQuestionIndex > 0) {
|
||||||
|
state.currentQuestionIndex--;
|
||||||
|
if (publish && client) {
|
||||||
|
client.publish('game/quiz/control', JSON.stringify({ action: 'setIndex', index: state.currentQuestionIndex }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public Actions
|
||||||
|
const actions = {
|
||||||
|
init,
|
||||||
|
nextQuestion: () => _nextQuestion(true),
|
||||||
|
prevQuestion: () => _prevQuestion(true),
|
||||||
|
setQuestion: (index) => {
|
||||||
|
if (index >= 0 && index < state.questions.length) {
|
||||||
|
state.currentQuestionIndex = index;
|
||||||
|
if (client) {
|
||||||
|
client.publish('game/quiz/control', JSON.stringify({ action: 'setIndex', index: index }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
startTimer: (seconds) => {
|
||||||
|
stopTimer();
|
||||||
|
state.timer = seconds;
|
||||||
|
publishTimer();
|
||||||
|
timerInterval = setInterval(() => {
|
||||||
|
if (state.timer > 0) {
|
||||||
|
state.timer--;
|
||||||
|
publishTimer();
|
||||||
|
} else {
|
||||||
|
stopTimer();
|
||||||
|
// Auto-hide by publishing pause
|
||||||
|
if (client) {
|
||||||
|
client.publish('/display/control', 'pause');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
stopTimer
|
||||||
|
};
|
||||||
|
|
||||||
|
function stopTimer() {
|
||||||
|
if (timerInterval) {
|
||||||
|
clearInterval(timerInterval);
|
||||||
|
timerInterval = null;
|
||||||
|
}
|
||||||
|
state.timer = 0;
|
||||||
|
publishTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function publishTimer() {
|
||||||
|
if (client) {
|
||||||
|
client.publish('game/timer', JSON.stringify({ time: state.timer }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
const getters = {
|
||||||
|
currentQuestion: computed(() => state.questions[state.currentQuestionIndex]),
|
||||||
|
isFirstQuestion: computed(() => state.currentQuestionIndex === 0),
|
||||||
|
isLastQuestion: computed(() => state.currentQuestionIndex === state.questions.length - 1),
|
||||||
|
totalQuestions: computed(() => state.questions.length),
|
||||||
|
packTitle: computed(() => state.packTitle),
|
||||||
|
currentQuestionIndex: computed(() => state.currentQuestionIndex),
|
||||||
|
timer: computed(() => state.timer)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
state,
|
||||||
|
actions,
|
||||||
|
getters
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user