121 lines
2.2 KiB
Vue
121 lines
2.2 KiB
Vue
<template>
|
|
<main class="panel">
|
|
<h1>Quibot Motor Control</h1>
|
|
|
|
<div class="actions">
|
|
<button :disabled="pending" @click="callMotor('step/forward')">
|
|
{{ pending && action === 'step/forward' ? 'Starting...' : 'Step Forward' }}
|
|
</button>
|
|
|
|
<button :disabled="pending" @click="callMotor('step/backwards')">
|
|
{{ pending && action === 'step/backwards' ? 'Starting...' : 'Step Backwards' }}
|
|
</button>
|
|
|
|
<button :disabled="pending" class="stop" @click="callMotor('stop')">
|
|
{{ pending && action === 'stop' ? 'Stopping...' : 'Stop' }}
|
|
</button>
|
|
</div>
|
|
|
|
<p v-if="message" class="message">
|
|
{{ message }}
|
|
</p>
|
|
|
|
<p v-if="error" class="error">
|
|
{{ error }}
|
|
</p>
|
|
</main>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
|
|
type MotorAction = 'step/forward' | 'step/backwards' | 'stop'
|
|
|
|
const pending = ref(false)
|
|
const action = ref<MotorAction | null>(null)
|
|
const message = ref('')
|
|
const error = ref('')
|
|
|
|
async function callMotor(nextAction: MotorAction) {
|
|
pending.value = true
|
|
action.value = nextAction
|
|
message.value = ''
|
|
error.value = ''
|
|
|
|
try {
|
|
const response = await $fetch<{ status?: string }>(`/api/motor/${nextAction}`, {
|
|
method: 'POST',
|
|
})
|
|
|
|
message.value = response.status || `${nextAction} request sent`
|
|
} catch (err: any) {
|
|
error.value = err?.data?.statusMessage || err?.data?.message || err?.message || 'Request failed'
|
|
} finally {
|
|
pending.value = false
|
|
action.value = null
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
:global(body) {
|
|
margin: 0;
|
|
font-family: Helvetica, Arial, sans-serif;
|
|
background: #f3f4f6;
|
|
}
|
|
|
|
.panel {
|
|
min-height: 100vh;
|
|
display: grid;
|
|
place-content: center;
|
|
gap: 1rem;
|
|
padding: 2rem;
|
|
text-align: center;
|
|
}
|
|
|
|
h1 {
|
|
margin: 0;
|
|
color: #111827;
|
|
}
|
|
|
|
.actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
justify-content: center;
|
|
}
|
|
|
|
button {
|
|
border: 0;
|
|
border-radius: 0.75rem;
|
|
padding: 0.9rem 1.4rem;
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
color: #fff;
|
|
background: #2563eb;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button.stop {
|
|
background: #dc2626;
|
|
}
|
|
|
|
button:disabled {
|
|
opacity: 0.7;
|
|
cursor: wait;
|
|
}
|
|
|
|
.message,
|
|
.error {
|
|
margin: 0;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.message {
|
|
color: #166534;
|
|
}
|
|
|
|
.error {
|
|
color: #b91c1c;
|
|
}
|
|
</style>
|