index.vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <!--suppress JSValidateTypes -->
  2. <template>
  3. <div>
  4. <DataTable
  5. :value="users"
  6. datakey="id"
  7. :loading="isPending"
  8. scrollable
  9. :scrollHeight="`calc(100vh - ${elementHeights}px)`"
  10. selectionMode="single"
  11. :pt="{
  12. header: { id: 'datatable_header' },
  13. footer: { id: 'datatable_footer' },
  14. tbody: 'text-base'
  15. }"
  16. @rowSelect="showUserEdit"
  17. >
  18. <Column
  19. v-for="column of columns"
  20. :key="column"
  21. :field="column"
  22. :header="_upperCase(column)"
  23. >
  24. <template #body="slotProps">
  25. <template v-if="_isDate(slotProps.data?.[column])">
  26. {{ toNumericDate(slotProps.data?.[column]) }}
  27. </template>
  28. <template v-else>
  29. {{ slotProps.data?.[column] }}
  30. </template>
  31. </template>
  32. </Column>
  33. <template #loading>
  34. <SpinnerModal
  35. :visible="true"
  36. maskClass="bg-surface!"
  37. />
  38. </template>
  39. <template #footer>
  40. <UserToolbar
  41. :class="isPending && 'hidden'"
  42. :count="count"
  43. />
  44. </template>
  45. </DataTable>
  46. </div>
  47. </template>
  48. <script setup>
  49. definePageMeta({
  50. name: "admin:users",
  51. middleware: ["signed-in", "admin"]
  52. })
  53. const { data: users, isPending } = useQuery(userListQuery)
  54. const columns = ["email", "name", "username", "role", "createdAt"]
  55. const count = computed(() => users?.value ? users.value.length : 0)
  56. const DEFAULT_ELEMENT_HEIGHTS = 109
  57. const elementHeights = ref(DEFAULT_ELEMENT_HEIGHTS)
  58. onMounted(() => updateElementHeights())
  59. onUpdated(() => updateElementHeights())
  60. function toNumericDate(date) {
  61. return new Intl.DateTimeFormat(undefined, {
  62. year: "numeric",
  63. month: "numeric",
  64. day: "numeric",
  65. hour: "numeric",
  66. minute: "numeric"
  67. }).format(date)
  68. }
  69. async function showUserEdit({ data: { id: userId } }) {
  70. await navigateTo({ name: 'admin:userEdit', params: { userId } })
  71. }
  72. function updateElementHeights() {
  73. elementHeights.value = totalElementHeights()
  74. }
  75. function totalElementHeights() {
  76. // total height of non-datatable elements (in pixels)
  77. const elements = ["navbar", "datatable_footer"]
  78. // noinspection JSUnresolvedReference
  79. let totalHeights = _reduce(
  80. elements,
  81. (acc, element) => acc + document?.getElementById(element)?.offsetHeight,
  82. 0
  83. )
  84. // plus 16px [--spacing(4)] navbar bottom margin
  85. totalHeights += 16
  86. return _isNaN(totalHeights) ? DEFAULT_ELEMENT_HEIGHTS : totalHeights
  87. }
  88. </script>
  89. <style scoped></style>