KI-AGENT: Telefonie Nebenstellen in Einstellungen integrieren
This commit is contained in:
@@ -400,6 +400,32 @@ const canArchiveItem = computed(() => {
|
||||
return true
|
||||
})
|
||||
|
||||
const telephonyExtensionTarget = computed(() => {
|
||||
if (!item.value?.id) return null
|
||||
|
||||
if (type === "teams") {
|
||||
return {
|
||||
targetType: "team",
|
||||
targetId: item.value.id,
|
||||
displayName: item.value.name || "Team",
|
||||
title: "Telefonie",
|
||||
description: "Lege fest, unter welcher Nebenstelle dieses Team erreichbar ist."
|
||||
}
|
||||
}
|
||||
|
||||
if (type === "branches") {
|
||||
return {
|
||||
targetType: "branch",
|
||||
targetId: item.value.id,
|
||||
displayName: item.value.name || "Niederlassung",
|
||||
title: "Telefonie",
|
||||
description: "Lege fest, unter welcher Nebenstelle diese Niederlassung erreichbar ist."
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
const createItem = async () => {
|
||||
let ret = null
|
||||
|
||||
@@ -1036,6 +1062,16 @@ const updateItem = async () => {
|
||||
</InputGroup>
|
||||
</UFormField>
|
||||
</UForm>
|
||||
|
||||
<TelephonyExtensionField
|
||||
v-if="telephonyExtensionTarget"
|
||||
class="mx-5 mb-5"
|
||||
:target-type="telephonyExtensionTarget.targetType"
|
||||
:target-id="telephonyExtensionTarget.targetId"
|
||||
:display-name="telephonyExtensionTarget.displayName"
|
||||
:title="telephonyExtensionTarget.title"
|
||||
:description="telephonyExtensionTarget.description"
|
||||
/>
|
||||
</UDashboardPanelContent>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -85,11 +85,6 @@ const links = computed(() => {
|
||||
to: "/communication/phone",
|
||||
icon: "i-heroicons-phone"
|
||||
},
|
||||
{
|
||||
label: "Telefonie Setup",
|
||||
to: "/communication/phone-setup",
|
||||
icon: "i-heroicons-cog-6-tooth"
|
||||
},
|
||||
featureEnabled("helpdesk") ? {
|
||||
label: "Helpdesk",
|
||||
to: "/helpdesk",
|
||||
@@ -342,6 +337,11 @@ const links = computed(() => {
|
||||
to: "/settings/tenant",
|
||||
icon: "i-heroicons-building-office",
|
||||
} : null,
|
||||
{
|
||||
label: "Telefonie",
|
||||
to: "/settings/telephony",
|
||||
icon: "i-heroicons-phone",
|
||||
},
|
||||
{
|
||||
label: "Matrix-Setup",
|
||||
to: "/communication",
|
||||
|
||||
197
frontend/components/TelephonyExtensionField.vue
Normal file
197
frontend/components/TelephonyExtensionField.vue
Normal file
@@ -0,0 +1,197 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
targetType: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
targetId: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
displayName: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "Telefonie"
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: "Lege fest, unter welcher internen Nebenstelle dieses Ziel erreichbar ist."
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(["saved"])
|
||||
|
||||
const toast = useToast()
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const deleting = ref(false)
|
||||
const extension = ref("")
|
||||
const enabled = ref(true)
|
||||
const existingId = ref(null)
|
||||
|
||||
const canUseExtension = computed(() => Boolean(props.targetId))
|
||||
const statusLabel = computed(() => {
|
||||
if (!canUseExtension.value) return "Kein Ziel verknüpft"
|
||||
if (!extension.value) return "Keine Nebenstelle"
|
||||
return enabled.value ? `Nebenstelle ${extension.value}` : `Nebenstelle ${extension.value} inaktiv`
|
||||
})
|
||||
const statusColor = computed(() => {
|
||||
if (!canUseExtension.value) return "neutral"
|
||||
if (!extension.value) return "neutral"
|
||||
return enabled.value ? "success" : "warning"
|
||||
})
|
||||
|
||||
const loadExtension = async () => {
|
||||
if (!canUseExtension.value) return
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const res = await useNuxtApp().$api("/api/telephony/extensions/target", {
|
||||
params: {
|
||||
targetType: props.targetType,
|
||||
targetId: props.targetId
|
||||
}
|
||||
})
|
||||
existingId.value = res?.extension?.id || null
|
||||
extension.value = res?.extension?.extension || ""
|
||||
enabled.value = res?.extension ? res.extension.enabled !== false : true
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: "Nebenstelle konnte nicht geladen werden",
|
||||
description: error?.data?.error || error?.message,
|
||||
color: "error"
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const saveExtension = async () => {
|
||||
if (!canUseExtension.value || saving.value) return
|
||||
saving.value = true
|
||||
|
||||
try {
|
||||
const res = await useNuxtApp().$api("/api/telephony/extensions/target", {
|
||||
method: "PUT",
|
||||
body: {
|
||||
targetType: props.targetType,
|
||||
targetId: props.targetId,
|
||||
extension: extension.value,
|
||||
displayName: props.displayName,
|
||||
enabled: enabled.value
|
||||
}
|
||||
})
|
||||
existingId.value = res?.id || existingId.value
|
||||
extension.value = res?.extension || extension.value
|
||||
enabled.value = res?.enabled !== false
|
||||
toast.add({ title: "Nebenstelle gespeichert", color: "success" })
|
||||
emit("saved", res)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: "Nebenstelle konnte nicht gespeichert werden",
|
||||
description: error?.data?.error || error?.message,
|
||||
color: "error"
|
||||
})
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteExtension = async () => {
|
||||
if (!canUseExtension.value || deleting.value) return
|
||||
deleting.value = true
|
||||
|
||||
try {
|
||||
await useNuxtApp().$api("/api/telephony/extensions/target", {
|
||||
method: "DELETE",
|
||||
params: {
|
||||
targetType: props.targetType,
|
||||
targetId: props.targetId
|
||||
}
|
||||
})
|
||||
existingId.value = null
|
||||
extension.value = ""
|
||||
enabled.value = true
|
||||
toast.add({ title: "Nebenstelle entfernt", color: "success" })
|
||||
emit("saved", null)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: "Nebenstelle konnte nicht entfernt werden",
|
||||
description: error?.data?.error || error?.message,
|
||||
color: "error"
|
||||
})
|
||||
} finally {
|
||||
deleting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => [props.targetType, props.targetId], loadExtension, { immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h3 class="text-base font-semibold text-highlighted">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-muted">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
<UBadge :color="statusColor" variant="soft">
|
||||
{{ statusLabel }}
|
||||
</UBadge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<UAlert
|
||||
v-if="!canUseExtension"
|
||||
color="warning"
|
||||
icon="i-heroicons-exclamation-triangle"
|
||||
title="Noch nicht verfügbar"
|
||||
description="Speichere den Datensatz zuerst oder verknüpfe einen Benutzer, bevor eine Nebenstelle vergeben wird."
|
||||
/>
|
||||
|
||||
<div v-else class="grid gap-4 md:grid-cols-[1fr_auto] md:items-end">
|
||||
<div class="grid gap-4 sm:grid-cols-[1fr_auto] sm:items-end">
|
||||
<UFormField label="Nebenstelle">
|
||||
<UInput
|
||||
v-model="extension"
|
||||
inputmode="tel"
|
||||
placeholder="z. B. 1001"
|
||||
:loading="loading"
|
||||
/>
|
||||
</UFormField>
|
||||
<UFormField label="Aktiv">
|
||||
<USwitch v-model="enabled" />
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-2 md:justify-end">
|
||||
<UButton
|
||||
icon="i-heroicons-check"
|
||||
:loading="saving"
|
||||
:disabled="!extension"
|
||||
@click="saveExtension"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
<UButton
|
||||
v-if="existingId"
|
||||
icon="i-heroicons-trash"
|
||||
color="error"
|
||||
variant="soft"
|
||||
:loading="deleting"
|
||||
@click="deleteExtension"
|
||||
>
|
||||
Entfernen
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
Reference in New Issue
Block a user