Initial commit
This commit is contained in:
135
app/components/viewer/ProductNoteHistory.vue
Normal file
135
app/components/viewer/ProductNoteHistory.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
const store = useStore()
|
||||
const { $connectWebSocket, $subscribe } = useNuxtApp()
|
||||
const { dealer } = store
|
||||
const notes = ref([])
|
||||
const isLoading = ref(true)
|
||||
|
||||
function navigateTo(productId) {
|
||||
if (!productId) return
|
||||
window.dispatchEvent(new CustomEvent('navigateToProduct', { detail: { productId } }))
|
||||
}
|
||||
|
||||
function handleWsMessageForNotes({ detail: response }) {
|
||||
if (response.type !== 'realtime_update') return
|
||||
const { name, change_type, record } = response.payload;
|
||||
if (name.toLowerCase() !== 'product_note') return;
|
||||
|
||||
if (dealer?.id && record.ref__cart__dealer !== dealer.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newNotes = [...notes.value]
|
||||
const existingNoteIndex = newNotes.findIndex(n => n.id === record.id)
|
||||
|
||||
if (change_type === 'created') {
|
||||
if (existingNoteIndex === -1) {
|
||||
newNotes.push(record)
|
||||
}
|
||||
} else if (change_type === 'updated') {
|
||||
if (existingNoteIndex > -1) {
|
||||
newNotes[existingNoteIndex] = { ...newNotes[existingNoteIndex], ...record }
|
||||
}
|
||||
} else if (change_type === 'deleted') {
|
||||
if (existingNoteIndex > -1) {
|
||||
newNotes.splice(existingNoteIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
notes.value = newNotes.sort((a, b) => new Date(b.create_time) - new Date(a.create_time));
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
$connectWebSocket();
|
||||
const filter = dealer?.id ? { ref__cart__dealer: dealer.id } : undefined;
|
||||
|
||||
$subscribe('productnote', filter, (initialData) => {
|
||||
if (initialData && initialData.rows) {
|
||||
notes.value = initialData.rows.sort((a, b) => new Date(b.create_time) - new Date(a.create_time));
|
||||
}
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
window.addEventListener('ws_message', handleWsMessageForNotes);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('ws_message', handleWsMessageForNotes);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="is-flex is-flex-direction-column has-background-white" style="height: 100%; overflow: hidden;">
|
||||
<!-- Loading -->
|
||||
<div v-if="isLoading" class="is-flex is-flex-grow-1 is-justify-content-center is-align-items-center p-5">
|
||||
<div class="has-text-centered">
|
||||
<progress class="progress is-info" max="100" style="width: 100px;"></progress>
|
||||
<p class="has-text-grey is-size-7 mt-2">Đang tải...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty -->
|
||||
<div v-else-if="notes.length === 0" class="is-flex is-flex-grow-1 is-justify-content-center is-align-items-center p-5">
|
||||
<p class="has-text-grey-light is-size-7">Chưa có ghi chú</p>
|
||||
</div>
|
||||
|
||||
<!-- Notes Table -->
|
||||
<div v-else class="is-flex-grow-1" style="overflow-y: auto; overflow-x: hidden; min-height: 0;">
|
||||
<table class="table is-fullwidth is-hoverable is-narrow is-size-7 mb-0">
|
||||
<thead style="position: sticky; top: 0px;">
|
||||
<tr>
|
||||
<th>Sản phẩm</th>
|
||||
<th>Nội dung</th>
|
||||
<th style="min-width: max-content; text-wrap: nowrap">Người tạo</th>
|
||||
<th class="has-text-right">Thời gian</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="note in notes" :key="note.id" class="is-clickable" @click="navigateTo(note.ref)">
|
||||
<td>
|
||||
<span class="tag is-link is-light is-small">{{ note.ref__trade_code }}</span>
|
||||
</td>
|
||||
<td style="white-space: pre-wrap; word-break: break-word;">{{ note.detail }}</td>
|
||||
<td>{{ note.username || note.user__username }}</td>
|
||||
<td class="has-text-right" style="white-space: nowrap;">
|
||||
{{ new Date(note.create_time).toLocaleString('vi-VN') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
#noteHistory.docking-panel {
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
width: 450px;
|
||||
height: 400px;
|
||||
resize: both;
|
||||
overflow: hidden;
|
||||
|
||||
.docking-panel-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-bottom: none;
|
||||
text-transform: none;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.docking-panel-scroll {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
margin-bottom: 20px;
|
||||
flex-grow: 1;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.table.is-narrow td, .table.is-narrow th {
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user