get ticket from api
This commit is contained in:
@@ -11,7 +11,7 @@ import AppSidebar from '@/components/AppSidebar.vue'
|
|||||||
<div class="wrapper d-flex flex-column min-vh-100">
|
<div class="wrapper d-flex flex-column min-vh-100">
|
||||||
<AppHeader />
|
<AppHeader />
|
||||||
<div class="body flex-grow-1">
|
<div class="body flex-grow-1">
|
||||||
<CContainer class="px-4" lg>
|
<CContainer class="px-4" fluid>
|
||||||
<router-view />
|
<router-view />
|
||||||
</CContainer>
|
</CContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ export const useTicketStore = defineStore('ticket', () => {
|
|||||||
const approvedTickets = ref([])
|
const approvedTickets = ref([])
|
||||||
const rejectedTickets = ref([])
|
const rejectedTickets = ref([])
|
||||||
|
|
||||||
|
function setTickets(data) {
|
||||||
|
tickets.value = data
|
||||||
|
}
|
||||||
|
|
||||||
function addTicket(ticket) {
|
function addTicket(ticket) {
|
||||||
tickets.value.push({ ...ticket })
|
tickets.value.push({ ...ticket })
|
||||||
}
|
}
|
||||||
@@ -101,5 +105,5 @@ export const useTicketStore = defineStore('ticket', () => {
|
|||||||
tickets.value[index].status = 'Rejected'
|
tickets.value[index].status = 'Rejected'
|
||||||
}
|
}
|
||||||
|
|
||||||
return { tickets, addTicket, updateTicket, deleteTicket, approveTicket, rejectTicket }
|
return { tickets, setTickets, addTicket, updateTicket, deleteTicket, approveTicket, rejectTicket }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,55 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { useTicketStore } from '@/stores/ticket.js'
|
import { useTicketStore } from '@/stores/ticket.js'
|
||||||
|
|
||||||
const store = useTicketStore()
|
const store = useTicketStore()
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
function capitalize(str) {
|
||||||
|
if (!str) return ''
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = 'Bearer uZ1vM4UON3CsDV9niGD1gLS4sHpCxT9nzadkITmc6caf2ea2'
|
||||||
|
|
||||||
|
async function fetchTickets() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await fetch('https://api.radiq.my.id/api/tickets', {
|
||||||
|
headers: { Authorization: token },
|
||||||
|
})
|
||||||
|
const json = await res.json()
|
||||||
|
const mapped = (json.data?.data || []).map((item) => ({
|
||||||
|
ticket_no: item.ticket_no,
|
||||||
|
tenant_id: item.tenant_id,
|
||||||
|
customer_id: item.customer_id,
|
||||||
|
deskripsi: item.description,
|
||||||
|
kode_tiket: item.title,
|
||||||
|
status: capitalize(item.status),
|
||||||
|
prioritas: capitalize(item.priority),
|
||||||
|
sla_minutes: item.sla_minutes,
|
||||||
|
ditugaskan_untuk: '',
|
||||||
|
created_by: item.created_by,
|
||||||
|
approved_by: item.approved_by || '',
|
||||||
|
approved_at: item.approved_at || '',
|
||||||
|
rejected_by: item.rejected_by || '',
|
||||||
|
rejected_at: item.rejected_at || '',
|
||||||
|
rejection_reason: item.rejection_reason || '',
|
||||||
|
assigned_at: item.assigned_at || '',
|
||||||
|
resolved_at: item.resolved_at || '',
|
||||||
|
closed_at: item.closed_at || '',
|
||||||
|
created_at: item.created_at || '',
|
||||||
|
updated_at: item.updated_at || '',
|
||||||
|
}))
|
||||||
|
store.setTickets(mapped)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to fetch tickets:', err)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(fetchTickets)
|
||||||
|
|
||||||
const ticketModal = ref(false)
|
const ticketModal = ref(false)
|
||||||
const detailModal = ref(false)
|
const detailModal = ref(false)
|
||||||
@@ -82,13 +129,43 @@ function openDetail(item) {
|
|||||||
detailModal.value = true
|
detailModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveTicket() {
|
async function saveTicket() {
|
||||||
|
const body = {
|
||||||
|
ticket_no: form.ticket_no,
|
||||||
|
tenant_id: form.tenant_id,
|
||||||
|
customer_id: form.customer_id,
|
||||||
|
title: form.kode_tiket,
|
||||||
|
description: form.deskripsi,
|
||||||
|
priority: form.prioritas?.toLowerCase(),
|
||||||
|
status: form.status?.toLowerCase(),
|
||||||
|
sla_minutes: form.sla_minutes,
|
||||||
|
}
|
||||||
|
try {
|
||||||
if (isEdit.value && editingIndex.value >= 0) {
|
if (isEdit.value && editingIndex.value >= 0) {
|
||||||
store.updateTicket(editingIndex.value, form)
|
const res = await fetch(
|
||||||
|
`https://api.radiq.my.id/api/tickets/${form.ticket_no}`,
|
||||||
|
{
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { Authorization: token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (res.ok) store.updateTicket(editingIndex.value, form)
|
||||||
} else {
|
} else {
|
||||||
store.addTicket(form)
|
const res = await fetch('https://api.radiq.my.id/api/tickets', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
|
const json = await res.json()
|
||||||
|
store.addTicket(json.data || form)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ticketModal.value = false
|
ticketModal.value = false
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Save ticket failed:', err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteTicket(index) {
|
function deleteTicket(index) {
|
||||||
@@ -101,11 +178,25 @@ function openApproveModal(index) {
|
|||||||
approveModal.value = true
|
approveModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmApprove() {
|
async function confirmApprove() {
|
||||||
if (approverName.value.trim()) {
|
if (!approverName.value.trim()) return
|
||||||
|
const ticket = store.tickets[approveIndex.value]
|
||||||
|
try {
|
||||||
|
const res = await fetch(`https://api.radiq.my.id/api/tickets/${ticket.ticket_no}/approve`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: {
|
||||||
|
Authorization: token,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ approved_by: approverName.value.trim() }),
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
store.approveTicket(approveIndex.value, approverName.value.trim())
|
store.approveTicket(approveIndex.value, approverName.value.trim())
|
||||||
approveModal.value = false
|
approveModal.value = false
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Approve failed:', err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRejectModal(index) {
|
function openRejectModal(index) {
|
||||||
@@ -147,9 +238,7 @@ function isPending(item) {
|
|||||||
<CTableRow>
|
<CTableRow>
|
||||||
<CTableHeaderCell scope="col">No</CTableHeaderCell>
|
<CTableHeaderCell scope="col">No</CTableHeaderCell>
|
||||||
<CTableHeaderCell scope="col" class="text-center">Ticket No</CTableHeaderCell>
|
<CTableHeaderCell scope="col" class="text-center">Ticket No</CTableHeaderCell>
|
||||||
<CTableHeaderCell scope="col" class="text-center w-25"
|
<CTableHeaderCell scope="col" class="text-center w-25">Title</CTableHeaderCell>
|
||||||
>Kode Tiket</CTableHeaderCell
|
|
||||||
>
|
|
||||||
<CTableHeaderCell scope="col">Deskripsi</CTableHeaderCell>
|
<CTableHeaderCell scope="col">Deskripsi</CTableHeaderCell>
|
||||||
<CTableHeaderCell scope="col">Status</CTableHeaderCell>
|
<CTableHeaderCell scope="col">Status</CTableHeaderCell>
|
||||||
<CTableHeaderCell scope="col">Prioritas</CTableHeaderCell>
|
<CTableHeaderCell scope="col">Prioritas</CTableHeaderCell>
|
||||||
|
|||||||
Reference in New Issue
Block a user