Index.vue 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <script setup>
  2. import { ref, watch, computed, onMounted } from 'vue'
  3. import { Inertia } from '@inertiajs/inertia'
  4. import { Head, useForm, usePage } from '@inertiajs/inertia-vue3'
  5. import dayjs from 'dayjs'
  6. import throttle from 'lodash/throttle'
  7. import pickBy from 'lodash/pickBy'
  8. import AppButton from '@/components/AppButton.vue'
  9. import AppPagination from '@/components/AppPagination.vue'
  10. import AppMenu from '@/components/AppMenu.vue'
  11. import AppDropdown from '@/components/AppDropdown.vue'
  12. import AppLayout from '@/layouts/AppLayout.vue'
  13. import { IndexTable } from './TableHeader'
  14. const props = defineProps({
  15. transactions: Object,
  16. transactionsStatus: Array,
  17. filters: Object,
  18. outlets: Array,
  19. })
  20. const filterForm = useForm({
  21. search: props.filters.search,
  22. dates: null,
  23. startDate: props.filters.startDate,
  24. endDate: props.filters.endDate,
  25. outlet: props.filters.outlet,
  26. })
  27. onMounted(() => {
  28. if (props.filters.startDate || props.filters.endDate) {
  29. if (props.filters.endDate) {
  30. filterForm.dates = [new Date(props.filters.startDate), new Date(props.filters.endDate)]
  31. } else {
  32. filterForm.dates = [new Date(props.filters.startDate), null]
  33. }
  34. }
  35. })
  36. watch(
  37. filterForm,
  38. throttle(() => {
  39. if (filterForm.dates) {
  40. if (filterForm.dates[1]) {
  41. filterForm.startDate = dayjs(filterForm.dates[0]).format('YYYY-MM-DD')
  42. filterForm.endDate = dayjs(filterForm.dates[1]).format('YYYY-MM-DD')
  43. } else {
  44. filterForm.startDate = dayjs(filterForm.dates[0]).format('YYYY-MM-DD')
  45. filterForm.endDate = null
  46. }
  47. } else {
  48. filterForm.endDate = null
  49. filterForm.startDate = null
  50. }
  51. Inertia.get(
  52. '/transactions',
  53. pickBy({
  54. search: filterForm.search,
  55. startDate: filterForm.startDate,
  56. endDate: filterForm.endDate,
  57. outlet: filterForm.outlet,
  58. }),
  59. {
  60. preserveState: true,
  61. }
  62. )
  63. }, 300)
  64. )
  65. const transactionId = ref()
  66. const updateStatusDialogShow = ref(false)
  67. const updateStatusForm = useForm({
  68. transaction_status_id: null,
  69. })
  70. const updateStatusSubmit = () => {
  71. updateStatusForm.put(route('transactions.update', transactionId.value), {
  72. onSuccess: () => {
  73. updateStatusDialogShow.value = false
  74. },
  75. })
  76. }
  77. const updateStatusItems = ref([])
  78. const overlayMenu = ref()
  79. const overlayItems = ref([])
  80. const startPrinting = (transactionNumber) => {
  81. Inertia.get(`/thermal-printing/${transactionNumber}`)
  82. }
  83. const overlayToggle = (event, data) => {
  84. overlayItems.value =
  85. data.transactionStatusId == 4
  86. ? [
  87. {
  88. label: 'Lihat detail',
  89. icon: 'pi pi-eye',
  90. to: route('transactions.show', data.id),
  91. },
  92. {
  93. label: 'Cetak ulang',
  94. icon: 'pi pi-print',
  95. command() {
  96. startPrinting(data.transactionNumber)
  97. },
  98. },
  99. ]
  100. : [
  101. {
  102. label: 'Perbaharui status',
  103. icon: 'pi pi-refresh',
  104. command() {
  105. updateStatusDialogShow.value = true
  106. },
  107. },
  108. {
  109. label: 'Lihat detail',
  110. icon: 'pi pi-eye',
  111. to: route('transactions.show', data.id),
  112. },
  113. {
  114. label: 'Cetak ulang',
  115. icon: 'pi pi-print',
  116. command() {
  117. startPrinting(data.transactionNumber)
  118. },
  119. },
  120. ]
  121. updateStatusItems.value = props.transactionsStatus.filter((val) => val.value >= data.transactionStatusId)
  122. updateStatusForm.transaction_status_id = data.transactionStatusId
  123. transactionId.value = data.id
  124. overlayMenu.value.toggle(event)
  125. }
  126. const isAdmin = computed(() => usePage().props.value.isAdmin)
  127. </script>
  128. <template>
  129. <Head title="Daftar Transaksi" />
  130. <AppLayout>
  131. <DataTable
  132. responsive-layout="scroll"
  133. column-resize-mode="expand"
  134. :value="transactions.data"
  135. :row-hover="true"
  136. :striped-rows="true"
  137. >
  138. <template #header>
  139. <h5>Transaksi</h5>
  140. <div class="grid">
  141. <div class="col-12 md:col-8">
  142. <div class="grid">
  143. <div class="col-12 md:col-4">
  144. <InputText class="w-full" placeholder="cari..." v-model="filterForm.search" />
  145. </div>
  146. <div class="col-12 md:col-4">
  147. <Calendar
  148. class="w-full"
  149. v-model="filterForm.dates"
  150. selection-mode="range"
  151. placeholder="filter waktu..."
  152. date-format="dd/mm/yy"
  153. :show-button-bar="true"
  154. :manual-input="false"
  155. />
  156. </div>
  157. <div class="col-12 md:col-4">
  158. <Dropdown
  159. v-if="isAdmin"
  160. class="w-full"
  161. placeholder="pilih outlet..."
  162. v-model="filterForm.outlet"
  163. option-label="label"
  164. option-value="value"
  165. :options="outlets"
  166. />
  167. </div>
  168. </div>
  169. </div>
  170. <div class="col-12 md:col-4 flex justify-content-end">
  171. <AppButton
  172. label="Tambah Transaksi"
  173. class="p-button-text md:w-16rem"
  174. icon="pi pi-pencil"
  175. :href="route('transactions.create')"
  176. />
  177. </div>
  178. </div>
  179. </template>
  180. <Column
  181. v-for="indexTable in IndexTable"
  182. :field="indexTable.field"
  183. :header="indexTable.header"
  184. :key="indexTable.field"
  185. >
  186. <template #body="{ data, field }">
  187. <template v-if="field === 'transactionNumber'">
  188. <p class="font-bold">{{ data[field] }}</p>
  189. <p>{{ data.createdAt }}</p>
  190. </template>
  191. <template v-else-if="field === 'customer'">
  192. <p class="font-bold">{{ data.customer.number }}</p>
  193. <p>{{ data.customer.name }}</p>
  194. <p>{{ data.customer.phone }}</p>
  195. </template>
  196. <template v-else-if="field === 'transactionStatusName'">
  197. <Badge v-if="data['transactionStatusId'] === 1" :value="data[field]"></Badge>
  198. <Badge v-else-if="data['transactionStatusId'] === 2" :value="data[field]" severity="warning"></Badge>
  199. <Badge v-else :value="data[field]" severity="success"></Badge>
  200. </template>
  201. <template v-else>
  202. {{ data[field] }}
  203. </template>
  204. </template>
  205. </Column>
  206. <Column>
  207. <template #body="slotProps">
  208. <Button
  209. icon="pi pi-angle-double-down"
  210. class="p-button-rounded p-button-text"
  211. aria-controls="overlay_menu"
  212. @click="overlayToggle($event, slotProps.data)"
  213. />
  214. <AppMenu id="overlay_menu" ref="overlayMenu" :popup="true" :model="overlayItems" />
  215. </template>
  216. </Column>
  217. </DataTable>
  218. <AppPagination :links="transactions.links" />
  219. <Dialog
  220. modal
  221. v-model:visible="updateStatusDialogShow"
  222. class="p-fluid"
  223. header="Perbaharui Status"
  224. :style="{ width: '450px' }"
  225. :breakpoints="{ '960px': '75vw' }"
  226. @hide="updateStatusDialogShow"
  227. >
  228. <div class="grid">
  229. <div class="col-12">
  230. <AppDropdown
  231. label="Perbaharui Status"
  232. placeholder="pilih satu"
  233. v-model="updateStatusForm.transaction_status_id"
  234. :error="updateStatusForm.error"
  235. :options="updateStatusItems"
  236. />
  237. </div>
  238. </div>
  239. <template #footer>
  240. <div class="flex justify-content-end">
  241. <AppButton
  242. label="Simpan"
  243. icon="pi pi-check"
  244. class="p-button-text"
  245. :disabled="updateStatusForm.processing"
  246. @click="updateStatusSubmit"
  247. />
  248. </div>
  249. </template>
  250. </Dialog>
  251. </AppLayout>
  252. </template>