mirror of
https://github.com/EvolutionAPI/evolution-manager.git
synced 2025-07-13 07:04:50 -06:00
muita coisa
This commit is contained in:
parent
e0f6d28a88
commit
558545e469
@ -5,7 +5,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Welcome to Vuetify 3</title>
|
<title>Evolution Manager</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 263 KiB |
17
src/App.vue
17
src/App.vue
@ -3,5 +3,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
//
|
//
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@for $i from 0 through 8 {
|
||||||
|
.gap-x-#{$i} {
|
||||||
|
column-gap: #{$i * 0.25}rem;
|
||||||
|
}
|
||||||
|
.gap-y-#{$i} {
|
||||||
|
row-gap: #{$i * 0.25}rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-#{$i} {
|
||||||
|
gap: #{$i * 0.25}rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 17 KiB |
@ -1,6 +0,0 @@
|
|||||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M261.126 140.65L164.624 307.732L256.001 466L377.028 256.5L498.001 47H315.192L261.126 140.65Z" fill="#1697F6"/>
|
|
||||||
<path d="M135.027 256.5L141.365 267.518L231.64 111.178L268.731 47H256H14L135.027 256.5Z" fill="#AEDDFF"/>
|
|
||||||
<path d="M315.191 47C360.935 197.446 256 466 256 466L164.624 307.732L315.191 47Z" fill="#1867C0"/>
|
|
||||||
<path d="M268.731 47C76.0026 47 141.366 267.518 141.366 267.518L268.731 47Z" fill="#7BC6FF"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 526 B |
59
src/components/instance/InstanceBody.vue
Normal file
59
src/components/instance/InstanceBody.vue
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<v-tabs>
|
||||||
|
<v-tab v-for="tab in tabs" :key="tab.id" :value="tab.id">
|
||||||
|
<v-icon start>{{ tab.icon }}</v-icon>
|
||||||
|
{{ tab.title }}
|
||||||
|
</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
|
||||||
|
<v-window v-model="tab">
|
||||||
|
<v-window-item v-for="tab in tabs" :key="tab.id" :value="tab.id" >
|
||||||
|
<div class="d-flex flex-column gap-8">
|
||||||
|
|
||||||
|
<component
|
||||||
|
v-for="component in tab.components"
|
||||||
|
:key="component"
|
||||||
|
:is="component"
|
||||||
|
:instance="instance"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</v-window-item>
|
||||||
|
</v-window>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Webhook from "./settings/webhook.vue";
|
||||||
|
import Websocket from "./settings/Websocket.vue";
|
||||||
|
import Rabbitmq from "./settings/Rabbitmq.vue";
|
||||||
|
import Chatwoot from "./settings/Chatwoot.vue";
|
||||||
|
import Typebot from "./settings/Typebot.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Webhook,
|
||||||
|
Websocket,
|
||||||
|
Rabbitmq,
|
||||||
|
Chatwoot,
|
||||||
|
Typebot,
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
tab: "settings",
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
id: "settings",
|
||||||
|
icon: "mdi-cog",
|
||||||
|
title: "Configurações",
|
||||||
|
components: ["Webhook", "Websocket", "Rabbitmq", "Chatwoot", "Typebot"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
99
src/components/instance/InstanceHeader.vue
Normal file
99
src/components/instance/InstanceHeader.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<v-card
|
||||||
|
variant="outlined"
|
||||||
|
class="d-flex align-center gap-4 pa-2"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
|
<v-avatar size="100" rounded="xl">
|
||||||
|
<v-icon
|
||||||
|
v-if="
|
||||||
|
instance.instance.status != 'open' &&
|
||||||
|
statusMapper[instance.instance.status].icon
|
||||||
|
"
|
||||||
|
size="70"
|
||||||
|
>
|
||||||
|
{{ statusMapper[instance.instance.status].icon }}
|
||||||
|
</v-icon>
|
||||||
|
<v-img
|
||||||
|
v-else
|
||||||
|
:src="
|
||||||
|
instance.instance.profilePictureUrl ||
|
||||||
|
'https://cdn.vuetifyjs.com/images/lists/1.jpg'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</v-avatar>
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<span class="text-overline" style="line-height: 1em">
|
||||||
|
{{ owner }}
|
||||||
|
</span>
|
||||||
|
<h2 class="mb-0">{{ instance.instance.instanceName }}</h2>
|
||||||
|
<small>{{ instance.instance.profileStatus }}</small>
|
||||||
|
</div>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
@click="disconnectInstance"
|
||||||
|
:disabled="instance.instance.status === 'close'"
|
||||||
|
:loading="disconnect.loading"
|
||||||
|
variant="tonal"
|
||||||
|
color="error"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-cellphone-nfc-off</v-icon>
|
||||||
|
{{ disconnect.confirm ? "Tem Certeza?" : "Desconectar" }}
|
||||||
|
</v-btn>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useAppStore } from "@/store/app";
|
||||||
|
import statusMapper from "@/helpers/mappers/status";
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InstanceHeader",
|
||||||
|
data: () => ({
|
||||||
|
disconnect: {
|
||||||
|
confirm: false,
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
statusMapper: statusMapper,
|
||||||
|
AppStore: useAppStore(),
|
||||||
|
|
||||||
|
}),
|
||||||
|
methods: {
|
||||||
|
async disconnectInstance() {
|
||||||
|
if (!this.disconnect.confirm) return (this.disconnect.confirm = true);
|
||||||
|
|
||||||
|
this.disconnect.loading = true;
|
||||||
|
try {
|
||||||
|
this.disconnect.confirm = false;
|
||||||
|
await instanceController.logout(this.instance.instance.instanceName);
|
||||||
|
await this.AppStore.reconnect();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
alert(e.message || e.error || "Erro desconhecido");
|
||||||
|
} finally {
|
||||||
|
this.disconnect.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
owner() {
|
||||||
|
if (!this.instance?.instance?.owner)
|
||||||
|
return (
|
||||||
|
this.statusMapper[this.instance.instance.status]?.text ||
|
||||||
|
"Desconhecido"
|
||||||
|
);
|
||||||
|
return (this.instance?.instance?.owner || "").split("@")[0];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
220
src/components/instance/settings/Chatwoot.vue
Normal file
220
src/components/instance/settings/Chatwoot.vue
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
<template>
|
||||||
|
<v-card variant="outlined" :loading="loading">
|
||||||
|
<v-card-title class="d-flex align-center">
|
||||||
|
<v-icon start>mdi-chat</v-icon>
|
||||||
|
Chatwoot
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
icon
|
||||||
|
:disabled="loading"
|
||||||
|
variant="tonal"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
:style="{ transform: expanded ? 'rotate(180deg)' : '' }"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-chevron-down</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text v-if="expanded">
|
||||||
|
<v-alert v-if="error" type="error" class="mb-3">
|
||||||
|
{{ error }}
|
||||||
|
</v-alert>
|
||||||
|
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-text-field
|
||||||
|
v-model="chatwootData.url"
|
||||||
|
label="URL"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(url) => {
|
||||||
|
if (!url) return 'URL é obrigatório';
|
||||||
|
if (!url.startsWith('http'))
|
||||||
|
return 'URL deve começar com http ou https';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="d-flex gap-4 flex-wrap">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<v-text-field
|
||||||
|
v-model="chatwootData.account_id"
|
||||||
|
label="ID da conta"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(account_id) => {
|
||||||
|
if (!account_id) return 'ID da conta é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<v-text-field
|
||||||
|
v-model="chatwootData.token"
|
||||||
|
label="Token da conta"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(token) => {
|
||||||
|
if (!token) return 'Token é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex gap-x-4 flex-wrap">
|
||||||
|
<div>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="chatwootData.sign_msg"
|
||||||
|
label="Assinar mensagens"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
density="compact"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="chatwootData.reopen_conversation"
|
||||||
|
label="Reabrir conversa"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
density="compact"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="chatwootData.conversation_pending"
|
||||||
|
label="Conversa pendente"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
density="compact"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions v-if="expanded">
|
||||||
|
<v-switch
|
||||||
|
v-model="chatwootData.enabled"
|
||||||
|
label="Habilitado"
|
||||||
|
color="primary"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
></v-switch>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
:disabled="
|
||||||
|
!valid ||
|
||||||
|
JSON.stringify(chatwootData) === JSON.stringify(defaultChatwootData)
|
||||||
|
"
|
||||||
|
:loading="loading"
|
||||||
|
color="primary"
|
||||||
|
@click="saveChatwoot"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
Salvar
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InstanceChatwoot",
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
expanded: false,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
valid: false,
|
||||||
|
chatwootData: {
|
||||||
|
enabled: false,
|
||||||
|
url: "",
|
||||||
|
account_id: "",
|
||||||
|
token: "",
|
||||||
|
sign_msg: true,
|
||||||
|
reopen_conversation: true,
|
||||||
|
conversation_pending: false,
|
||||||
|
},
|
||||||
|
defaultChatwootData: {
|
||||||
|
enabled: false,
|
||||||
|
url: "",
|
||||||
|
account_id: "",
|
||||||
|
token: "",
|
||||||
|
sign_msg: true,
|
||||||
|
reopen_conversation: true,
|
||||||
|
conversation_pending: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async saveChatwoot() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
await instanceController.chatwoot.set(
|
||||||
|
this.instance.instance.instanceName,
|
||||||
|
{
|
||||||
|
...this.chatwootData,
|
||||||
|
url: this.chatwootData.url.trim().replace(/\/$/, ""),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.defaultChatwootData = Object.assign({}, this.chatwootData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadChatwoot() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
const chatwootData = await instanceController.chatwoot.get(
|
||||||
|
this.instance.instance.instanceName
|
||||||
|
);
|
||||||
|
|
||||||
|
this.chatwootData = Object.assign({}, chatwootData);
|
||||||
|
this.defaultChatwootData = Object.assign({}, chatwootData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
expanded(expanded) {
|
||||||
|
if (expanded) this.loadChatwoot();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
154
src/components/instance/settings/Rabbitmq.vue
Normal file
154
src/components/instance/settings/Rabbitmq.vue
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<template>
|
||||||
|
<v-card variant="outlined" :loading="loading">
|
||||||
|
<v-card-title class="d-flex align-center">
|
||||||
|
<v-icon start>mdi-rabbit</v-icon>
|
||||||
|
RabbitMQ
|
||||||
|
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
icon
|
||||||
|
:disabled="loading"
|
||||||
|
variant="tonal"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
:style="{ transform: expanded ? 'rotate(180deg)' : '' }"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-chevron-down</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text v-if="expanded">
|
||||||
|
<v-alert v-if="error" type="error" class="mb-3">
|
||||||
|
{{ error }}
|
||||||
|
</v-alert>
|
||||||
|
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-select
|
||||||
|
:items="rabbitmqEventsType"
|
||||||
|
v-model="rabbitmqData.events"
|
||||||
|
:disabled="loading"
|
||||||
|
label="Eventos"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
multiple
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
chips
|
||||||
|
/>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions v-if="expanded">
|
||||||
|
<v-switch
|
||||||
|
v-model="rabbitmqData.enabled"
|
||||||
|
label="Habilitado"
|
||||||
|
color="primary"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
></v-switch>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
:disabled="
|
||||||
|
!valid ||
|
||||||
|
JSON.stringify(rabbitmqData) === JSON.stringify(defaultRabbitmqData)
|
||||||
|
"
|
||||||
|
:loading="loading"
|
||||||
|
color="primary"
|
||||||
|
@click="saveRabbitmq"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
Salvar
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InstanceRabbitmq",
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
expanded: false,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
valid: false,
|
||||||
|
rabbitmqData: {
|
||||||
|
enabled: false,
|
||||||
|
events: [],
|
||||||
|
},
|
||||||
|
defaultRabbitmqData: {
|
||||||
|
enabled: false,
|
||||||
|
events: [],
|
||||||
|
},
|
||||||
|
rabbitmqEventsType: [
|
||||||
|
"APPLICATION_STARTUP",
|
||||||
|
"QRCODE_UPDATED",
|
||||||
|
"MESSAGES_SET",
|
||||||
|
"MESSAGES_UPSERT",
|
||||||
|
"MESSAGES_UPDATE",
|
||||||
|
"MESSAGES_DELETE",
|
||||||
|
"SEND_MESSAGE",
|
||||||
|
"CONTACTS_SET",
|
||||||
|
"CONTACTS_UPSERT",
|
||||||
|
"CONTACTS_UPDATE",
|
||||||
|
"PRESENCE_UPDATE",
|
||||||
|
"CHATS_SET",
|
||||||
|
"CHATS_UPSERT",
|
||||||
|
"CHATS_UPDATE",
|
||||||
|
"CHATS_DELETE",
|
||||||
|
"GROUPS_UPSERT",
|
||||||
|
"GROUP_UPDATE",
|
||||||
|
"GROUP_PARTICIPANTS_UPDATE",
|
||||||
|
"CONNECTION_UPDATE",
|
||||||
|
"CALL",
|
||||||
|
"NEW_JWT_TOKEN",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async saveRabbitmq() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
await instanceController.rabbitmq.set(
|
||||||
|
this.instance.instance.instanceName,
|
||||||
|
this.rabbitmqData
|
||||||
|
);
|
||||||
|
this.defaultRabbitmqData = Object.assign({}, this.rabbitmqData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadRabbitmq() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
const rabbitmqData = await instanceController.rabbitmq.get(
|
||||||
|
this.instance.instance.instanceName
|
||||||
|
);
|
||||||
|
|
||||||
|
this.rabbitmqData = Object.assign({}, rabbitmqData);
|
||||||
|
this.defaultRabbitmqData = Object.assign({}, rabbitmqData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.loadRabbitmq();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
252
src/components/instance/settings/Typebot.vue
Normal file
252
src/components/instance/settings/Typebot.vue
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
<template>
|
||||||
|
<v-card variant="outlined" :loading="loading">
|
||||||
|
<v-card-title class="d-flex align-center">
|
||||||
|
<v-icon start>mdi-robot-happy</v-icon>
|
||||||
|
Typebot
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
icon
|
||||||
|
:disabled="loading"
|
||||||
|
variant="tonal"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
:style="{ transform: expanded ? 'rotate(180deg)' : '' }"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-chevron-down</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text v-if="expanded">
|
||||||
|
<v-alert v-if="error" type="error" class="mb-3">
|
||||||
|
{{ error }}
|
||||||
|
</v-alert>
|
||||||
|
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-text-field
|
||||||
|
v-model="typebotData.url"
|
||||||
|
label="URL"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(url) => {
|
||||||
|
if (!url) return 'URL é obrigatório';
|
||||||
|
if (!url.startsWith('http'))
|
||||||
|
return 'URL deve começar com http ou https';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="d-flex gap-4 flex-wrap">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<v-text-field
|
||||||
|
v-model="typebotData.typebot"
|
||||||
|
label="Typebot"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(account_id) => {
|
||||||
|
if (!account_id) return 'Typebot é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<v-text-field
|
||||||
|
v-model="typebotData.keyword_finish"
|
||||||
|
label="Palavra-chave de finalização"
|
||||||
|
placeholder="#SAIR"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(token) => {
|
||||||
|
if (!token)
|
||||||
|
return 'Palavra-chave de finalização é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex gap-4 flex-wrap">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<v-text-field
|
||||||
|
v-model="typebotData.expire"
|
||||||
|
label="Tempo de expiração (em minutos)"
|
||||||
|
:disabled="loading"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(v) => {
|
||||||
|
if (!v) return 'Tempo de expiração é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<v-text-field
|
||||||
|
v-model="typebotData.delay_message"
|
||||||
|
label="Tempo de atraso da mensagem (em milisegundos)"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
:hint="`${typebotData.delay_message}ms = ${(
|
||||||
|
typebotData.delay_message / 1000
|
||||||
|
)
|
||||||
|
.toFixed(1)
|
||||||
|
.replace('.0', '')}s`"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(token) => {
|
||||||
|
if (token == null || token < 0)
|
||||||
|
return 'Palavra-chave de finalização é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-text-field
|
||||||
|
v-model="typebotData.unknown_message"
|
||||||
|
label="Mensagem de desconhecido"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(token) => {
|
||||||
|
if (!token) return 'Mensagem de desconhecido é obrigatório';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions v-if="expanded">
|
||||||
|
<v-switch
|
||||||
|
v-model="typebotData.enabled"
|
||||||
|
label="Habilitado"
|
||||||
|
color="primary"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
></v-switch>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
:disabled="
|
||||||
|
!valid ||
|
||||||
|
JSON.stringify(typebotData) === JSON.stringify(defaultTypebotData)
|
||||||
|
"
|
||||||
|
:loading="loading"
|
||||||
|
color="primary"
|
||||||
|
@click="saveTypebot"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
Salvar
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InstanceTypebot",
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
expanded: false,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
valid: false,
|
||||||
|
typebotData: {
|
||||||
|
enabled: false,
|
||||||
|
expire: 0,
|
||||||
|
sessions: [],
|
||||||
|
typebot: "",
|
||||||
|
url: "",
|
||||||
|
keyword_finish: "",
|
||||||
|
unknown_message: "",
|
||||||
|
},
|
||||||
|
defaultTypebotData: {
|
||||||
|
enabled: false,
|
||||||
|
expire: 0,
|
||||||
|
sessions: [],
|
||||||
|
typebot: "",
|
||||||
|
url: "",
|
||||||
|
keyword_finish: "",
|
||||||
|
unknown_message: "",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async saveTypebot() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
await instanceController.typebot.set(
|
||||||
|
this.instance.instance.instanceName,
|
||||||
|
{
|
||||||
|
...this.typebotData,
|
||||||
|
url: this.typebotData.url.trim().replace(/\/$/, ""),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.defaultTypebotData = Object.assign({}, this.typebotData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadTypebot() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
const typebotData = await instanceController.typebot.get(
|
||||||
|
this.instance.instance.instanceName
|
||||||
|
);
|
||||||
|
|
||||||
|
this.typebotData = Object.assign({}, typebotData);
|
||||||
|
this.defaultTypebotData = Object.assign({}, typebotData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
expanded(expanded) {
|
||||||
|
if (expanded) this.loadTypebot();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
204
src/components/instance/settings/Webhook.vue
Normal file
204
src/components/instance/settings/Webhook.vue
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<v-card variant="outlined" :loading="loading">
|
||||||
|
<v-card-title class="d-flex align-center">
|
||||||
|
<v-icon start>mdi-webhook</v-icon>
|
||||||
|
Webhook
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
icon
|
||||||
|
:disabled="loading"
|
||||||
|
variant="tonal"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
:style="{ transform: expanded ? 'rotate(180deg)' : '' }"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-chevron-down</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text v-if="expanded">
|
||||||
|
<v-alert v-if="error" type="error" class="mb-3">
|
||||||
|
{{ error }}
|
||||||
|
</v-alert>
|
||||||
|
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-text-field
|
||||||
|
v-model="webhookData.url"
|
||||||
|
label="URL"
|
||||||
|
:disabled="loading"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-3"
|
||||||
|
:rules="[
|
||||||
|
(url) => {
|
||||||
|
if (!url) return 'URL é obrigatório';
|
||||||
|
if (!url.startsWith('http'))
|
||||||
|
return 'URL deve começar com http ou https';
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-select
|
||||||
|
:items="webhookEventsType"
|
||||||
|
v-model="webhookData.events"
|
||||||
|
:disabled="loading"
|
||||||
|
label="Eventos"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
multiple
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
chips
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="d-flex gap-x-4 flex-wrap align-center">
|
||||||
|
<div>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="webhookData.webhook_base64"
|
||||||
|
:disabled="loading"
|
||||||
|
label="Webhook base64"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
density="compact"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="webhookData.webhook_by_events"
|
||||||
|
:disabled="loading"
|
||||||
|
label="Webhook por eventos"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
density="compact"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions v-if="expanded">
|
||||||
|
<v-switch
|
||||||
|
v-model="webhookData.enabled"
|
||||||
|
label="Habilitado"
|
||||||
|
color="primary"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
></v-switch>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
:disabled="
|
||||||
|
!valid ||
|
||||||
|
JSON.stringify(webhookData) === JSON.stringify(defaultWebhookData)
|
||||||
|
"
|
||||||
|
:loading="loading"
|
||||||
|
color="primary"
|
||||||
|
@click="saveWebhook"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
Salvar
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InstanceWebhook",
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
expanded: false,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
valid: false,
|
||||||
|
webhookData: {
|
||||||
|
enabled: false,
|
||||||
|
events: [],
|
||||||
|
url: "",
|
||||||
|
webhook_base64: false,
|
||||||
|
webhook_by_events: false,
|
||||||
|
},
|
||||||
|
defaultWebhookData: {
|
||||||
|
enabled: false,
|
||||||
|
events: [],
|
||||||
|
url: "",
|
||||||
|
webhook_base64: false,
|
||||||
|
webhook_by_events: false,
|
||||||
|
},
|
||||||
|
webhookEventsType: [
|
||||||
|
"APPLICATION_STARTUP",
|
||||||
|
"QRCODE_UPDATED",
|
||||||
|
"MESSAGES_SET",
|
||||||
|
"MESSAGES_UPSERT",
|
||||||
|
"MESSAGES_UPDATE",
|
||||||
|
"MESSAGES_DELETE",
|
||||||
|
"SEND_MESSAGE",
|
||||||
|
"CONTACTS_SET",
|
||||||
|
"CONTACTS_UPSERT",
|
||||||
|
"CONTACTS_UPDATE",
|
||||||
|
"PRESENCE_UPDATE",
|
||||||
|
"CHATS_SET",
|
||||||
|
"CHATS_UPSERT",
|
||||||
|
"CHATS_UPDATE",
|
||||||
|
"CHATS_DELETE",
|
||||||
|
"GROUPS_UPSERT",
|
||||||
|
"GROUP_UPDATE",
|
||||||
|
"GROUP_PARTICIPANTS_UPDATE",
|
||||||
|
"CONNECTION_UPDATE",
|
||||||
|
"CALL",
|
||||||
|
"NEW_JWT_TOKEN",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async saveWebhook() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
await instanceController.webhook.set(
|
||||||
|
this.instance.instance.instanceName,
|
||||||
|
{
|
||||||
|
...this.webhookData,
|
||||||
|
url: this.webhookData.url.trim().replace(/\/$/, ""),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.defaultWebhookData = Object.assign({}, this.webhookData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadWebhook() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
const webhookData = await instanceController.webhook.get(
|
||||||
|
this.instance.instance.instanceName
|
||||||
|
);
|
||||||
|
|
||||||
|
this.webhookData = Object.assign({}, webhookData);
|
||||||
|
this.defaultWebhookData = Object.assign({}, webhookData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
expanded(expanded) {
|
||||||
|
if (expanded) this.loadWebhook();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
157
src/components/instance/settings/Websocket.vue
Normal file
157
src/components/instance/settings/Websocket.vue
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<v-card variant="outlined" :loading="loading">
|
||||||
|
<v-card-title class="d-flex align-center">
|
||||||
|
<v-icon start>mdi-email-fast</v-icon>
|
||||||
|
Websocket
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
icon
|
||||||
|
:disabled="loading"
|
||||||
|
variant="tonal"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
:style="{ transform: expanded ? 'rotate(180deg)' : '' }"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-chevron-down</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text v-if="expanded">
|
||||||
|
<v-alert v-if="error" type="error" class="mb-3">
|
||||||
|
{{ error }}
|
||||||
|
</v-alert>
|
||||||
|
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<v-select
|
||||||
|
:items="websocketEventsType"
|
||||||
|
v-model="websocketData.events"
|
||||||
|
:disabled="loading"
|
||||||
|
label="Eventos"
|
||||||
|
hide-details
|
||||||
|
class="mb-3"
|
||||||
|
multiple
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
chips
|
||||||
|
/>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions v-if="expanded">
|
||||||
|
<v-switch
|
||||||
|
v-model="websocketData.enabled"
|
||||||
|
label="Habilitado"
|
||||||
|
color="primary"
|
||||||
|
:disabled="loading"
|
||||||
|
hide-details
|
||||||
|
></v-switch>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
:disabled="
|
||||||
|
!valid ||
|
||||||
|
JSON.stringify(websocketData) === JSON.stringify(defaultWebsocketData)
|
||||||
|
"
|
||||||
|
:loading="loading"
|
||||||
|
color="primary"
|
||||||
|
@click="saveWebsocket"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
Salvar
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "InstanceWebsocket",
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
expanded: false,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
valid: false,
|
||||||
|
websocketData: {
|
||||||
|
enabled: false,
|
||||||
|
events: [],
|
||||||
|
},
|
||||||
|
defaultWebsocketData: {
|
||||||
|
enabled: false,
|
||||||
|
events: [],
|
||||||
|
},
|
||||||
|
websocketEventsType: [
|
||||||
|
"APPLICATION_STARTUP",
|
||||||
|
"QRCODE_UPDATED",
|
||||||
|
"MESSAGES_SET",
|
||||||
|
"MESSAGES_UPSERT",
|
||||||
|
"MESSAGES_UPDATE",
|
||||||
|
"MESSAGES_DELETE",
|
||||||
|
"SEND_MESSAGE",
|
||||||
|
"CONTACTS_SET",
|
||||||
|
"CONTACTS_UPSERT",
|
||||||
|
"CONTACTS_UPDATE",
|
||||||
|
"PRESENCE_UPDATE",
|
||||||
|
"CHATS_SET",
|
||||||
|
"CHATS_UPSERT",
|
||||||
|
"CHATS_UPDATE",
|
||||||
|
"CHATS_DELETE",
|
||||||
|
"GROUPS_UPSERT",
|
||||||
|
"GROUP_UPDATE",
|
||||||
|
"GROUP_PARTICIPANTS_UPDATE",
|
||||||
|
"CONNECTION_UPDATE",
|
||||||
|
"CALL",
|
||||||
|
"NEW_JWT_TOKEN",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async saveWebsocket() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
await instanceController.websocket.set(
|
||||||
|
this.instance.instance.instanceName,
|
||||||
|
this.websocketData
|
||||||
|
);
|
||||||
|
this.defaultWebsocketData = Object.assign({}, this.websocketData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadWebsocket() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
const websocketData = await instanceController.websocket.get(
|
||||||
|
this.instance.instance.instanceName
|
||||||
|
);
|
||||||
|
|
||||||
|
this.websocketData = Object.assign({}, websocketData);
|
||||||
|
this.defaultWebsocketData = Object.assign({}, websocketData);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
expanded: {
|
||||||
|
handler() {
|
||||||
|
if (this.expanded) this.loadWebsocket();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
99
src/components/modal/ConnectPhone.vue
Normal file
99
src/components/modal/ConnectPhone.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<v-alert
|
||||||
|
icon="mdi-qrcode-scan"
|
||||||
|
v-if="instance.instance?.status != 'open'"
|
||||||
|
type="warning"
|
||||||
|
>
|
||||||
|
<div class="d-flex justify-space-between align-center flex-wrap">
|
||||||
|
<span>Telefone não conectado</span>
|
||||||
|
<v-btn @click="startConnect" size="small"> Conectar </v-btn>
|
||||||
|
</div>
|
||||||
|
</v-alert>
|
||||||
|
<v-dialog v-model="dialog" max-width="350px">
|
||||||
|
<v-card :loading="loading && qrCode">
|
||||||
|
<v-card-text>
|
||||||
|
<v-img v-if="qrCode" :src="qrCode" width="300px" height="300px" />
|
||||||
|
<v-card
|
||||||
|
v-else
|
||||||
|
width="300px"
|
||||||
|
height="300px"
|
||||||
|
variant="outlined"
|
||||||
|
elevation="0"
|
||||||
|
>
|
||||||
|
<v-card-text class="d-flex justify-center align-center h-100">
|
||||||
|
<v-progress-circular indeterminate color="primary" />
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
|
||||||
|
<v-alert type="error" v-if="error">
|
||||||
|
{{ Array.isArray(error) ? error.join(", ") : error }}
|
||||||
|
</v-alert>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn text @click="dialog = false" :disabled="loading"> Cancel </v-btn>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useAppStore } from "@/store/app";
|
||||||
|
import instanceController from "@/services/instanceController";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SettingsModal",
|
||||||
|
data: () => ({
|
||||||
|
dialog: false,
|
||||||
|
error: false,
|
||||||
|
|
||||||
|
loading: false,
|
||||||
|
qrCode: null,
|
||||||
|
success: false,
|
||||||
|
|
||||||
|
timeout: null,
|
||||||
|
|
||||||
|
AppStore: useAppStore(),
|
||||||
|
}),
|
||||||
|
methods: {
|
||||||
|
async loadQr() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
this.error = false;
|
||||||
|
|
||||||
|
const response = await instanceController.connect(
|
||||||
|
this.instance.instance.instanceName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.base64) this.qrCode = response.base64;
|
||||||
|
else {
|
||||||
|
this.dialog = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.timeout = setTimeout(this.loadQr, 40000);
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e.message?.message || e.message || e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async startConnect() {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.dialog = true;
|
||||||
|
this.error = false;
|
||||||
|
|
||||||
|
await this.loadQr();
|
||||||
|
await this.AppStore.reconnect();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ["close"],
|
||||||
|
};
|
||||||
|
</script>
|
@ -5,7 +5,7 @@
|
|||||||
:persistent="!AppStore.validConnection"
|
:persistent="!AppStore.validConnection"
|
||||||
>
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-text>
|
<v-card-text class="d-flex flex-column gap-4">
|
||||||
<v-form v-model="valid">
|
<v-form v-model="valid">
|
||||||
<h3 class="mb-4">Criar instancia</h3>
|
<h3 class="mb-4">Criar instancia</h3>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@ -21,7 +21,7 @@
|
|||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="instance.apiKey"
|
v-model="instance.token"
|
||||||
label="API Key"
|
label="API Key"
|
||||||
required
|
required
|
||||||
outlined
|
outlined
|
||||||
@ -41,7 +41,7 @@
|
|||||||
configurados após a criação da instância.
|
configurados após a criação da instância.
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<v-alert type="error" v-if="error">
|
<v-alert type="error" v-if="error" >
|
||||||
{{ Array.isArray(error) ? error.join(", ") : error }}
|
{{ Array.isArray(error) ? error.join(", ") : error }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@ -62,7 +62,7 @@
|
|||||||
:disabled="!valid"
|
:disabled="!valid"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
Conectar
|
Criar
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
@ -80,7 +80,7 @@ export default {
|
|||||||
valid: false,
|
valid: false,
|
||||||
instance: {
|
instance: {
|
||||||
instanceName: "",
|
instanceName: "",
|
||||||
apiKey: "",
|
token: "",
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
error: false,
|
error: false,
|
||||||
@ -88,7 +88,7 @@ export default {
|
|||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
generateApiKey() {
|
generateApiKey() {
|
||||||
this.instance.apiKey =
|
this.instance.token =
|
||||||
Math.random().toString(36).substring(2, 15) +
|
Math.random().toString(36).substring(2, 15) +
|
||||||
Math.random().toString(36).substring(2, 15);
|
Math.random().toString(36).substring(2, 15);
|
||||||
},
|
},
|
||||||
|
@ -1,25 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-dialog
|
<v-dialog v-model="dialog" max-width="500px" :persistent="!AppStore.validConnection">
|
||||||
v-model="dialog"
|
|
||||||
max-width="500px"
|
|
||||||
:persistent="!AppStore.validConnection"
|
|
||||||
>
|
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
|
<v-form v-model="valid">
|
||||||
|
<h3 class="mb-4">Configurar conexão</h3>
|
||||||
|
|
||||||
|
<v-text-field
|
||||||
|
v-model="apiKey"
|
||||||
|
label="Global API Key"
|
||||||
|
required
|
||||||
|
outlined
|
||||||
|
:type="revelPassword ? 'text' : 'password'"
|
||||||
|
:append-inner-icon="revelPassword ? 'mdi-eye' : 'mdi-eye-off'"
|
||||||
|
@click:append-inner="revelPassword = !revelPassword"
|
||||||
|
/>
|
||||||
|
</v-form>
|
||||||
|
|
||||||
<v-alert type="error" v-if="error">
|
<v-alert type="error" v-if="error">
|
||||||
{{ Array.isArray(error) ? error.join(", ") : error }}
|
{{ Array.isArray(error) ? error.join(", ") : error }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn
|
<v-btn text to="/" :disabled="loading">Cancel</v-btn>
|
||||||
v-if="AppStore.validConnection"
|
|
||||||
text
|
|
||||||
@click="dialog = false"
|
|
||||||
:disabled="loading"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</v-btn>
|
|
||||||
<v-btn
|
<v-btn
|
||||||
color="success"
|
color="success"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
@ -35,13 +38,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import instanceController from "@/services/instanceController";
|
|
||||||
import { useAppStore } from "@/store/app";
|
import { useAppStore } from "@/store/app";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SettingsModal",
|
name: "SettingsModal",
|
||||||
data: () => ({
|
data: () => ({
|
||||||
dialog: false,
|
dialog: false,
|
||||||
|
valid: false,
|
||||||
|
revelPassword: false,
|
||||||
|
connection: {
|
||||||
|
host: "",
|
||||||
|
globalApiKey: "",
|
||||||
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
error: false,
|
error: false,
|
||||||
AppStore: useAppStore(),
|
AppStore: useAppStore(),
|
||||||
@ -52,13 +60,8 @@ export default {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = false;
|
this.error = false;
|
||||||
|
|
||||||
const instance = await instanceController.create(this.instance);
|
await this.AppStore.setConnection(this.connection);
|
||||||
await this.AppStore.reconnect();
|
this.dialog = false;
|
||||||
|
|
||||||
this.$router.push({
|
|
||||||
name: "instance",
|
|
||||||
params: { id: instance.instance.instanceName },
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e.message?.message || e.message || e;
|
this.error = e.message?.message || e.message || e;
|
||||||
} finally {
|
} finally {
|
||||||
@ -67,9 +70,6 @@ export default {
|
|||||||
},
|
},
|
||||||
open() {
|
open() {
|
||||||
this.dialog = true;
|
this.dialog = true;
|
||||||
this.error = false;
|
|
||||||
this.instance.instanceName = "";
|
|
||||||
this.generateApiKey();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -2,11 +2,16 @@ export default {
|
|||||||
close: {
|
close: {
|
||||||
color: "red",
|
color: "red",
|
||||||
text: "Desconectado",
|
text: "Desconectado",
|
||||||
icon: "mdi-close-circle",
|
icon: "mdi-cellphone-off",
|
||||||
|
},
|
||||||
|
connecting: {
|
||||||
|
color: "warning",
|
||||||
|
text: "Conectando",
|
||||||
|
icon: "mdi-cellphone-settings",
|
||||||
},
|
},
|
||||||
open: {
|
open: {
|
||||||
color: "green",
|
color: "green",
|
||||||
text: "Conectado",
|
text: "Conectado",
|
||||||
icon: "mdi-check-circle",
|
icon: "mdi-cellphone-nfc",
|
||||||
},
|
},
|
||||||
}
|
}
|
@ -15,6 +15,27 @@ http.interceptors.request.use(
|
|||||||
config.baseURL = appStore.connection.host;
|
config.baseURL = appStore.connection.host;
|
||||||
config.headers["apikey"] = appStore.connection.globalApiKey;
|
config.headers["apikey"] = appStore.connection.globalApiKey;
|
||||||
|
|
||||||
|
// find all uri variables and replace them with the value from the params object
|
||||||
|
// e.g. /instance/connect/:instance -> /instance/connect/instance1
|
||||||
|
const params = Object.entries(config.params || {});
|
||||||
|
if (params.length > 0) {
|
||||||
|
config.url = config.url.replace(/:(\w+)/g, (_, key) => {
|
||||||
|
const value = params.find(([k]) => k === key)?.[1];
|
||||||
|
if (value) {
|
||||||
|
delete config.params[key];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return _;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (params.instance) {
|
||||||
|
const apikey = appStore.getInstanceApiKey(params.instance);
|
||||||
|
if (apikey) config.headers["apikey"] = apikey;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
error => Promise.reject(error)
|
error => Promise.reject(error)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app-bar flat>
|
<v-app-bar flat>
|
||||||
<v-app-bar-title>
|
<v-app-bar-title>
|
||||||
<v-icon icon="mdi-whatsapp" left />
|
<v-btn variant="text" @click="$router.push('/')">
|
||||||
Evolution Manager
|
<v-img src="@/assets/logo.png" height="24" width="24" class="mr-2" />
|
||||||
|
Evolution Manager
|
||||||
|
</v-btn>
|
||||||
</v-app-bar-title>
|
</v-app-bar-title>
|
||||||
|
|
||||||
<v-icon v-if="AppStore.validConnection" color="success">
|
<v-icon v-if="AppStore.validConnection" color="success">
|
||||||
@ -33,8 +35,9 @@ export default {
|
|||||||
this.$refs.settings.open();
|
this.$refs.settings.open();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
if (!this.AppValidConnection) this.openSettings();
|
await this.AppStore.loadConnection();
|
||||||
|
if (!this.AppStore.validConnection) this.openSettings();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -19,8 +19,40 @@ const create = async (data) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const connect = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.get("/instance/connect/:instance", {
|
||||||
|
params: {
|
||||||
|
instance: instanceName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const logout = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.delete("/instance/logout/:instance", {
|
||||||
|
params: {
|
||||||
|
instance: instanceName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
import settings from "./instanceSettingsController.js";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
fetchAll,
|
fetchAll,
|
||||||
create
|
create,
|
||||||
|
connect,
|
||||||
|
logout,
|
||||||
|
...settings
|
||||||
|
|
||||||
};
|
};
|
||||||
|
139
src/services/instanceSettingsController.js
Normal file
139
src/services/instanceSettingsController.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
|
||||||
|
import http from "../http-common";
|
||||||
|
|
||||||
|
const findWebhook = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.get("/webhook/find/:instance", {
|
||||||
|
params: {
|
||||||
|
instance: instanceName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const setWebhook = async (instanceName, data) => {
|
||||||
|
return await http
|
||||||
|
.post("/webhook/set/:instance", data, {
|
||||||
|
params: {
|
||||||
|
instance: instanceName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const findWebsocket = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.get("/websocket/find/:instance", {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const setWebsocket = async (instanceName, data) => {
|
||||||
|
return await http
|
||||||
|
.post("/websocket/set/:instance", data, {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const findRabbitmq = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.get("/rabbitmq/find/:instance", {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const setRabbitmq = async (instanceName, data) => {
|
||||||
|
return await http
|
||||||
|
.post("/rabbitmq/set/:instance", data, {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const findChatwoot = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.get("/chatwoot/find/:instance", {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const setChatwoot = async (instanceName, data) => {
|
||||||
|
return await http
|
||||||
|
.post("/chatwoot/set/:instance", data, {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const findTypebot = async (instanceName) => {
|
||||||
|
return await http
|
||||||
|
.get("/typebot/find/:instance", {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTypebot = async (instanceName, data) => {
|
||||||
|
return await http
|
||||||
|
.post("/typebot/set/:instance", data, {
|
||||||
|
params: { instance: instanceName }
|
||||||
|
})
|
||||||
|
.then((r) => r.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error.response?.data || error.response || error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
webhook: {
|
||||||
|
get: findWebhook,
|
||||||
|
set: setWebhook,
|
||||||
|
},
|
||||||
|
websocket: {
|
||||||
|
get: findWebsocket,
|
||||||
|
set: setWebsocket,
|
||||||
|
},
|
||||||
|
rabbitmq: {
|
||||||
|
get: findRabbitmq,
|
||||||
|
set: setRabbitmq,
|
||||||
|
},
|
||||||
|
chatwoot: {
|
||||||
|
get: findChatwoot,
|
||||||
|
set: setChatwoot,
|
||||||
|
},
|
||||||
|
typebot: {
|
||||||
|
get: findTypebot,
|
||||||
|
set: setTypebot,
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,18 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
|
||||||
export const useAppStore = defineStore('app', {
|
export const useAppStore = defineStore('app', {
|
||||||
getters: {
|
getters: {
|
||||||
validConnection: (state) => state.connection.valid,
|
validConnection: (state) => state.connection.valid,
|
||||||
instances: (state) => state.instancesList,
|
instances: (state) => state.instancesList,
|
||||||
|
getInstance: (state) => (instanceName) => state.instancesList.find(
|
||||||
|
(instance) => instance.instance.instanceName === instanceName
|
||||||
|
),
|
||||||
|
getInstanceApiKey: (state) => (instance) => {
|
||||||
|
return state.getInstance(instance).instance.apiKey ||
|
||||||
|
state.instancesKeys[instance]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
state: () => ({
|
state: () => ({
|
||||||
connection: {
|
connection: {
|
||||||
@ -13,6 +21,7 @@ export const useAppStore = defineStore('app', {
|
|||||||
host: null,
|
host: null,
|
||||||
globalApiKey: null,
|
globalApiKey: null,
|
||||||
},
|
},
|
||||||
|
instancesKeys: {},
|
||||||
instancesList: [],
|
instancesList: [],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -29,9 +38,8 @@ export const useAppStore = defineStore('app', {
|
|||||||
url: '/instance/fetchInstances'
|
url: '/instance/fetchInstances'
|
||||||
})
|
})
|
||||||
|
|
||||||
this.connection.valid = true
|
this.saveConnection({ host, globalApiKey })
|
||||||
this.connection.host = host
|
|
||||||
this.connection.globalApiKey = globalApiKey
|
|
||||||
this.instancesList = responde.data
|
this.instancesList = responde.data
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.connection.valid = false
|
this.connection.valid = false
|
||||||
@ -39,10 +47,31 @@ export const useAppStore = defineStore('app', {
|
|||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async loadInstance(instanceName) {
|
||||||
|
try {
|
||||||
|
const { host, globalApiKey } = this.connection;
|
||||||
|
|
||||||
|
const response = await axios({
|
||||||
|
method: 'GET',
|
||||||
|
baseURL: host,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'apikey': globalApiKey
|
||||||
|
},
|
||||||
|
url: `/instance/fetchInstances?instanceName=${instanceName}`
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
this.connection.valid = false
|
||||||
|
throw e.response?.data?.response?.message || e.response || e
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async reconnect() {
|
async reconnect() {
|
||||||
try {
|
try {
|
||||||
const { host, globalApiKey } = this.connection
|
const { host, globalApiKey } = this.connection
|
||||||
const responde = await axios({
|
const response = await axios({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
baseURL: host,
|
baseURL: host,
|
||||||
headers: {
|
headers: {
|
||||||
@ -52,14 +81,48 @@ export const useAppStore = defineStore('app', {
|
|||||||
url: '/instance/fetchInstances'
|
url: '/instance/fetchInstances'
|
||||||
})
|
})
|
||||||
|
|
||||||
this.connection.valid = true
|
this.saveConnection({ host, globalApiKey })
|
||||||
this.connection.host = host
|
|
||||||
this.connection.globalApiKey = globalApiKey
|
this.instancesList = response.data
|
||||||
this.instancesList = responde.data
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.connection.valid = false
|
this.connection.valid = false
|
||||||
throw e.response?.data?.response?.message || e.response || e
|
throw e.response?.data?.response?.message || e.response || e
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setInstanceStatus(instance, status) {
|
||||||
|
const index = this.instancesList.findIndex(
|
||||||
|
(instance) => instance.instance.instanceName === instance
|
||||||
|
)
|
||||||
|
this.instancesList[index].instance.status = status
|
||||||
|
},
|
||||||
|
|
||||||
|
addInstanceKey({ instance, key }) {
|
||||||
|
this.instancesKeys[instance] = key
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
saveConnection({ host, globalApiKey }) {
|
||||||
|
this.connection = {
|
||||||
|
valid: true,
|
||||||
|
host,
|
||||||
|
globalApiKey,
|
||||||
|
}
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window.localStorage.setItem('connection', JSON.stringify({
|
||||||
|
host,
|
||||||
|
globalApiKey,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadConnection() {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const connection = window.localStorage.getItem('connection')
|
||||||
|
if (connection) {
|
||||||
|
this.connection = JSON.parse(connection)
|
||||||
|
return this.reconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -3,33 +3,21 @@
|
|||||||
{{ error }}
|
{{ error }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
<div v-else-if="instance" class="d-flex flex-column" style="gap: 1.5rem">
|
<div v-else-if="instance" class="d-flex flex-column" style="gap: 1.5rem">
|
||||||
;
|
<InstanceHeader :instance="instance" />
|
||||||
<v-card variant="outlined" class="d-flex align-center">
|
<ConnectPhone :instance="instance" />
|
||||||
<v-avatar size="100">
|
|
||||||
<v-icon v-if="statusMapper[instance.instance.status].icon" size="70">
|
<InstanceBody :instance="instance" />
|
||||||
{{ statusMapper[instance.instance.status].icon }}
|
|
||||||
</v-icon>
|
<InstanceApiKey :instance="instance" ref="apiKeyModal" />
|
||||||
</v-avatar>
|
|
||||||
<div>
|
|
||||||
<h2>{{ instance.instance.instanceName }}</h2>
|
|
||||||
</div>
|
|
||||||
</v-card>
|
|
||||||
<v-alert
|
|
||||||
icon="mdi-qrcode-scan"
|
|
||||||
v-if="instance.status != 'connected'"
|
|
||||||
type="warning"
|
|
||||||
>
|
|
||||||
<div class="d-flex justify-space-between align-center flex-wrap">
|
|
||||||
<span>Telefone não conectado</span>
|
|
||||||
<v-btn @click="connectPhone" size="small"> Conectar </v-btn>
|
|
||||||
</div>
|
|
||||||
</v-alert>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useAppStore } from "@/store/app";
|
import { useAppStore } from "@/store/app";
|
||||||
import statusMapper from "@/helpers/mappers/status";
|
import InstanceApiKey from "@/components/modal/InstanceApiKey.vue";
|
||||||
|
import ConnectPhone from "@/components/modal/ConnectPhone.vue";
|
||||||
|
import InstanceHeader from "@/components/instance/InstanceHeader.vue";
|
||||||
|
import InstanceBody from "@/components/instance/InstanceBody.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "HomeInstance",
|
name: "HomeInstance",
|
||||||
@ -37,27 +25,32 @@ export default {
|
|||||||
AppStore: useAppStore(),
|
AppStore: useAppStore(),
|
||||||
loading: true,
|
loading: true,
|
||||||
error: false,
|
error: false,
|
||||||
instance: null,
|
|
||||||
statusMapper: statusMapper,
|
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
async loadInstance() {
|
async loadInstance() {
|
||||||
if (!this.AppStore.instances) await this.AppStore.reconnect();
|
try {
|
||||||
const instances = this.AppStore.instances;
|
this.loading = true;
|
||||||
const instance = instances.find(
|
this.error = false;
|
||||||
(instance) => instance.instance.instanceName === this.$route.params.id
|
await this.AppStore.loadInstance(this.$route.params.id);
|
||||||
);
|
} catch (e) {
|
||||||
if (!instance) {
|
this.error = e.message?.message || e.message || e;
|
||||||
this.error = "Instância não encontrada";
|
} finally {
|
||||||
return;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
this.instance = instance;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
instance() {
|
||||||
|
return this.AppStore.getInstance(this.$route.params.id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
if (this.AppStore.validConnection) this.loadInstance();
|
if (this.AppStore.validConnection) this.loadInstance();
|
||||||
else this.$router.push({ name: "instances" });
|
else this.$router.push({ name: "instances" });
|
||||||
},
|
},
|
||||||
|
components: { InstanceApiKey, ConnectPhone, InstanceHeader, InstanceBody },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user