162 lines
5.0 KiB
Vue
162 lines
5.0 KiB
Vue
<script setup>
|
|
import { usePageTitle } from '../composables/Core/usePageTitle';
|
|
usePageTitle('POS History');
|
|
|
|
import { ref, onMounted } from 'vue';
|
|
import axios from 'axios';
|
|
import { useNavigate } from '../composables/Core/useNavigate';
|
|
import LoadingSpinner from '../Components/LoadingSpinner.vue';
|
|
import BackButton from '../Components/Core/BackButton.vue';
|
|
import PosHistoryList from '../Components/Market/PosHistoryList.vue';
|
|
import PosTodayStats from '../Components/Market/PosTodayStats.vue';
|
|
import SkeletonTable from '../Components/Core/Skeleton/SkeletonTable.vue';
|
|
import { usePosStore } from '../stores/pos';
|
|
|
|
const props = defineProps({
|
|
target: { type: String, required: true },
|
|
storeName: { type: String, default: 'Store' }
|
|
});
|
|
|
|
const { navigate } = useNavigate();
|
|
const posStore = usePosStore();
|
|
const store = ref(null);
|
|
const loadingStore = ref(false);
|
|
const loadingStats = ref(false);
|
|
|
|
const fetchStoreDetails = async () => {
|
|
// Only fetch if we don't have a specific name or if we want to ensure latest
|
|
loadingStore.value = true;
|
|
try {
|
|
const response = await axios.post('/View/Store/Details/data', {
|
|
target: props.target
|
|
});
|
|
if (response.data) {
|
|
store.value = response.data;
|
|
}
|
|
} catch (e) {
|
|
console.error('Failed to fetch store details:', e);
|
|
} finally {
|
|
loadingStore.value = false;
|
|
}
|
|
};
|
|
|
|
const fetchTodayStats = async () => {
|
|
loadingStats.value = true;
|
|
try {
|
|
await posStore.fetchTodayStats(props.target);
|
|
} catch (e) {
|
|
console.error('Failed to fetch today stats:', e);
|
|
} finally {
|
|
loadingStats.value = false;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
fetchStoreDetails();
|
|
fetchTodayStats();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="pos-history-page pb-5">
|
|
<div class="header-section shadow-sm mb-4">
|
|
<div class="tf-container py-3">
|
|
<div class="d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center">
|
|
<BackButton
|
|
:to="{ page: 'ViewStoreMarket', props: { target: props.target } }"
|
|
text=""
|
|
className="me-3"
|
|
/>
|
|
<div>
|
|
<h4 class="fw_7 mb-0">POS History</h4>
|
|
<p class="text-muted small mb-0">
|
|
{{ store?.name || props.storeName }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button
|
|
@click="navigate({ page: 'PosMain', props: { target: props.target } })"
|
|
class="btn btn-primary rounded-pill shadow-sm px-3 py-2 fw_6"
|
|
>
|
|
<i class="fas fa-cash-register me-2"></i> Open POS
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tf-container">
|
|
<PosTodayStats :loading="loadingStats" />
|
|
|
|
<div class="glass-card p-3 p-md-4">
|
|
<div class="d-flex align-items-center justify-content-between mb-4 mt-2">
|
|
<div class="d-flex align-items-center">
|
|
<div class="icon-avatar me-3">
|
|
<i class="fas fa-receipt text-primary"></i>
|
|
</div>
|
|
<div>
|
|
<h5 class="fw_6 mb-0">Transaction Records</h5>
|
|
<span v-if="posStore.posSessionsCount > 0" class="text-muted small">
|
|
{{ posStore.posSessionsCount }} Sessions Found
|
|
</span>
|
|
<span v-else class="text-muted small">
|
|
Past POS sessions
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="loadingStore && !store" class="mt-2">
|
|
<SkeletonTable :rows="6" :columns="4" />
|
|
</div>
|
|
|
|
<PosHistoryList v-else :storeHash="target" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.pos-history-page {
|
|
min-height: 100vh;
|
|
background: var(--bg-body);
|
|
}
|
|
|
|
.header-section {
|
|
background: var(--bg-card);
|
|
}
|
|
|
|
.glass-card {
|
|
background: var(--bg-card);
|
|
border-radius: 20px;
|
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.icon-avatar {
|
|
width: 44px;
|
|
height: 44px;
|
|
background: rgba(var(--primary-rgb), 0.1);
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
:global(.dark-mode) .header-section,
|
|
:global(.dark-mode) .glass-card {
|
|
background: #24272c;
|
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
:global(.dark-mode) .icon-avatar {
|
|
background: rgba(16, 185, 129, 0.1);
|
|
}
|
|
|
|
:global(.dark-mode) .icon-avatar i {
|
|
color: #10b981 !important;
|
|
}
|
|
</style>
|