mirror of https://github.com/interlegis/sapl.git
16 changed files with 530 additions and 14761 deletions
@ -0,0 +1,92 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<audio |
||||
|
ref="player" |
||||
|
:src="audioSrc" |
||||
|
preload="auto" |
||||
|
></audio> |
||||
|
{{ title }}: <span>{{ formatTime(time) }}</span><br/> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'Cronometro', |
||||
|
props: ['id', 'title'], |
||||
|
data() { |
||||
|
return { |
||||
|
time: 300, |
||||
|
isRunning: false, |
||||
|
initialTime: 300, |
||||
|
intervalId: null, |
||||
|
audioSrc: require('@/assets/audio/ring.mp3'), |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
console.log('Cronometro mounted'); |
||||
|
console.log(this.audioSrc); |
||||
|
this.$emit('child-mounted'); // Emit a custom event |
||||
|
}, |
||||
|
methods: { |
||||
|
handleStartStop() { |
||||
|
this.isRunning = !this.isRunning; |
||||
|
|
||||
|
if (this.isRunning) { |
||||
|
this.intervalId = setInterval(() => { |
||||
|
if (this.time > 0) { |
||||
|
this.time--; |
||||
|
// play buzz at 00:00:30 |
||||
|
if (this.time == 30000) { |
||||
|
this.playSound(); |
||||
|
} |
||||
|
} else { |
||||
|
this.isRunning = false; |
||||
|
clearInterval(this.intervalId); |
||||
|
this.playSound(); |
||||
|
} |
||||
|
}, 1000); |
||||
|
} else { |
||||
|
clearInterval(this.intervalId); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
handleReset() { |
||||
|
this.isRunning = false; |
||||
|
clearInterval(this.intervalId); |
||||
|
this.time = this.initialTime; |
||||
|
}, |
||||
|
|
||||
|
playSound() { |
||||
|
const audio = this.$refs.player |
||||
|
if (!audio) return |
||||
|
|
||||
|
const playPromise = audio.play() |
||||
|
}, |
||||
|
|
||||
|
formatTime(seconds) { |
||||
|
const hrs = Math.floor(seconds / 3600); |
||||
|
const mins = Math.floor((seconds % 3600) / 60); |
||||
|
const secs = seconds % 60; |
||||
|
|
||||
|
if (hrs > 0) { |
||||
|
return `${hrs.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; |
||||
|
} |
||||
|
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; |
||||
|
} |
||||
|
}, |
||||
|
watch: { |
||||
|
initialTime(newVal) { |
||||
|
if (!this.isRunning) { |
||||
|
this.time = newVal; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
beforeDestroy() { |
||||
|
clearInterval(this.intervalId); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* Add your own styles here */ |
||||
|
</style> |
||||
@ -0,0 +1,51 @@ |
|||||
|
.<template> |
||||
|
<div class="col-md-6 text-left painel" v-if="canRender"> |
||||
|
<div class="d-flex align-items-left justify-content-left mb-2"> |
||||
|
<h2 class="text-subtitle mb-0">Cronômetros</h2> |
||||
|
</div> |
||||
|
<div class="text-value" id="box_cronometros"> |
||||
|
<Cronometro v-for="(title, idx) in titles" :key="idx" :title="title" :ref="'childRef_' + idx" @child-mounted="handleChildMounted"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { ref, onMounted } from 'vue'; |
||||
|
import { mapState } from 'vuex'; |
||||
|
import Cronometro from './Cronometro.vue'; |
||||
|
|
||||
|
export default { |
||||
|
name: 'CronometroList', |
||||
|
components: { |
||||
|
Cronometro, |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
titles: ["Discurso", "Aparte", "Questão de Ordem", "Considerações Finais"], |
||||
|
itemRefs: ref([]), // An array to store the refs |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
console.log('CronometroList mounted'); |
||||
|
}, |
||||
|
computed: { |
||||
|
canRender () { |
||||
|
return this.sessao_aberta && this.painel_aberto; |
||||
|
}, |
||||
|
...mapState(["painel_aberto", "sessao_aberta"]) |
||||
|
}, |
||||
|
methods: { |
||||
|
handleStartStop() { |
||||
|
console.log("start/stop stopwatch"); |
||||
|
//console.log(this.$refs.itemRefs); |
||||
|
}, |
||||
|
handleChildMounted() { |
||||
|
console.log('ChildComponent has finished mounting in the parent!'); |
||||
|
// Perform actions in the parent that depend on the child being fully mounted |
||||
|
const childId = 0; |
||||
|
const childComponent = this.$refs['childRef_' + childId]; |
||||
|
childComponent[0].handleStartStop(); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
@ -1,117 +0,0 @@ |
|||||
<template> |
|
||||
<div class="stopwatch-container"> |
|
||||
<div class="stopwatch-card"> |
|
||||
<h1>Stopwatch Timer</h1> |
|
||||
|
|
||||
<div class="time-input"> |
|
||||
<label>Set Time (seconds)</label> |
|
||||
<input |
|
||||
type="number" |
|
||||
v-model.number="initialTime" |
|
||||
:disabled="isRunning" |
|
||||
min="0" |
|
||||
/> |
|
||||
</div> |
|
||||
|
|
||||
<div class="time-display" :class="{ 'time-up': time === 0 }"> |
|
||||
{{ formatTime(time) }} |
|
||||
</div> |
|
||||
|
|
||||
<div class="controls"> |
|
||||
<button @click="handleStartStop" :class="isRunning ? 'pause-btn' : 'start-btn'"> |
|
||||
{{ isRunning ? 'Pause' : 'Start' }} |
|
||||
</button> |
|
||||
|
|
||||
<button @click="handleReset" class="reset-btn"> |
|
||||
Reset |
|
||||
</button> |
|
||||
</div> |
|
||||
|
|
||||
<div v-if="time === 0" class="alert"> |
|
||||
<p>Time's up!</p> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'Stopwatch', |
|
||||
data() { |
|
||||
return { |
|
||||
time: 300, |
|
||||
isRunning: false, |
|
||||
initialTime: 300, |
|
||||
intervalId: null |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
handleStartStop() { |
|
||||
this.isRunning = !this.isRunning; |
|
||||
|
|
||||
if (this.isRunning) { |
|
||||
this.intervalId = setInterval(() => { |
|
||||
if (this.time > 0) { |
|
||||
this.time--; |
|
||||
} else { |
|
||||
this.isRunning = false; |
|
||||
clearInterval(this.intervalId); |
|
||||
this.playSound(); |
|
||||
} |
|
||||
}, 1000); |
|
||||
} else { |
|
||||
clearInterval(this.intervalId); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
handleReset() { |
|
||||
this.isRunning = false; |
|
||||
clearInterval(this.intervalId); |
|
||||
this.time = this.initialTime; |
|
||||
}, |
|
||||
|
|
||||
playSound() { |
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
|
||||
const oscillator = audioContext.createOscillator(); |
|
||||
const gainNode = audioContext.createGain(); |
|
||||
|
|
||||
oscillator.connect(gainNode); |
|
||||
gainNode.connect(audioContext.destination); |
|
||||
|
|
||||
oscillator.frequency.value = 800; |
|
||||
oscillator.type = 'sine'; |
|
||||
|
|
||||
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime); |
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5); |
|
||||
|
|
||||
oscillator.start(audioContext.currentTime); |
|
||||
oscillator.stop(audioContext.currentTime + 0.5); |
|
||||
}, |
|
||||
|
|
||||
formatTime(seconds) { |
|
||||
const hrs = Math.floor(seconds / 3600); |
|
||||
const mins = Math.floor((seconds % 3600) / 60); |
|
||||
const secs = seconds % 60; |
|
||||
|
|
||||
if (hrs > 0) { |
|
||||
return `${hrs.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; |
|
||||
} |
|
||||
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; |
|
||||
} |
|
||||
}, |
|
||||
watch: { |
|
||||
initialTime(newVal) { |
|
||||
if (!this.isRunning) { |
|
||||
this.time = newVal; |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
beforeDestroy() { |
|
||||
clearInterval(this.intervalId); |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
/* Add your own styles here */ |
|
||||
</style> |
|
||||
File diff suppressed because it is too large
Loading…
Reference in new issue