update barcode, kasir
This commit is contained in:
parent
a3e68b8cd0
commit
a6be703b10
@ -42,9 +42,16 @@ class ItemController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*/
|
*/
|
||||||
public function show(int $id)
|
public function show(string $kode_item)
|
||||||
{
|
{
|
||||||
$item = Item::with('produk.foto','nampan')->findOrFail($id);
|
$item = Item::with(['produk.foto', 'nampan'])
|
||||||
|
->where('kode_item', $kode_item)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$item) {
|
||||||
|
return response()->json(['message' => 'Item tidak ditemukan'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json($item);
|
return response()->json($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -102,14 +102,16 @@ const createdItem = ref(null);
|
|||||||
// QR Code generator - berdasarkan logika dari brankas list
|
// QR Code generator - berdasarkan logika dari brankas list
|
||||||
const qrCodeUrl = computed(() => {
|
const qrCodeUrl = computed(() => {
|
||||||
if (createdItem.value && props.product) {
|
if (createdItem.value && props.product) {
|
||||||
const itemId = createdItem.value.id || createdItem.value.kode_item;
|
const itemId = createdItem.value.kode_item || createdItem.value.id;
|
||||||
const productName = props.product.nama.replace(/\s/g, "");
|
const data = `${itemId}`;
|
||||||
const data = `ITM-${itemId}-${productName}`;
|
|
||||||
return `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(data)}`;
|
// Barcode Code128
|
||||||
|
return `https://barcode.tec-it.com/barcode.ashx?data=${encodeURIComponent(data)}&code=Code128&dpi=96`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
const loadNampanList = async () => {
|
const loadNampanList = async () => {
|
||||||
try {
|
try {
|
||||||
@ -204,7 +206,7 @@ const printItem = () => {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="qr-container">
|
<div class="qr-container">
|
||||||
<img src="${qrCodeUrl.value}" alt="QR Code" style="width: 200px; height: 200px;" />
|
<img src="${qrCodeUrl.value}" alt="Barcode" style="width: 300px; height: 100px;" />
|
||||||
<div class="item-info">
|
<div class="item-info">
|
||||||
<div style="font-weight: bold; margin-bottom: 5px;">${itemCode}</div>
|
<div style="font-weight: bold; margin-bottom: 5px;">${itemCode}</div>
|
||||||
<div>${props.product.nama}</div>
|
<div>${props.product.nama}</div>
|
||||||
|
|||||||
20
resources/js/components/ModalConfirm.vue
Normal file
20
resources/js/components/ModalConfirm.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||||
|
<div class="bg-white rounded-lg p-6 max-w-sm w-full shadow-xl">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">{{ title }}</h3>
|
||||||
|
<p class="mb-6">{{ message }}</p>
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<button @click="$emit('cancel')" class="px-4 py-2 bg-gray-300 rounded">Batal</button>
|
||||||
|
<button @click="$emit('confirm')" class="px-4 py-2 bg-blue-600 text-white rounded">Ya</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
title: String,
|
||||||
|
message: String
|
||||||
|
});
|
||||||
|
defineEmits(["confirm", "cancel"]);
|
||||||
|
</script>
|
||||||
@ -33,16 +33,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ✅ POPUP KONFIRMASI -->
|
||||||
|
<ModalConfirm
|
||||||
|
v-if="showConfirm"
|
||||||
|
title="Konfirmasi"
|
||||||
|
:message="confirmMessage"
|
||||||
|
@confirm="handleConfirm"
|
||||||
|
@cancel="showConfirm = false"
|
||||||
|
/>
|
||||||
</mainLayout>
|
</mainLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted, onUnmounted } from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import mainLayout from "../layouts/mainLayout.vue";
|
import mainLayout from "../layouts/mainLayout.vue";
|
||||||
import KasirForm from "../components/KasirForm.vue";
|
import KasirForm from "../components/KasirForm.vue";
|
||||||
import KasirTransaksiList from "../components/KasirTransaksiList.vue";
|
import KasirTransaksiList from "../components/KasirTransaksiList.vue";
|
||||||
|
import ModalConfirm from "../components/ModalConfirm.vue"; // ✅ Tambah ini
|
||||||
|
|
||||||
const transaksi = ref({
|
const transaksi = ref({
|
||||||
data: [],
|
data: [],
|
||||||
@ -52,13 +62,22 @@ const loading = ref(true);
|
|||||||
const currentPage = ref(1);
|
const currentPage = ref(1);
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
|
|
||||||
|
const showConfirm = ref(false); // ✅
|
||||||
|
const confirmMessage = ref("Apakah kamu yakin?"); // ✅
|
||||||
|
let lastTransaksi = null; // untuk tau data transaksi terakhir
|
||||||
|
|
||||||
|
// ✅ Placeholder jika user tekan "Ya"
|
||||||
|
const handleConfirm = () => {
|
||||||
|
showConfirm.value = false;
|
||||||
|
console.log("User konfirmasi, cetak struk di sini...", lastTransaksi);
|
||||||
|
// TODO: jalankan fungsi cetakStruk(lastTransaksi)
|
||||||
|
};
|
||||||
|
|
||||||
// Fetch hanya transaksi hari ini
|
// Fetch hanya transaksi hari ini
|
||||||
const fetchTransaksiHariIni = async (page = 1) => {
|
const fetchTransaksiHariIni = async (page = 1) => {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
currentPage.value = page;
|
currentPage.value = page;
|
||||||
|
|
||||||
// Hanya fetch transaksi hari ini
|
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split('T')[0];
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
limit: limit,
|
limit: limit,
|
||||||
@ -67,8 +86,6 @@ const fetchTransaksiHariIni = async (page = 1) => {
|
|||||||
end_date: today
|
end_date: today
|
||||||
}).toString();
|
}).toString();
|
||||||
|
|
||||||
// console.log('Fetching transaksi hari ini:', params);
|
|
||||||
|
|
||||||
const res = await axios.get(`/api/transaksi?${params}`, {
|
const res = await axios.get(`/api/transaksi?${params}`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
@ -80,22 +97,10 @@ const fetchTransaksiHariIni = async (page = 1) => {
|
|||||||
pagination: res.data.pagination || null
|
pagination: res.data.pagination || null
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log("Transaksi hari ini:", transaksi.value);
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Gagal fetch transaksi hari ini:", err);
|
console.error("Gagal fetch transaksi hari ini:", err);
|
||||||
transaksi.value = { data: [], pagination: null };
|
transaksi.value = { data: [], pagination: null };
|
||||||
|
alert("Gagal memuat transaksi hari ini");
|
||||||
let errorMessage = 'Gagal memuat transaksi hari ini';
|
|
||||||
if (err.response) {
|
|
||||||
errorMessage += `: ${err.response.status} - ${err.response.data?.message || err.response.statusText}`;
|
|
||||||
} else if (err.request) {
|
|
||||||
errorMessage += ': Tidak ada respon dari server';
|
|
||||||
} else {
|
|
||||||
errorMessage += `: ${err.message}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
alert(errorMessage);
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@ -103,18 +108,13 @@ const fetchTransaksiHariIni = async (page = 1) => {
|
|||||||
|
|
||||||
// Handle pagination
|
// Handle pagination
|
||||||
const handlePageChange = (page) => {
|
const handlePageChange = (page) => {
|
||||||
// console.log('Page changed to:', page);
|
|
||||||
|
|
||||||
if (page >= 1 && page <= (transaksi.value.pagination?.last_page || 1)) {
|
if (page >= 1 && page <= (transaksi.value.pagination?.last_page || 1)) {
|
||||||
fetchTransaksiHariIni(page);
|
fetchTransaksiHariIni(page);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle transaksi baru dari KasirForm
|
// ✅ Popup setelah transaksi tersimpan
|
||||||
const handleTransaksiSaved = async (newTransaksi) => {
|
const handleTransaksiSaved = async (newTransaksi) => {
|
||||||
// console.log("Transaksi baru disimpan:", newTransaksi);
|
|
||||||
|
|
||||||
// Karena ini transaksi hari ini, selalu tambahkan ke list
|
|
||||||
const formattedNewTransaksi = {
|
const formattedNewTransaksi = {
|
||||||
id: newTransaksi.id,
|
id: newTransaksi.id,
|
||||||
kode_transaksi: newTransaksi.kode_transaksi,
|
kode_transaksi: newTransaksi.kode_transaksi,
|
||||||
@ -126,30 +126,27 @@ const handleTransaksiSaved = async (newTransaksi) => {
|
|||||||
tanggal: new Date(newTransaksi.created_at).toLocaleDateString('id-ID')
|
tanggal: new Date(newTransaksi.created_at).toLocaleDateString('id-ID')
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tambahkan ke awal array
|
|
||||||
transaksi.value.data.unshift(formattedNewTransaksi);
|
transaksi.value.data.unshift(formattedNewTransaksi);
|
||||||
|
lastTransaksi = formattedNewTransaksi; // ✅ Simpan untuk cetak
|
||||||
|
|
||||||
// Update pagination
|
|
||||||
if (transaksi.value.pagination) {
|
if (transaksi.value.pagination) {
|
||||||
transaksi.value.pagination.total += 1;
|
transaksi.value.pagination.total += 1;
|
||||||
|
|
||||||
// Jika sudah penuh, hapus item terakhir
|
|
||||||
if (transaksi.value.data.length > limit) {
|
if (transaksi.value.data.length > limit) {
|
||||||
transaksi.value.data.pop();
|
transaksi.value.data.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log("Transaksi baru ditambahkan ke list hari ini");
|
confirmMessage.value = "Transaksi berhasil disimpan. Cetak struk sekarang?";
|
||||||
|
showConfirm.value = true; // ✅ Munculkan popup
|
||||||
};
|
};
|
||||||
|
|
||||||
// Auto-refresh setiap 10 detik untuk update real-time
|
// Auto-refresh setiap 10 detik untuk update real-time
|
||||||
let refreshInterval = null;
|
let refreshInterval = null;
|
||||||
|
|
||||||
const startAutoRefresh = () => {
|
const startAutoRefresh = () => {
|
||||||
if (refreshInterval) clearInterval(refreshInterval);
|
if (refreshInterval) clearInterval(refreshInterval);
|
||||||
refreshInterval = setInterval(() => {
|
refreshInterval = setInterval(() => {
|
||||||
fetchTransaksiHariIni(currentPage.value);
|
fetchTransaksiHariIni(currentPage.value);
|
||||||
}, 10000); // 10 detik
|
}, 10000);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopAutoRefresh = () => {
|
const stopAutoRefresh = () => {
|
||||||
@ -159,14 +156,11 @@ const stopAutoRefresh = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchTransaksiHariIni();
|
await fetchTransaksiHariIni();
|
||||||
startAutoRefresh();
|
startAutoRefresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
import { onUnmounted } from 'vue';
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
stopAutoRefresh();
|
stopAutoRefresh();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user