Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
dtd
/
civitas.ui
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit d2ba5fbc
authored
Apr 16, 2025
by
Samuel Taniel Mulyadi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix Absen
1 parent
cb4ae055
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
101 additions
and
85 deletions
components/beranda/UserLog.vue
components/beranda/UserLog.vue
View file @
d2ba5fb
<
script
setup
lang=
"ts"
>
import
{
useKeycloakStore
}
from
"@/@core/stores/keycloakStore"
;
import
{
onMounted
,
ref
,
watchEffect
}
from
"vue"
;
import
{
onMounted
,
ref
,
watchEffect
}
from
'vue'
import
{
useKeycloakStore
}
from
'@/@core/stores/keycloakStore'
// Store Keycloak
const
keycloakStore
=
useKeycloakStore
()
;
const
keycloakStore
=
useKeycloakStore
()
// Data dan state
const
items
=
ref
<
any
[]
>
([])
;
const
loading
=
ref
(
false
)
;
const
searchQuery
=
ref
(
""
);
const
items
=
ref
<
any
[]
>
([])
const
loading
=
ref
(
false
)
const
searchQuery
=
ref
(
''
)
// Fungsi ambil tanggal dari shift_start atau shift_end
const
getTanggal
=
(
waktu
:
string
)
=>
(
waktu
?
waktu
.
split
(
" "
)[
0
]
:
"-"
);
const
getTanggal
=
(
waktu
:
string
)
=>
(
waktu
?
waktu
.
split
(
' '
)[
0
]
:
'-'
)
// Fungsi ambil jam dari start_time atau end_time, kasih "-" kalau kosong
const
getJam
=
(
waktu
:
string
)
=>
(
waktu
?
waktu
.
split
(
" "
)[
1
].
slice
(
0
,
5
)
:
"-"
);
const
getJam
=
(
waktu
:
string
)
=>
{
if
(
!
waktu
)
return
'-'
return
waktu
.
length
>=
5
?
waktu
.
slice
(
0
,
5
)
:
waktu
}
// Fungsi ambil nama hari dari tanggal
const
getNamaHari
=
(
tanggal
:
string
)
=>
{
if
(
!
tanggal
||
tanggal
===
"-"
)
return
"-"
;
const
date
=
new
Date
(
tanggal
);
if
(
isNaN
(
date
.
getTime
()))
return
"-"
;
return
new
Intl
.
DateTimeFormat
(
"id-ID"
,
{
weekday
:
"long"
}).
format
(
date
);
};
if
(
!
tanggal
||
tanggal
===
'-'
)
return
'-'
const
date
=
new
Date
(
tanggal
)
if
(
isNaN
(
date
.
getTime
()))
return
'-'
return
new
Intl
.
DateTimeFormat
(
'id-ID'
,
{
weekday
:
'long'
}).
format
(
date
)
}
const
getJadwalShift
=
(
start
:
string
,
end
:
string
)
=>
{
const
jamStart
=
start
?
start
.
split
(
" "
)[
1
].
slice
(
0
,
5
)
:
"-"
;
const
jamEnd
=
end
?
end
.
split
(
" "
)[
1
].
slice
(
0
,
5
)
:
"-"
;
return
`
${
jamStart
}
-
${
jamEnd
}
`
;
};
const
jamStart
=
start
&&
start
.
length
>=
5
?
start
.
slice
(
0
,
5
)
:
'-'
const
jamEnd
=
end
&&
end
.
length
>=
5
?
end
.
slice
(
0
,
5
)
:
'-'
return
`
${
jamStart
}
-
${
jamEnd
}
`
}
const
getStatus
=
(
start
:
string
|
undefined
,
end
:
string
|
undefined
)
=>
{
if
(
!
start
&&
!
end
)
return
"Tidak Ada"
;
if
(
!
start
||
!
end
)
return
"Belum Hitung"
;
return
"On Time"
;
};
if
(
!
start
&&
!
end
)
return
'Tidak Ada'
if
(
!
start
||
!
end
)
return
'Belum Hitung'
return
'On Time'
}
// Header tabel
const
logHeaders
=
[
{
title
:
"TANGGAL"
,
key
:
"tanggal"
},
{
title
:
"NAMA HARI"
,
key
:
"namaHari"
},
{
title
:
"SHIFT"
,
key
:
"shift"
},
{
title
:
"JADWAL SHIFT"
,
key
:
"jadwalShift"
},
{
title
:
"MULAI AKTUAL"
,
key
:
"start_time"
},
{
title
:
"SELESAI AKTUAL"
,
key
:
"end_time"
},
{
title
:
"STATUS"
,
key
:
"status"
},
]
;
{
title
:
'TANGGAL'
,
key
:
'tanggal'
},
{
title
:
'NAMA HARI'
,
key
:
'namaHari'
},
{
title
:
'SHIFT'
,
key
:
'shift'
},
{
title
:
'JADWAL SHIFT'
,
key
:
'jadwalShift'
},
{
title
:
'MULAI AKTUAL'
,
key
:
'start_time'
},
{
title
:
'SELESAI AKTUAL'
,
key
:
'end_time'
},
{
title
:
'STATUS'
,
key
:
'status'
},
]
// Fungsi ambil data dari API
async
function
getData
()
{
loading
.
value
=
true
;
items
.
value
=
[]
;
loading
.
value
=
true
items
.
value
=
[]
try
{
const
apiEndpoint
=
"https://api.ui.ac.id/my/hr/attendance"
;
const
apiEndpoint
=
'https://api.ui.ac.id/my/hr/attendance'
const
response
=
await
fetch
(
apiEndpoint
,
{
headers
:
{
Authorization
:
`Bearer
${
keycloakStore
.
accessToken
}
`
,
},
})
;
})
if
(
!
response
.
ok
)
throw
new
Error
(
"Gagal mengambil data"
);
const
dataku
=
await
response
.
json
();
if
(
!
response
.
ok
)
throw
new
Error
(
'Gagal mengambil data'
)
const
dataku
=
await
response
.
json
()
// Tambahkan properti tanggal, namaHari, mulai aktual, dan selesai aktual ke setiap item
items
.
value
=
dataku
.
map
((
item
:
any
)
=>
{
const
tanggal
=
getTanggal
(
item
.
shift_start
)
||
getTanggal
(
item
.
shift_end
);
const
tanggal
=
getTanggal
(
item
.
shift_start
)
||
getTanggal
(
item
.
shift_end
)
return
{
...
item
,
tanggal
:
tanggal
,
tanggal
,
namaHari
:
getNamaHari
(
tanggal
),
jadwalShift
:
getJadwalShift
(
item
.
shift_start
,
item
.
shift_end
),
start_time
:
getJam
(
item
.
start_time
),
end_time
:
getJam
(
item
.
end_time
),
status
:
getStatus
(
item
.
start_time
,
item
.
end_time
),
};
});
}
catch
(
err
)
{
console
.
error
(
"Gagal mengambil data:"
,
err
);
}
finally
{
loading
.
value
=
false
;
}
})
}
catch
(
err
)
{
console
.
error
(
'Gagal mengambil data:'
,
err
)
}
finally
{
loading
.
value
=
false
}
}
// Fetch data saat mounted
onMounted
(()
=>
{
keycloakStore
.
refresh
()
;
getData
()
;
})
;
keycloakStore
.
refresh
()
getData
()
})
// Auto refresh data saat token berubah
watchEffect
(
async
()
=>
{
if
(
!
keycloakStore
.
accessToken
)
return
;
await
getData
();
});
if
(
!
keycloakStore
.
accessToken
)
return
await
getData
()
})
const
filteredItems
=
computed
(()
=>
{
if
(
!
searchQuery
.
value
)
return
items
.
value
;
if
(
!
searchQuery
.
value
)
return
items
.
value
const
query
=
searchQuery
.
value
.
toLowerCase
()
;
const
query
=
searchQuery
.
value
.
toLowerCase
()
return
items
.
value
.
filter
(
(
item
)
=>
return
items
.
value
.
filter
(
item
=>
logHeaders
.
some
(
(
header
)
=>
item
[
header
.
key
]
&&
String
(
item
[
header
.
key
]).
toLowerCase
().
includes
(
query
)
)
);
});
header
=>
item
[
header
.
key
]
&&
String
(
item
[
header
.
key
]).
toLowerCase
().
includes
(
query
),
),
)
})
</
script
>
<
template
>
<VCard
title=
"Log Absen"
class=
"recentnamaHariCard"
>
<VCard
title=
"Log Absen"
class=
"recentnamaHariCard"
>
<div
class=
"search-container mb-4 pl-2 pr-2"
>
<VTextField
v-model=
"searchQuery"
...
...
@@ -133,32 +154,27 @@ const filteredItems = computed(() => {
:sort-by=
"['tanggal']"
:sort-asc=
"[true]"
>
<template
#
item
.
namaHari=
"
{ item }">
<VChip
:color=
"item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'"
:class=
"`text-$
{item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'}`"
size="small"
class="font-weight-medium"
>
{{
item
.
namaHari
}}
</VChip>
</
template
>
<
template
#
item
.
status=
"{ item }"
>
<VChip
:color=
"item.status === 'Tidak Ada' ? 'error' : 'primary'"
:class=
"`text-$
{item.status === 'Tidak Ada' ? 'error' : 'primary'}`"
size="small"
class="font-weight-medium"
>
{{
item
.
status
}}
</VChip>
</
template
>
</VDataTable>
<template
#
item
.
namaHari=
"
{ item }">
<VChip
:color=
"item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'"
:class=
"`text-$
{item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'}`"
size="small"
class="font-weight-medium"
>
{{
item
.
namaHari
}}
</VChip>
</
template
>
<
template
#
item
.
status=
"{ item }"
>
<VChip
:color=
"item.status === 'Tidak Ada' ? 'error' : 'primary'"
:class=
"`text-$
{item.status === 'Tidak Ada' ? 'error' : 'primary'}`"
size="small"
class="font-weight-medium"
>
{{
item
.
status
}}
</VChip>
</
template
>
</VDataTable>
</VCard>
</template>
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment