Index.vue 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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(filterForm, () => {
  37. if (filterForm.dates) {
  38. if (filterForm.dates[1]) {
  39. filterForm.startDate = dayjs(filterForm.dates[0]).format('YYYY-MM-DD')
  40. filterForm.endDate = dayjs(filterForm.dates[1]).format('YYYY-MM-DD')
  41. } else {
  42. filterForm.startDate = dayjs(filterForm.dates[0]).format('YYYY-MM-DD')
  43. filterForm.endDate = null
  44. }
  45. } else {
  46. filterForm.endDate = null
  47. filterForm.startDate = null
  48. }
  49. Inertia.get(
  50. '/transactions',
  51. pickBy({
  52. search: filterForm.search,
  53. startDate: filterForm.startDate,
  54. endDate: filterForm.endDate,
  55. outlet: filterForm.outlet,
  56. }),
  57. {
  58. preserveState: true,
  59. }
  60. )
  61. })
  62. const filterReset = () => {
  63. Inertia.get('/transactions')
  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. <h1>Transaksi</h1>
  140. <div class="grid">
  141. <div class="col-12 md:col-8">
  142. <div class="grid">
  143. <div class="col-12 md:col-3">
  144. <InputText class="w-full" placeholder="cari..." v-model="filterForm.search" />
  145. </div>
  146. <div class="col-12 md:col-3">
  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. :manual-input="false"
  154. />
  155. </div>
  156. <div class="col-12 md:col-3">
  157. <Dropdown
  158. v-if="isAdmin"
  159. class="w-full"
  160. placeholder="pilih outlet..."
  161. v-model="filterForm.outlet"
  162. option-label="label"
  163. option-value="value"
  164. :options="outlets"
  165. />
  166. </div>
  167. <div class="col-auto mt-2 ml-2">
  168. <Button label="reset" class="p-button-link" @click="filterReset" />
  169. </div>
  170. </div>
  171. </div>
  172. <div class="col-12 md:col-4 flex justify-content-end">
  173. <AppButton
  174. label="Tambah Transaksi"
  175. class="p-button-outlined md:w-16rem"
  176. icon="pi pi-pencil"
  177. :href="route('transactions.create')"
  178. />
  179. </div>
  180. </div>
  181. </template>
  182. <Column
  183. v-for="indexTable in IndexTable"
  184. :field="indexTable.field"
  185. :header="indexTable.header"
  186. :key="indexTable.field"
  187. >
  188. <template #body="{ data, field }">
  189. <template v-if="field === 'transactionNumber'">
  190. <p class="font-bold">{{ data[field] }}</p>
  191. <p>{{ data.createdAt }}</p>
  192. </template>
  193. <template v-else-if="field === 'customer'">
  194. <p class="font-bold">{{ data.customer.number }}</p>
  195. <p>{{ data.customer.name }}</p>
  196. <p>{{ data.customer.phone }}</p>
  197. </template>
  198. <template v-else-if="field === 'transactionStatusName'">
  199. <Badge v-if="data['transactionStatusId'] === 1" :value="data[field]"></Badge>
  200. <Badge v-else-if="data['transactionStatusId'] === 2" :value="data[field]" severity="warning"></Badge>
  201. <Badge v-else :value="data[field]" severity="success"></Badge>
  202. </template>
  203. <template v-else>
  204. {{ data[field] }}
  205. </template>
  206. </template>
  207. </Column>
  208. <Column>
  209. <template #body="slotProps">
  210. <Button
  211. icon="pi pi-angle-double-down"
  212. class="p-button-rounded p-button-text"
  213. aria-controls="overlay_menu"
  214. @click="overlayToggle($event, slotProps.data)"
  215. />
  216. <AppMenu id="overlay_menu" ref="overlayMenu" :popup="true" :model="overlayItems" />
  217. </template>
  218. </Column>
  219. </DataTable>
  220. <AppPagination :links="transactions.links" />
  221. <Dialog
  222. modal
  223. v-model:visible="updateStatusDialogShow"
  224. class="p-fluid"
  225. header="Perbaharui Status"
  226. :style="{ width: '450px' }"
  227. :breakpoints="{ '960px': '75vw' }"
  228. @hide="updateStatusDialogShow"
  229. >
  230. <div class="grid">
  231. <div class="col-12">
  232. <AppDropdown
  233. label="Perbaharui Status"
  234. placeholder="pilih satu"
  235. v-model="updateStatusForm.transaction_status_id"
  236. :error="updateStatusForm.error"
  237. :options="updateStatusItems"
  238. />
  239. </div>
  240. </div>
  241. <template #footer>
  242. <div class="flex justify-content-end">
  243. <Button
  244. label="Simpan"
  245. icon="pi pi-check"
  246. class="p-button-text"
  247. :disabled="updateStatusForm.processing"
  248. @click="updateStatusSubmit"
  249. />
  250. </div>
  251. </template>
  252. </Dialog>
  253. </AppLayout>
  254. </template>