mirror of
https://github.com/Macrame-App/Macrame
synced 2025-12-29 07:19:26 +00:00
Dashboard page restructured. Moved some elements to the other views.
This commit is contained in:
parent
1cf9029a63
commit
315d169cf9
10 changed files with 363 additions and 121 deletions
|
|
@ -35,18 +35,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.block__primary {
|
&.block__primary {
|
||||||
@apply bg-sky-300/40;
|
@apply bg-sky-300/20;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
@apply from-sky-100/40;
|
@apply from-sky-100/20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.block__secondary {
|
&.block__secondary {
|
||||||
@apply bg-amber-300/40;
|
@apply bg-amber-300/20;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
@apply from-amber-100/40;
|
@apply from-amber-100/20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, onUpdated, ref } from 'vue'
|
||||||
import ButtonComp from './ButtonComp.vue'
|
import ButtonComp from './ButtonComp.vue'
|
||||||
import { IconChevronDown, IconChevronUp } from '@tabler/icons-vue'
|
import { IconChevronDown, IconChevronUp } from '@tabler/icons-vue'
|
||||||
|
|
||||||
|
|
@ -35,6 +35,10 @@ onMounted(() => {
|
||||||
if (props.open) toggleAccordion(props.open)
|
if (props.open) toggleAccordion(props.open)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onUpdated(() => {
|
||||||
|
if (props.open) toggleAccordion(props.open)
|
||||||
|
})
|
||||||
|
|
||||||
function toggleAccordion(open = false) {
|
function toggleAccordion(open = false) {
|
||||||
if (open) {
|
if (open) {
|
||||||
accordionOpen.value = true
|
accordionOpen.value = true
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,8 @@ button,
|
||||||
tracking-wide
|
tracking-wide
|
||||||
font-normal
|
font-normal
|
||||||
transition-all
|
transition-all
|
||||||
cursor-pointer;
|
cursor-pointer
|
||||||
|
no-underline;
|
||||||
|
|
||||||
transition:
|
transition:
|
||||||
border-color 0.1s ease-in-out,
|
border-color 0.1s ease-in-out,
|
||||||
|
|
|
||||||
86
fe/src/components/dashboard/RemoteView.vue
Normal file
86
fe/src/components/dashboard/RemoteView.vue
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<div id="remote-dashboard">
|
||||||
|
<div id="panels" class="dashboard-block mcrm-block block__light" v-if="server.handshake">
|
||||||
|
<div class="icon__container">
|
||||||
|
<IconLayoutGrid />
|
||||||
|
</div>
|
||||||
|
<h4>{{ server.panelCount }} {{ server.panelCount != 1 ? 'Panels' : 'Panel' }}</h4>
|
||||||
|
<template v-if="server.panelCount == 0">
|
||||||
|
<p><em>No panels found. </em></p>
|
||||||
|
<p>Learn how to create a panel <a href="#" target="_blank">here</a>.</p>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>Start using a panel!</p>
|
||||||
|
<ButtonComp variant="danger" href="/panels"> <IconLayoutGrid /> View panels </ButtonComp>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div id="server" class="dashboard-block mcrm-block block__light">
|
||||||
|
<div class="icon__container">
|
||||||
|
<IconServer />
|
||||||
|
</div>
|
||||||
|
<h4>Server</h4>
|
||||||
|
<template v-if="server.handshake">
|
||||||
|
<p>
|
||||||
|
Linked with: <strong class="text-center">{{ server.ip }}</strong>
|
||||||
|
</p>
|
||||||
|
<ButtonComp variant="primary" href="/devices"> <IconServer /> View server</ButtonComp>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>
|
||||||
|
<em>Not linked</em>
|
||||||
|
</p>
|
||||||
|
<ButtonComp variant="primary" href="/devices"> <IconLink /> Link with server</ButtonComp>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { IconLayoutGrid, IconLink, IconServer } from '@tabler/icons-vue'
|
||||||
|
import { onMounted, reactive } from 'vue'
|
||||||
|
|
||||||
|
import ButtonComp from '../base/ButtonComp.vue'
|
||||||
|
|
||||||
|
import { useDeviceStore } from '@/stores/device'
|
||||||
|
import { usePanelStore } from '@/stores/panel'
|
||||||
|
|
||||||
|
const device = useDeviceStore()
|
||||||
|
const panel = usePanelStore()
|
||||||
|
|
||||||
|
const server = reactive({
|
||||||
|
ip: '',
|
||||||
|
handshake: '',
|
||||||
|
panelCount: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const serverIp = await device.serverGetIP()
|
||||||
|
server.ip = serverIp
|
||||||
|
|
||||||
|
if (device.key()) server.handshake = true
|
||||||
|
|
||||||
|
device.$subscribe(() => {
|
||||||
|
if (device.key()) server.handshake = true
|
||||||
|
})
|
||||||
|
|
||||||
|
const panelCount = await panel.getList(true)
|
||||||
|
server.panelCount = panelCount
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "@/assets/main.css";
|
||||||
|
|
||||||
|
#remote-dashboard {
|
||||||
|
@apply grid
|
||||||
|
pt-8
|
||||||
|
gap-4
|
||||||
|
md:w-fit
|
||||||
|
h-fit
|
||||||
|
content-start;
|
||||||
|
|
||||||
|
&.not__linked #server {
|
||||||
|
@apply row-start-1 md:col-start-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
133
fe/src/components/dashboard/ServerView.vue
Normal file
133
fe/src/components/dashboard/ServerView.vue
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
id="server-dashboard"
|
||||||
|
:class="`${server.remoteCount == 0 ? 'no__devices' : 'devices__found'} ${server.macroCount == 0 ? 'no__macros' : 'macros__found'}`"
|
||||||
|
>
|
||||||
|
<div id="devices" class="dashboard-block mcrm-block block__light">
|
||||||
|
<div class="icon__container">
|
||||||
|
<IconDevices />
|
||||||
|
</div>
|
||||||
|
<h4>{{ server.remoteCount }} {{ server.remoteCount != 1 ? 'Devices' : 'Device' }}</h4>
|
||||||
|
<template v-if="server.remoteCount == 0">
|
||||||
|
<p><em>No devices found.</em></p>
|
||||||
|
<ButtonComp variant="primary" href="/devices"> <IconLink /> Link a device</ButtonComp>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>Unlink a device or add new devices.</p>
|
||||||
|
<ButtonComp variant="primary" href="/devices"><IconDevices /> View devices</ButtonComp>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div id="macros" class="dashboard-block mcrm-block block__light">
|
||||||
|
<div class="icon__container">
|
||||||
|
<IconKeyboard />
|
||||||
|
</div>
|
||||||
|
<h4>{{ server.macroCount }} {{ server.macroCount != 1 ? 'Macros' : 'Macro' }}</h4>
|
||||||
|
<template v-if="server.macroCount == 0">
|
||||||
|
<p><em>No macros found.</em></p>
|
||||||
|
<ButtonComp variant="secondary" href="/macros"> <IconLayoutGrid /> Create macro</ButtonComp>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>Edit and view your macros.</p>
|
||||||
|
<ButtonComp variant="secondary" href="/macros"><IconKeyboard /> View macros</ButtonComp>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="panels" class="dashboard-block mcrm-block block__light">
|
||||||
|
<div class="icon__container">
|
||||||
|
<IconLayoutGrid />
|
||||||
|
</div>
|
||||||
|
<h4>{{ server.panelCount }} {{ server.panelCount != 1 ? 'Panels' : 'Panel' }}</h4>
|
||||||
|
<template v-if="server.panelCount == 0">
|
||||||
|
<p><em>No panels found. </em></p>
|
||||||
|
<p>Learn how to create a panel <a href="#" target="_blank">here</a>.</p>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>Link macros to panels or view a panel.</p>
|
||||||
|
<ButtonComp variant="danger" href="/panels"> <IconLayoutGrid /> View panels </ButtonComp>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useDeviceStore } from '@/stores/device'
|
||||||
|
import { usePanelStore } from '@/stores/panel'
|
||||||
|
import { IconDevices, IconKeyboard, IconLayoutGrid, IconLink } from '@tabler/icons-vue'
|
||||||
|
import { onMounted, reactive } from 'vue'
|
||||||
|
import ButtonComp from '../base/ButtonComp.vue'
|
||||||
|
import { GetMacroList } from '@/services/MacroService'
|
||||||
|
|
||||||
|
const device = useDeviceStore()
|
||||||
|
const panel = usePanelStore()
|
||||||
|
|
||||||
|
const server = reactive({
|
||||||
|
ip: '',
|
||||||
|
port: '',
|
||||||
|
fullPath: '',
|
||||||
|
remoteCount: 0,
|
||||||
|
macroCount: 0,
|
||||||
|
panelCount: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const serverIP = await device.serverGetIP()
|
||||||
|
server.ip = serverIP
|
||||||
|
// server.port = window.__CONFIG__.MCRM__PORT
|
||||||
|
// server.fullPath = `http://${server.ip}:${server.port}`
|
||||||
|
|
||||||
|
const remoteCount = await device.serverGetRemotes(true)
|
||||||
|
server.remoteCount = remoteCount
|
||||||
|
|
||||||
|
const macroCount = await GetMacroList(true)
|
||||||
|
server.macroCount = macroCount
|
||||||
|
|
||||||
|
const panelCount = await panel.getList(true)
|
||||||
|
server.panelCount = panelCount
|
||||||
|
|
||||||
|
console.log(server)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "@/assets/main.css";
|
||||||
|
|
||||||
|
#server-dashboard {
|
||||||
|
@apply grid
|
||||||
|
grid-cols-1
|
||||||
|
grid-rows-3
|
||||||
|
md:grid-cols-3
|
||||||
|
md:grid-rows-1
|
||||||
|
gap-4
|
||||||
|
w-fit
|
||||||
|
h-fit
|
||||||
|
pt-8;
|
||||||
|
|
||||||
|
&.no__devices #devices {
|
||||||
|
@apply row-start-1 md:col-start-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no__macros.devices__found #devices {
|
||||||
|
@apply row-start-3 md:col-start-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.devices__found #devices {
|
||||||
|
@apply row-start-3 md:col-start-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no__devices.no__macros #macros {
|
||||||
|
@apply row-start-2 md:col-start-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no__macros #macros {
|
||||||
|
@apply row-start-1 md:col-start-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.macros__found #macros {
|
||||||
|
@apply row-start-2 md:col-start-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no__devices.macros__found #macros {
|
||||||
|
@apply row-start-3 md:col-start-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -7,12 +7,14 @@
|
||||||
|
|
||||||
<div class="flex flex-wrap items-start gap-4 mcrm-block block__light">
|
<div class="flex flex-wrap items-start gap-4 mcrm-block block__light">
|
||||||
<h4 class="flex items-center justify-between w-full gap-4 mb-4">
|
<h4 class="flex items-center justify-between w-full gap-4 mb-4">
|
||||||
<span class="flex gap-4" v-if="Object.keys(remote.devices).length > 0">
|
<span class="flex gap-4">
|
||||||
<IconDevices />{{ Object.keys(remote.devices).length }}
|
<IconDevices />{{ Object.keys(remote.devices).length }}
|
||||||
{{ Object.keys(remote.devices).length > 1 ? 'Devices' : 'Device' }}
|
{{ Object.keys(remote.devices).length == 1 ? 'Device' : 'Devices' }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ButtonComp variant="primary" @click="device.serverGetRemotes()"><IconReload /></ButtonComp>
|
<ButtonComp v-if="!remote.poll" variant="primary" @click="device.serverGetRemotes()"
|
||||||
|
><IconReload
|
||||||
|
/></ButtonComp>
|
||||||
</h4>
|
</h4>
|
||||||
<template v-if="Object.keys(remote.devices).length > 0">
|
<template v-if="Object.keys(remote.devices).length > 0">
|
||||||
<template v-for="(remoteDevice, id) in remote.devices" :key="id">
|
<template v-for="(remoteDevice, id) in remote.devices" :key="id">
|
||||||
|
|
@ -51,28 +53,34 @@
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<!-- <template v-else>
|
||||||
<div class="grid w-full gap-4">
|
<div class="grid w-full gap-4">
|
||||||
<em class="text-slate-300">No remote devices</em>
|
<em class="text-slate-300">No remote devices</em>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template> -->
|
||||||
|
|
||||||
<AccordionComp
|
<AccordionComp
|
||||||
class="w-full mt-8 border-t border-t-white/50"
|
class="w-full mt-8 border-t border-t-white/50"
|
||||||
title="How to connect a device?"
|
title="How to connect a device?"
|
||||||
|
:open="Object.keys(remote.devices).length == 0"
|
||||||
>
|
>
|
||||||
<div class="grid py-4">
|
<div class="grid py-4">
|
||||||
<ul class="space-y-1">
|
<ul class="space-y-2">
|
||||||
<li>
|
<li>
|
||||||
To connect a device, open <strong>http://{{ server.ip }}:{{ server.port }}</strong> in
|
Scan the QR code with the remote device.
|
||||||
a browser on the device.
|
<div class="grid gap-4 py-4 pl-6">
|
||||||
|
<canvas ref="serverQr"></canvas>
|
||||||
|
<p>
|
||||||
|
Or manually type the IP address: <br />
|
||||||
|
<strong>{{ server.ip }}/devices</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li>Open the menu, and click on <strong>Server.</strong></li>
|
|
||||||
<li>
|
<li>
|
||||||
The device will automatically request access, if you see "Access requested" on the
|
The device will automatically request access, if you see "Access requested" on the
|
||||||
device.
|
device.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li v-if="!remote.poll">
|
||||||
<div class="inline-flex items-center gap-2">
|
<div class="inline-flex items-center gap-2">
|
||||||
Click the
|
Click the
|
||||||
<span class="p-1 border rounded-sm"><IconReload class="size-4" /></span> to reload
|
<span class="p-1 border rounded-sm"><IconReload class="size-4" /></span> to reload
|
||||||
|
|
@ -85,14 +93,14 @@
|
||||||
<span class="flex items-center gap-1 p-1 text-sm border rounded-sm">
|
<span class="flex items-center gap-1 p-1 text-sm border rounded-sm">
|
||||||
<IconLink class="size-4" /> Link device
|
<IconLink class="size-4" /> Link device
|
||||||
</span>
|
</span>
|
||||||
to generate a one-time-pin to link the device.
|
A one-time-pin will be shown in a dialog.
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li>Enter the pin on the remote device.</li>
|
||||||
<li>
|
<li>
|
||||||
Enter the pin that is shown on this server in the dialog that will appear on the
|
Congratulations! You have linked a device! You can now start using panels on that
|
||||||
device.
|
device.
|
||||||
</li>
|
</li>
|
||||||
<li>Congratulations! You have linked a device! (Hopefully)</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</AccordionComp>
|
</AccordionComp>
|
||||||
|
|
@ -110,7 +118,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import { onMounted, onUpdated, reactive, ref } from 'vue'
|
||||||
import AlertComp from '../base/AlertComp.vue'
|
import AlertComp from '../base/AlertComp.vue'
|
||||||
import { useDeviceStore } from '@/stores/device'
|
import { useDeviceStore } from '@/stores/device'
|
||||||
import {
|
import {
|
||||||
|
|
@ -128,16 +136,18 @@ import DialogComp from '../base/DialogComp.vue'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { appUrl } from '@/services/ApiService'
|
import { appUrl } from '@/services/ApiService'
|
||||||
import AccordionComp from '../base/AccordionComp.vue'
|
import AccordionComp from '../base/AccordionComp.vue'
|
||||||
|
import QRCode from 'qrcode'
|
||||||
|
|
||||||
const device = useDeviceStore()
|
const device = useDeviceStore()
|
||||||
|
|
||||||
const pinDialog = ref()
|
const pinDialog = ref()
|
||||||
|
const serverQr = ref()
|
||||||
|
|
||||||
const server = reactive({
|
const server = reactive({
|
||||||
ip: '',
|
ip: '',
|
||||||
port: '',
|
|
||||||
})
|
})
|
||||||
const remote = reactive({ devices: [], pinlink: false })
|
|
||||||
|
const remote = reactive({ devices: [], pinlink: false, poll: false })
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
device.serverGetRemotes()
|
device.serverGetRemotes()
|
||||||
|
|
@ -146,11 +156,32 @@ onMounted(async () => {
|
||||||
if (state.remote !== remote.devices) remote.devices = device.remote
|
if (state.remote !== remote.devices) remote.devices = device.remote
|
||||||
})
|
})
|
||||||
|
|
||||||
|
getIp()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUpdated(() => {
|
||||||
|
getIp()
|
||||||
|
|
||||||
|
if (Object.keys(remote.devices).length == 0 && !remote.poll) {
|
||||||
|
remote.poll = setInterval(() => {
|
||||||
|
device.serverGetRemotes()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(remote.devices).length > 0 && remote.poll) {
|
||||||
|
clearInterval(remote.poll)
|
||||||
|
remote.poll = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getIp() {
|
||||||
const serverIP = await device.serverGetIP()
|
const serverIP = await device.serverGetIP()
|
||||||
server.ip = serverIP
|
server.ip = serverIP
|
||||||
|
|
||||||
server.port = window.__CONFIG__.MCRM__PORT
|
QRCode.toCanvas(serverQr.value, `${server.ip}/devices`, (error) => {
|
||||||
})
|
if (error) console.log('QRCode error: ', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function startLink(deviceUuid) {
|
async function startLink(deviceUuid) {
|
||||||
const pin = await device.serverStartLink(deviceUuid)
|
const pin = await device.serverStartLink(deviceUuid)
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@ import axios from 'axios'
|
||||||
import { appUrl, isLocal } from './ApiService'
|
import { appUrl, isLocal } from './ApiService'
|
||||||
import { AuthCall } from './EncryptService'
|
import { AuthCall } from './EncryptService'
|
||||||
|
|
||||||
export const GetMacroList = async () => {
|
export const GetMacroList = async (count = false) => {
|
||||||
const request = await axios.post(appUrl() + '/macro/list')
|
const request = await axios.post(appUrl() + '/macro/list')
|
||||||
return sortMacroList(request.data)
|
|
||||||
|
if (!request.data) return 0
|
||||||
|
|
||||||
|
if (!count) return sortMacroList(request.data)
|
||||||
|
else return request.data.length
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortMacroList = (list) => {
|
const sortMacroList = (list) => {
|
||||||
|
|
|
||||||
|
|
@ -52,16 +52,19 @@ export const useDeviceStore = defineStore('device', () => {
|
||||||
|
|
||||||
const serverGetIP = async () => {
|
const serverGetIP = async () => {
|
||||||
const request = await axios.post(appUrl() + '/device/server/ip')
|
const request = await axios.post(appUrl() + '/device/server/ip')
|
||||||
return request.data
|
return `http://${request.data}:${window.__CONFIG__.MCRM__PORT}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server application
|
// Server application
|
||||||
const serverGetRemotes = async (remoteUuid) => {
|
const serverGetRemotes = async (count = false) => {
|
||||||
axios.post(appUrl() + '/device/list', { uuid: remoteUuid }).then((data) => {
|
const request = await axios.post(appUrl() + '/device/list')
|
||||||
if (data.data.devices) {
|
|
||||||
remote.value = data.data.devices
|
if (!request.data.devices) return false
|
||||||
}
|
|
||||||
})
|
remote.value = request.data.devices
|
||||||
|
|
||||||
|
if (!count) return remote.value
|
||||||
|
else return Object.keys(remote.value).length
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverStartLink = async (deviceUuid) => {
|
const serverStartLink = async (deviceUuid) => {
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,20 @@ export const usePanelStore = defineStore('panel', () => {
|
||||||
return current.value
|
return current.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const getList = async () => {
|
const getList = async (count = false) => {
|
||||||
if (list.value.length > 0) return list.value
|
if (list.value.length > 0 && !count) return list.value
|
||||||
|
else if (list.value.length > 0 && count) return list.value.length
|
||||||
|
|
||||||
const data = AuthCall()
|
const data = AuthCall()
|
||||||
|
|
||||||
const resp = await axios.post(appUrl() + '/panel/list', data)
|
const resp = await axios.post(appUrl() + '/panel/list', data)
|
||||||
list.value = resp.data
|
list.value = resp.data
|
||||||
|
|
||||||
return list.value
|
if (!resp.data && !count) return false
|
||||||
|
else if (!resp.data && count) return 0
|
||||||
|
|
||||||
|
if (!count) return list.value
|
||||||
|
else return list.value.length
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,97 +1,72 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="dashboard" class="panel">
|
<div id="dashboard" class="panel">
|
||||||
<h1 class="panel__title">Dashboard</h1>
|
<div class="panel__title">
|
||||||
|
<h1>Dashboard</h1>
|
||||||
<div class="panel__content">
|
<div>
|
||||||
<div class="grid gap-1 opacity-50 h-fit">
|
|
||||||
<em v-if="isLocal()">This is the server dashboard.</em>
|
<em v-if="isLocal()">This is the server dashboard.</em>
|
||||||
<em v-else>This is the remote dashboard.</em>
|
<em v-else>This is the remote dashboard.</em>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isLocal()">
|
</div>
|
||||||
<h4>Start: Authenticate a device</h4>
|
|
||||||
<ul>
|
<div class="panel__content">
|
||||||
<li>
|
<ServerView v-if="isLocal()" />
|
||||||
Open <strong>{{ server.ip }}:{{ server.port }}</strong> in a browser on your phone.
|
<RemoteView v-else />
|
||||||
<div class="p-4 qr-container">
|
|
||||||
<canvas ref="serverQr"></canvas>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>Navigate to the Server page. An authentication request will start automatically.</li>
|
|
||||||
<li>
|
|
||||||
Open the
|
|
||||||
<RouterLink to="/devices"> Devices</RouterLink>
|
|
||||||
page in this window.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="inline-flex items-center gap-2">
|
|
||||||
The device will appear, if not click the
|
|
||||||
<span class="p-1 border rounded-sm"><IconReload class="size-4" /></span> button.
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Using a panel</h4>
|
|
||||||
<ul>
|
|
||||||
<li>Once authenticated you can access the Test Panel on your device.</li>
|
|
||||||
<li>Open the Panels page on your device and click the Test Panel.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<h4>Start: Authenticate this device</h4>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Open
|
|
||||||
<RouterLink to="/devices"> Server</RouterLink>
|
|
||||||
to start.
|
|
||||||
</li>
|
|
||||||
<li>An authentication request will start automatically.</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Using a panel</h4>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Once authenticated you can access the
|
|
||||||
<RouterLink to="/panel/view/test_panel"> Test Panel</RouterLink>
|
|
||||||
on your device.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Open the
|
|
||||||
<RouterLink to="/panels">Panels page</RouterLink>
|
|
||||||
you can edit the panel.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { RouterLink } from 'vue-router'
|
|
||||||
import { isLocal } from '@/services/ApiService'
|
import { isLocal } from '@/services/ApiService'
|
||||||
import { useDeviceStore } from '@/stores/device'
|
import ServerView from '@/components/dashboard/ServerView.vue'
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import RemoteView from '@/components/dashboard/RemoteView.vue'
|
||||||
import { IconReload } from '@tabler/icons-vue'
|
|
||||||
|
|
||||||
import QRCode from 'qrcode'
|
|
||||||
|
|
||||||
const device = useDeviceStore()
|
|
||||||
|
|
||||||
const server = reactive({
|
|
||||||
ip: '',
|
|
||||||
port: '',
|
|
||||||
fullPath: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const serverQr = ref()
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const serverIP = await device.serverGetIP()
|
|
||||||
server.ip = serverIP
|
|
||||||
server.port = window.__CONFIG__.MCRM__PORT
|
|
||||||
server.fullPath = `http://${server.ip}:${server.port}`
|
|
||||||
|
|
||||||
QRCode.toCanvas(serverQr.value, server.fullPath, (error) => {
|
|
||||||
console.log(error)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style>
|
||||||
|
@reference "@/assets/main.css";
|
||||||
|
|
||||||
|
.dashboard-block {
|
||||||
|
@apply md:!row-start-1
|
||||||
|
grid
|
||||||
|
justify-items-center
|
||||||
|
gap-4;
|
||||||
|
|
||||||
|
&#devices .icon__container,
|
||||||
|
&#server .icon__container {
|
||||||
|
@apply bg-sky-300/30
|
||||||
|
text-sky-400
|
||||||
|
border-sky-300/60;
|
||||||
|
}
|
||||||
|
|
||||||
|
&#macros .icon__container {
|
||||||
|
@apply bg-amber-300/30
|
||||||
|
text-amber-400
|
||||||
|
border-amber-300/60;
|
||||||
|
}
|
||||||
|
|
||||||
|
&#panels .icon__container {
|
||||||
|
@apply bg-rose-300/30
|
||||||
|
text-rose-400
|
||||||
|
border-rose-300/60;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon__container {
|
||||||
|
@apply flex
|
||||||
|
justify-center
|
||||||
|
items-center
|
||||||
|
size-16
|
||||||
|
aspect-square
|
||||||
|
rounded-full
|
||||||
|
border;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
@apply size-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
@apply opacity-50
|
||||||
|
w-42
|
||||||
|
text-center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue