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