@escalated-dev/escalated 0.7.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +380 -357
- package/package.json +85 -81
- package/src/components/ActiveChatsPanel.vue +246 -246
- package/src/components/AdminDashboard.stories.js +1423 -1423
- package/src/components/AttachmentList.vue +65 -65
- package/src/components/ChatActionBar.vue +226 -226
- package/src/components/ChatBubble.vue +162 -162
- package/src/components/ChatComposer.vue +308 -308
- package/src/components/ChatQueue.vue +222 -222
- package/src/components/ChatThread.vue +197 -197
- package/src/components/CustomTicketActions.stories.js +71 -0
- package/src/components/CustomTicketActions.vue +101 -0
- package/src/components/EscalatedLayout.vue +619 -598
- package/src/components/FollowButton.vue +20 -1
- package/src/components/MentionDropdown.vue +154 -154
- package/src/components/MetricComparison.vue +89 -89
- package/src/components/PercentileChart.vue +67 -67
- package/src/components/PeriodSelector.vue +98 -98
- package/src/components/PresenceIndicator.vue +228 -213
- package/src/components/ReplyComposer.vue +336 -336
- package/src/components/ReplyThread.vue +153 -153
- package/src/components/ReportChart.vue +395 -395
- package/src/components/ReportExportButton.vue +108 -108
- package/src/components/SaveViewDialog.vue +172 -172
- package/src/components/SavedViewSidebar.vue +208 -208
- package/src/components/SkillTagManager.vue +29 -22
- package/src/components/SnoozeButton.vue +247 -247
- package/src/components/TicketFilters.vue +270 -270
- package/src/components/TicketList.vue +655 -655
- package/src/components/TicketSidebar.vue +4 -0
- package/src/components/TicketSplitDialog.vue +98 -98
- package/src/components/TicketSubjects.stories.js +63 -0
- package/src/components/TicketSubjects.vue +107 -0
- package/src/components/TwoFactorSetup.vue +1 -37
- package/src/components/VariableTokenInput.vue +111 -111
- package/src/components/WorkflowActionConfig.vue +287 -287
- package/src/components/WorkflowActionList.vue +350 -350
- package/src/components/WorkflowConditionBuilder.vue +265 -265
- package/src/components/WorkflowTriggerSelector.vue +125 -125
- package/src/components/admin/newsletters/AnalyticsTiles.stories.js +14 -0
- package/src/components/admin/newsletters/AnalyticsTiles.vue +55 -0
- package/src/components/admin/newsletters/DeliveriesTable.stories.js +28 -0
- package/src/components/admin/newsletters/DeliveriesTable.vue +104 -0
- package/src/components/admin/newsletters/DynamicFilterBuilder.stories.js +11 -0
- package/src/components/admin/newsletters/DynamicFilterBuilder.vue +53 -0
- package/src/components/admin/newsletters/ListMemberTable.stories.js +12 -0
- package/src/components/admin/newsletters/ListMemberTable.vue +53 -0
- package/src/components/admin/newsletters/MarkdownEditor.stories.js +6 -0
- package/src/components/admin/newsletters/MarkdownEditor.vue +53 -0
- package/src/components/admin/newsletters/MergeFieldDropdown.stories.js +6 -0
- package/src/components/admin/newsletters/MergeFieldDropdown.vue +84 -0
- package/src/components/admin/newsletters/PreviewIframe.stories.js +7 -0
- package/src/components/admin/newsletters/PreviewIframe.vue +40 -0
- package/src/components/admin/newsletters/SummaryTiles.stories.js +8 -0
- package/src/components/admin/newsletters/SummaryTiles.vue +63 -0
- package/src/composables/useChat.js +187 -187
- package/src/composables/useI18n.js +30 -8
- package/src/composables/useMentions.js +134 -134
- package/src/composables/usePermissions.js +31 -0
- package/src/composables/useRealtime.js +182 -182
- package/src/index.js +85 -84
- package/src/locales/README.md +13 -0
- package/src/locales/ar.json +727 -727
- package/src/locales/de.json +690 -690
- package/src/locales/en.json +889 -729
- package/src/locales/es.json +691 -691
- package/src/locales/fr.json +691 -691
- package/src/locales/index.js +16 -16
- package/src/locales/it.json +727 -727
- package/src/locales/ja.json +727 -727
- package/src/locales/ko.json +727 -727
- package/src/locales/nl.json +727 -727
- package/src/locales/pl.json +727 -727
- package/src/locales/pt-BR.json +727 -727
- package/src/locales/ru.json +727 -727
- package/src/locales/tr.json +727 -727
- package/src/locales/zh-CN.json +727 -727
- package/src/pages/Admin/Newsletters/Compose.vue +192 -0
- package/src/pages/Admin/Newsletters/Edit.vue +24 -0
- package/src/pages/Admin/Newsletters/Index.vue +141 -0
- package/src/pages/Admin/Newsletters/Lists/Create.vue +64 -0
- package/src/pages/Admin/Newsletters/Lists/Index.vue +59 -0
- package/src/pages/Admin/Newsletters/Lists/Show.vue +53 -0
- package/src/pages/Admin/Newsletters/Settings.vue +85 -0
- package/src/pages/Admin/Newsletters/Show.vue +140 -0
- package/src/pages/Admin/Newsletters/Templates/Create.vue +11 -0
- package/src/pages/Admin/Newsletters/Templates/Index.vue +54 -0
- package/src/pages/Admin/Newsletters/Templates/Show.vue +65 -0
- package/src/pages/Admin/Newsletters/usePreview.js +44 -0
- package/src/pages/Admin/Reports/AgentDetail.vue +132 -132
- package/src/pages/Admin/Reports/AgentRanking.vue +246 -246
- package/src/pages/Admin/Reports/Cohorts.vue +180 -180
- package/src/pages/Admin/Reports/Comparison.vue +141 -141
- package/src/pages/Admin/Reports/Dashboard.vue +226 -226
- package/src/pages/Admin/Reports/ResolutionTimes.vue +164 -164
- package/src/pages/Admin/Reports/ResponseTimes.vue +164 -164
- package/src/pages/Admin/Reports/SlaTrends.vue +183 -183
- package/src/pages/Admin/Settings/SsoSettings.vue +157 -4
- package/src/pages/Admin/Settings/TwoFactor.vue +32 -6
- package/src/pages/Admin/Settings.vue +1008 -1008
- package/src/pages/Admin/Skills/Form.vue +164 -4
- package/src/pages/Admin/Skills/Index.vue +14 -3
- package/src/pages/Admin/Tickets/Index.vue +126 -126
- package/src/pages/Admin/Tickets/Show.vue +254 -249
- package/src/pages/Admin/Users/Index.vue +145 -0
- package/src/pages/Admin/Workflows/Builder.vue +207 -207
- package/src/pages/Admin/Workflows/Index.vue +235 -235
- package/src/pages/Admin/Workflows/Logs.vue +286 -286
- package/src/pages/Agent/TicketIndex.vue +112 -112
- package/src/pages/Agent/TicketShow.vue +547 -494
- package/src/pages/Customer/Index.vue +26 -1
- package/src/pages/Customer/KnowledgeBase/Article.vue +129 -129
- package/src/plugin.js +175 -175
- package/src/utils/mentionHighlight.js +24 -24
- package/src/widget/EscalatedWidget.vue +804 -804
- package/src/widget/index.js +254 -254
|
@@ -1,226 +1,226 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
3
|
-
import KpiCard from '../../../components/KpiCard.vue';
|
|
4
|
-
import ChartWidget from '../../../components/ChartWidget.vue';
|
|
5
|
-
import PeriodSelector from '../../../components/PeriodSelector.vue';
|
|
6
|
-
import ReportExportButton from '../../../components/ReportExportButton.vue';
|
|
7
|
-
import { router, Link } from '@inertiajs/vue3';
|
|
8
|
-
import { ref } from 'vue';
|
|
9
|
-
|
|
10
|
-
defineProps({
|
|
11
|
-
period_days: Number,
|
|
12
|
-
volume: Array,
|
|
13
|
-
by_status: Array,
|
|
14
|
-
by_priority: Array,
|
|
15
|
-
avg_response_hours: Number,
|
|
16
|
-
avg_resolution_hours: Number,
|
|
17
|
-
sla_compliance: Number,
|
|
18
|
-
csat_average: Number,
|
|
19
|
-
agent_performance: Array,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const activeTab = ref('overview');
|
|
23
|
-
|
|
24
|
-
const tabs = [
|
|
25
|
-
{ key: 'overview', label: 'Overview' },
|
|
26
|
-
{ key: 'agents', label: 'Agents' },
|
|
27
|
-
{ key: 'sla', label: 'SLA' },
|
|
28
|
-
{ key: 'csat', label: 'CSAT' },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const advancedReports = [
|
|
32
|
-
{ label: 'SLA Trends', route: 'escalated.admin.reports.sla-trends' },
|
|
33
|
-
{ label: 'Response Times', route: 'escalated.admin.reports.response-times' },
|
|
34
|
-
{ label: 'Resolution Times', route: 'escalated.admin.reports.resolution-times' },
|
|
35
|
-
{ label: 'Agent Rankings', route: 'escalated.admin.reports.agent-ranking' },
|
|
36
|
-
{ label: 'Cohorts', route: 'escalated.admin.reports.cohorts' },
|
|
37
|
-
{ label: 'Comparison', route: 'escalated.admin.reports.comparison' },
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
function changePeriod(days) {
|
|
41
|
-
router.get(route('escalated.admin.reports.dashboard'), { days }, { preserveState: true });
|
|
42
|
-
}
|
|
43
|
-
</script>
|
|
44
|
-
|
|
45
|
-
<template>
|
|
46
|
-
<EscalatedLayout title="Reports Dashboard">
|
|
47
|
-
<!-- Period selector & export -->
|
|
48
|
-
<div class="mb-6 flex items-center justify-between">
|
|
49
|
-
<PeriodSelector :model-value="period_days" @update:model-value="changePeriod" />
|
|
50
|
-
<div class="flex items-center gap-3">
|
|
51
|
-
<ReportExportButton report-name="dashboard" :period-days="period_days" />
|
|
52
|
-
<Link
|
|
53
|
-
:href="route('escalated.admin.reports')"
|
|
54
|
-
class="text-sm text-[var(--esc-panel-text-muted)] hover:text-[var(--esc-panel-text-secondary)]"
|
|
55
|
-
>
|
|
56
|
-
Classic View
|
|
57
|
-
</Link>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<!-- Tabs -->
|
|
62
|
-
<div class="mb-6 flex gap-1 rounded-lg border border-[var(--esc-panel-border)] bg-[var(--esc-panel-hover)] p-1">
|
|
63
|
-
<button
|
|
64
|
-
v-for="tab in tabs"
|
|
65
|
-
:key="tab.key"
|
|
66
|
-
:class="[
|
|
67
|
-
'rounded-md px-4 py-2 text-sm font-medium transition-all',
|
|
68
|
-
activeTab === tab.key
|
|
69
|
-
? 'bg-[var(--esc-panel-active)] text-[var(--esc-panel-text)]'
|
|
70
|
-
: 'text-[var(--esc-panel-text-muted)] hover:text-[var(--esc-panel-text-secondary)]',
|
|
71
|
-
]"
|
|
72
|
-
@click="activeTab = tab.key"
|
|
73
|
-
>
|
|
74
|
-
{{ tab.label }}
|
|
75
|
-
</button>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<!-- Overview Tab -->
|
|
79
|
-
<div v-if="activeTab === 'overview'">
|
|
80
|
-
<!-- KPI Cards -->
|
|
81
|
-
<div class="mb-6 grid grid-cols-2 gap-4 md:grid-cols-4">
|
|
82
|
-
<KpiCard
|
|
83
|
-
label="Avg Response Time"
|
|
84
|
-
:value="`${avg_response_hours}h`"
|
|
85
|
-
:icon="'M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z'"
|
|
86
|
-
/>
|
|
87
|
-
<KpiCard
|
|
88
|
-
label="Avg Resolution Time"
|
|
89
|
-
:value="`${avg_resolution_hours}h`"
|
|
90
|
-
:icon="'M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z'"
|
|
91
|
-
/>
|
|
92
|
-
<KpiCard
|
|
93
|
-
label="SLA Compliance"
|
|
94
|
-
:value="`${sla_compliance}%`"
|
|
95
|
-
:icon="'M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z'"
|
|
96
|
-
/>
|
|
97
|
-
<KpiCard
|
|
98
|
-
label="CSAT Average"
|
|
99
|
-
:value="csat_average || '—'"
|
|
100
|
-
:icon="'M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z'"
|
|
101
|
-
/>
|
|
102
|
-
</div>
|
|
103
|
-
|
|
104
|
-
<!-- Charts -->
|
|
105
|
-
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
106
|
-
<ChartWidget title="Ticket Volume" :data="volume" color="cyan" />
|
|
107
|
-
<ChartWidget title="By Status" :data="by_status" color="violet" />
|
|
108
|
-
<ChartWidget title="By Priority" :data="by_priority" color="amber" />
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<!-- Agents Tab -->
|
|
113
|
-
<div v-if="activeTab === 'agents'">
|
|
114
|
-
<div class="mb-4 text-right">
|
|
115
|
-
<Link
|
|
116
|
-
:href="route('escalated.admin.reports.agents', { days: period_days })"
|
|
117
|
-
class="text-sm text-[var(--esc-panel-accent)] hover:text-[var(--esc-panel-accent)]"
|
|
118
|
-
>
|
|
119
|
-
Full Agent Report →
|
|
120
|
-
</Link>
|
|
121
|
-
</div>
|
|
122
|
-
<div class="overflow-hidden rounded-xl border border-[var(--esc-panel-border)]">
|
|
123
|
-
<table class="w-full">
|
|
124
|
-
<thead>
|
|
125
|
-
<tr class="border-b border-[var(--esc-panel-border)] bg-[var(--esc-panel-hover)]">
|
|
126
|
-
<th
|
|
127
|
-
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
128
|
-
>
|
|
129
|
-
Agent
|
|
130
|
-
</th>
|
|
131
|
-
<th
|
|
132
|
-
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
133
|
-
>
|
|
134
|
-
Tickets
|
|
135
|
-
</th>
|
|
136
|
-
<th
|
|
137
|
-
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
138
|
-
>
|
|
139
|
-
Resolved
|
|
140
|
-
</th>
|
|
141
|
-
<th
|
|
142
|
-
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
143
|
-
>
|
|
144
|
-
Avg Response
|
|
145
|
-
</th>
|
|
146
|
-
<th
|
|
147
|
-
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
148
|
-
>
|
|
149
|
-
Avg Resolution
|
|
150
|
-
</th>
|
|
151
|
-
</tr>
|
|
152
|
-
</thead>
|
|
153
|
-
<tbody class="divide-y divide-[var(--esc-panel-border)]">
|
|
154
|
-
<tr
|
|
155
|
-
v-for="agent in agent_performance"
|
|
156
|
-
:key="agent.agent_id"
|
|
157
|
-
class="hover:bg-[var(--esc-panel-hover)]"
|
|
158
|
-
>
|
|
159
|
-
<td class="px-4 py-3 text-sm font-medium text-[var(--esc-panel-text-secondary)]">
|
|
160
|
-
{{ agent.agent_name }}
|
|
161
|
-
</td>
|
|
162
|
-
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
163
|
-
{{ agent.total_tickets }}
|
|
164
|
-
</td>
|
|
165
|
-
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
166
|
-
{{ agent.resolved_tickets }}
|
|
167
|
-
</td>
|
|
168
|
-
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
169
|
-
{{ agent.avg_response_hours ?? '—' }}h
|
|
170
|
-
</td>
|
|
171
|
-
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
172
|
-
{{ agent.avg_resolution_hours ?? '—' }}h
|
|
173
|
-
</td>
|
|
174
|
-
</tr>
|
|
175
|
-
<tr v-if="!agent_performance?.length">
|
|
176
|
-
<td colspan="5" class="px-4 py-8 text-center text-sm text-[var(--esc-panel-text-muted)]">
|
|
177
|
-
No agent data for this period.
|
|
178
|
-
</td>
|
|
179
|
-
</tr>
|
|
180
|
-
</tbody>
|
|
181
|
-
</table>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
<!-- SLA Tab -->
|
|
186
|
-
<div v-if="activeTab === 'sla'">
|
|
187
|
-
<div class="mb-4 flex items-center justify-between">
|
|
188
|
-
<KpiCard label="Overall SLA Compliance" :value="`${sla_compliance}%`" />
|
|
189
|
-
<Link
|
|
190
|
-
:href="route('escalated.admin.reports.sla', { days: period_days })"
|
|
191
|
-
class="text-sm text-[var(--esc-panel-accent)] hover:text-[var(--esc-panel-accent)]"
|
|
192
|
-
>
|
|
193
|
-
Full SLA Report →
|
|
194
|
-
</Link>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
<!-- CSAT Tab -->
|
|
199
|
-
<div v-if="activeTab === 'csat'">
|
|
200
|
-
<div class="mb-4 flex items-center justify-between">
|
|
201
|
-
<KpiCard label="Average CSAT" :value="csat_average || '—'" />
|
|
202
|
-
<Link
|
|
203
|
-
:href="route('escalated.admin.reports.csat', { days: period_days })"
|
|
204
|
-
class="text-sm text-[var(--esc-panel-accent)] hover:text-[var(--esc-panel-accent)]"
|
|
205
|
-
>
|
|
206
|
-
Full CSAT Report →
|
|
207
|
-
</Link>
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
|
-
<!-- Advanced Reports Navigation -->
|
|
212
|
-
<div class="mt-8 rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-5">
|
|
213
|
-
<h3 class="mb-4 text-sm font-semibold text-[var(--esc-panel-text-secondary)]">Advanced Reports</h3>
|
|
214
|
-
<div class="grid grid-cols-2 gap-3 md:grid-cols-3 lg:grid-cols-6">
|
|
215
|
-
<Link
|
|
216
|
-
v-for="report in advancedReports"
|
|
217
|
-
:key="report.route"
|
|
218
|
-
:href="route(report.route, { days: period_days })"
|
|
219
|
-
class="rounded-lg border border-[var(--esc-panel-border)] bg-[var(--esc-panel-hover)] px-4 py-3 text-center text-sm font-medium text-[var(--esc-panel-text-tertiary)] transition-all hover:border-[var(--esc-panel-accent)]/30 hover:text-[var(--esc-panel-text-secondary)]"
|
|
220
|
-
>
|
|
221
|
-
{{ report.label }}
|
|
222
|
-
</Link>
|
|
223
|
-
</div>
|
|
224
|
-
</div>
|
|
225
|
-
</EscalatedLayout>
|
|
226
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import EscalatedLayout from '../../../components/EscalatedLayout.vue';
|
|
3
|
+
import KpiCard from '../../../components/KpiCard.vue';
|
|
4
|
+
import ChartWidget from '../../../components/ChartWidget.vue';
|
|
5
|
+
import PeriodSelector from '../../../components/PeriodSelector.vue';
|
|
6
|
+
import ReportExportButton from '../../../components/ReportExportButton.vue';
|
|
7
|
+
import { router, Link } from '@inertiajs/vue3';
|
|
8
|
+
import { ref } from 'vue';
|
|
9
|
+
|
|
10
|
+
defineProps({
|
|
11
|
+
period_days: Number,
|
|
12
|
+
volume: Array,
|
|
13
|
+
by_status: Array,
|
|
14
|
+
by_priority: Array,
|
|
15
|
+
avg_response_hours: Number,
|
|
16
|
+
avg_resolution_hours: Number,
|
|
17
|
+
sla_compliance: Number,
|
|
18
|
+
csat_average: Number,
|
|
19
|
+
agent_performance: Array,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const activeTab = ref('overview');
|
|
23
|
+
|
|
24
|
+
const tabs = [
|
|
25
|
+
{ key: 'overview', label: 'Overview' },
|
|
26
|
+
{ key: 'agents', label: 'Agents' },
|
|
27
|
+
{ key: 'sla', label: 'SLA' },
|
|
28
|
+
{ key: 'csat', label: 'CSAT' },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const advancedReports = [
|
|
32
|
+
{ label: 'SLA Trends', route: 'escalated.admin.reports.sla-trends' },
|
|
33
|
+
{ label: 'Response Times', route: 'escalated.admin.reports.response-times' },
|
|
34
|
+
{ label: 'Resolution Times', route: 'escalated.admin.reports.resolution-times' },
|
|
35
|
+
{ label: 'Agent Rankings', route: 'escalated.admin.reports.agent-ranking' },
|
|
36
|
+
{ label: 'Cohorts', route: 'escalated.admin.reports.cohorts' },
|
|
37
|
+
{ label: 'Comparison', route: 'escalated.admin.reports.comparison' },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function changePeriod(days) {
|
|
41
|
+
router.get(route('escalated.admin.reports.dashboard'), { days }, { preserveState: true });
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<EscalatedLayout title="Reports Dashboard">
|
|
47
|
+
<!-- Period selector & export -->
|
|
48
|
+
<div class="mb-6 flex items-center justify-between">
|
|
49
|
+
<PeriodSelector :model-value="period_days" @update:model-value="changePeriod" />
|
|
50
|
+
<div class="flex items-center gap-3">
|
|
51
|
+
<ReportExportButton report-name="dashboard" :period-days="period_days" />
|
|
52
|
+
<Link
|
|
53
|
+
:href="route('escalated.admin.reports')"
|
|
54
|
+
class="text-sm text-[var(--esc-panel-text-muted)] hover:text-[var(--esc-panel-text-secondary)]"
|
|
55
|
+
>
|
|
56
|
+
Classic View
|
|
57
|
+
</Link>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Tabs -->
|
|
62
|
+
<div class="mb-6 flex gap-1 rounded-lg border border-[var(--esc-panel-border)] bg-[var(--esc-panel-hover)] p-1">
|
|
63
|
+
<button
|
|
64
|
+
v-for="tab in tabs"
|
|
65
|
+
:key="tab.key"
|
|
66
|
+
:class="[
|
|
67
|
+
'rounded-md px-4 py-2 text-sm font-medium transition-all',
|
|
68
|
+
activeTab === tab.key
|
|
69
|
+
? 'bg-[var(--esc-panel-active)] text-[var(--esc-panel-text)]'
|
|
70
|
+
: 'text-[var(--esc-panel-text-muted)] hover:text-[var(--esc-panel-text-secondary)]',
|
|
71
|
+
]"
|
|
72
|
+
@click="activeTab = tab.key"
|
|
73
|
+
>
|
|
74
|
+
{{ tab.label }}
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<!-- Overview Tab -->
|
|
79
|
+
<div v-if="activeTab === 'overview'">
|
|
80
|
+
<!-- KPI Cards -->
|
|
81
|
+
<div class="mb-6 grid grid-cols-2 gap-4 md:grid-cols-4">
|
|
82
|
+
<KpiCard
|
|
83
|
+
label="Avg Response Time"
|
|
84
|
+
:value="`${avg_response_hours}h`"
|
|
85
|
+
:icon="'M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z'"
|
|
86
|
+
/>
|
|
87
|
+
<KpiCard
|
|
88
|
+
label="Avg Resolution Time"
|
|
89
|
+
:value="`${avg_resolution_hours}h`"
|
|
90
|
+
:icon="'M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z'"
|
|
91
|
+
/>
|
|
92
|
+
<KpiCard
|
|
93
|
+
label="SLA Compliance"
|
|
94
|
+
:value="`${sla_compliance}%`"
|
|
95
|
+
:icon="'M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z'"
|
|
96
|
+
/>
|
|
97
|
+
<KpiCard
|
|
98
|
+
label="CSAT Average"
|
|
99
|
+
:value="csat_average || '—'"
|
|
100
|
+
:icon="'M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z'"
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- Charts -->
|
|
105
|
+
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
106
|
+
<ChartWidget title="Ticket Volume" :data="volume" color="cyan" />
|
|
107
|
+
<ChartWidget title="By Status" :data="by_status" color="violet" />
|
|
108
|
+
<ChartWidget title="By Priority" :data="by_priority" color="amber" />
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Agents Tab -->
|
|
113
|
+
<div v-if="activeTab === 'agents'">
|
|
114
|
+
<div class="mb-4 text-right">
|
|
115
|
+
<Link
|
|
116
|
+
:href="route('escalated.admin.reports.agents', { days: period_days })"
|
|
117
|
+
class="text-sm text-[var(--esc-panel-accent)] hover:text-[var(--esc-panel-accent)]"
|
|
118
|
+
>
|
|
119
|
+
Full Agent Report →
|
|
120
|
+
</Link>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="overflow-hidden rounded-xl border border-[var(--esc-panel-border)]">
|
|
123
|
+
<table class="w-full">
|
|
124
|
+
<thead>
|
|
125
|
+
<tr class="border-b border-[var(--esc-panel-border)] bg-[var(--esc-panel-hover)]">
|
|
126
|
+
<th
|
|
127
|
+
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
128
|
+
>
|
|
129
|
+
Agent
|
|
130
|
+
</th>
|
|
131
|
+
<th
|
|
132
|
+
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
133
|
+
>
|
|
134
|
+
Tickets
|
|
135
|
+
</th>
|
|
136
|
+
<th
|
|
137
|
+
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
138
|
+
>
|
|
139
|
+
Resolved
|
|
140
|
+
</th>
|
|
141
|
+
<th
|
|
142
|
+
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
143
|
+
>
|
|
144
|
+
Avg Response
|
|
145
|
+
</th>
|
|
146
|
+
<th
|
|
147
|
+
class="px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-[var(--esc-panel-text-muted)]"
|
|
148
|
+
>
|
|
149
|
+
Avg Resolution
|
|
150
|
+
</th>
|
|
151
|
+
</tr>
|
|
152
|
+
</thead>
|
|
153
|
+
<tbody class="divide-y divide-[var(--esc-panel-border)]">
|
|
154
|
+
<tr
|
|
155
|
+
v-for="agent in agent_performance"
|
|
156
|
+
:key="agent.agent_id"
|
|
157
|
+
class="hover:bg-[var(--esc-panel-hover)]"
|
|
158
|
+
>
|
|
159
|
+
<td class="px-4 py-3 text-sm font-medium text-[var(--esc-panel-text-secondary)]">
|
|
160
|
+
{{ agent.agent_name }}
|
|
161
|
+
</td>
|
|
162
|
+
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
163
|
+
{{ agent.total_tickets }}
|
|
164
|
+
</td>
|
|
165
|
+
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
166
|
+
{{ agent.resolved_tickets }}
|
|
167
|
+
</td>
|
|
168
|
+
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
169
|
+
{{ agent.avg_response_hours ?? '—' }}h
|
|
170
|
+
</td>
|
|
171
|
+
<td class="px-4 py-3 text-sm text-[var(--esc-panel-text-tertiary)]">
|
|
172
|
+
{{ agent.avg_resolution_hours ?? '—' }}h
|
|
173
|
+
</td>
|
|
174
|
+
</tr>
|
|
175
|
+
<tr v-if="!agent_performance?.length">
|
|
176
|
+
<td colspan="5" class="px-4 py-8 text-center text-sm text-[var(--esc-panel-text-muted)]">
|
|
177
|
+
No agent data for this period.
|
|
178
|
+
</td>
|
|
179
|
+
</tr>
|
|
180
|
+
</tbody>
|
|
181
|
+
</table>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<!-- SLA Tab -->
|
|
186
|
+
<div v-if="activeTab === 'sla'">
|
|
187
|
+
<div class="mb-4 flex items-center justify-between">
|
|
188
|
+
<KpiCard label="Overall SLA Compliance" :value="`${sla_compliance}%`" />
|
|
189
|
+
<Link
|
|
190
|
+
:href="route('escalated.admin.reports.sla', { days: period_days })"
|
|
191
|
+
class="text-sm text-[var(--esc-panel-accent)] hover:text-[var(--esc-panel-accent)]"
|
|
192
|
+
>
|
|
193
|
+
Full SLA Report →
|
|
194
|
+
</Link>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<!-- CSAT Tab -->
|
|
199
|
+
<div v-if="activeTab === 'csat'">
|
|
200
|
+
<div class="mb-4 flex items-center justify-between">
|
|
201
|
+
<KpiCard label="Average CSAT" :value="csat_average || '—'" />
|
|
202
|
+
<Link
|
|
203
|
+
:href="route('escalated.admin.reports.csat', { days: period_days })"
|
|
204
|
+
class="text-sm text-[var(--esc-panel-accent)] hover:text-[var(--esc-panel-accent)]"
|
|
205
|
+
>
|
|
206
|
+
Full CSAT Report →
|
|
207
|
+
</Link>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<!-- Advanced Reports Navigation -->
|
|
212
|
+
<div class="mt-8 rounded-xl border border-[var(--esc-panel-border)] bg-[var(--esc-panel-surface)] p-5">
|
|
213
|
+
<h3 class="mb-4 text-sm font-semibold text-[var(--esc-panel-text-secondary)]">Advanced Reports</h3>
|
|
214
|
+
<div class="grid grid-cols-2 gap-3 md:grid-cols-3 lg:grid-cols-6">
|
|
215
|
+
<Link
|
|
216
|
+
v-for="report in advancedReports"
|
|
217
|
+
:key="report.route"
|
|
218
|
+
:href="route(report.route, { days: period_days })"
|
|
219
|
+
class="rounded-lg border border-[var(--esc-panel-border)] bg-[var(--esc-panel-hover)] px-4 py-3 text-center text-sm font-medium text-[var(--esc-panel-text-tertiary)] transition-all hover:border-[var(--esc-panel-accent)]/30 hover:text-[var(--esc-panel-text-secondary)]"
|
|
220
|
+
>
|
|
221
|
+
{{ report.label }}
|
|
222
|
+
</Link>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</EscalatedLayout>
|
|
226
|
+
</template>
|