Files
web/app/components/product/Cart.vue
2026-05-05 11:06:49 +07:00

268 lines
6.8 KiB
Vue

<template>
<div>
<!-- Header với nút thêm upload -->
<div class="columns mb-0">
<div class="column is-10">
<!-- Cart selection list -->
<div v-if="showCartList">
<div class="tags">
<div
v-for="(cart, index) in carts"
:key="cart.id"
class="tag is-medium has-addons"
:class="{ 'is-primary': selectedCarts.includes(cart.id) }"
@click="handleCartClick(cart.id, index, $event)"
style="cursor: pointer; user-select: none"
>
<span>{{ cart.code }} - {{ cart.name }}</span>
<span
v-if="selectedCarts.includes(cart.id) && $getEditRights()"
class="ml-2 tag is-delete"
@click.stop="removeCart(cart.id)"
></span>
<span
v-if="selectedCarts.includes(cart.id) && $getEditRights()"
class="tag ml-2"
@click.stop="editCart(cart.id)"
title="Chỉnh sửa giỏ hàng"
style="cursor: pointer"
>
<SvgIcon v-bind="{ name: 'pen1.svg', type: 'dark', size: 16 }" />
</span>
</div>
</div>
</div>
</div>
<div
v-if="$getEditRights()"
class="column is-2"
>
<div class="field">
<div class="control">
<a
class="mr-3"
@click="upload()"
>
<span class="icon-text">
<SvgIcon v-bind="{ name: 'upload.svg', type: 'primary', size: 25 }" />
<span class="ml-1 fsb-17">Phân bổ</span>
</span>
</a>
<a @click="addNew()">
<span class="icon-text">
<SvgIcon v-bind="{ name: 'add1.png', type: 'primary', size: 23 }" />
<span class="ml-1 fsb-17">Thêm mới</span>
</span>
</a>
</div>
</div>
</div>
</div>
<!-- Data View với product được filter -->
<div
class="m-0"
v-if="selectedCarts.length > 0"
>
<div class="level mb-3">
<div class="level-left">
<div class="level-item">
<h5 class="title is-5">Sản phẩm trong giỏ</h5>
<button
class="button is-small is-text"
@click="clearSelection"
>
Bỏ chọn tất cả
</button>
</div>
</div>
</div>
<!-- DataView với key động để force reload khi filter thay đổi -->
<DataView
v-bind="dataViewConfig"
:key="selectedCartsKey"
/>
</div>
<!-- Modal Components -->
<Modal
v-if="showmodal"
@close="showmodal = undefined"
@dataevent="dataevent"
v-bind="showmodal"
/>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import { useStore } from "~/stores/index";
import DataView from "~/components/datatable/DataView.vue";
import Modal from "~/components/Modal.vue";
import SvgIcon from "~/components/SvgIcon.vue";
const { $getapi, $findapi, $copy, $find } = useNuxtApp();
const store = useStore();
// State
const showmodal = ref();
const showCartList = ref(true);
const selectedCarts = ref([]);
const carts = ref([]);
const lastSelectedIndex = ref(null);
// Key động để force reload DataView khi selectedCarts thay đổi
const selectedCartsKey = computed(() => {
const sorted = [...selectedCarts.value].sort((a, b) => a - b);
return "dataview-cart-" + sorted.join("-");
});
// DataView config
const dataViewConfig = computed(() => {
const config = {
api: "product",
setting: "product-list-cart",
pagename: "pagedata1",
modal: { component: "parameter/ProductForm", title: "Sản phẩm" },
timeopt: { time: 36000, disable: "add" },
realtime: { time: 2, update: "false" },
};
if (selectedCarts.value.length > 0) {
config.filter = { cart__in: selectedCarts.value };
}
return config;
});
// Modal configs
const newAddon = {
component: "parameter/NewCart",
title: "Giỏ hàng",
width: "900px",
height: "400px",
};
// Methods
function handleCartClick(cartId, index, event) {
if (event.ctrlKey) {
// Ctrl + Click: Chọn/bỏ chọn từng cái
toggleCart(cartId);
lastSelectedIndex.value = index;
} else if (event.shiftKey) {
// Shift + Click: Chọn range từ last đến hiện tại
if (lastSelectedIndex.value !== null) {
selectRange(lastSelectedIndex.value, index);
} else {
toggleCart(cartId);
lastSelectedIndex.value = index;
}
} else {
// Click bình thường: Chọn chỉ cái này
selectedCarts.value = [cartId];
lastSelectedIndex.value = index;
}
}
function selectRange(startIndex, endIndex) {
const start = Math.min(startIndex, endIndex);
const end = Math.max(startIndex, endIndex);
for (let i = start; i <= end; i++) {
const cartId = carts.value[i].id;
if (!selectedCarts.value.includes(cartId)) {
selectedCarts.value.push(cartId);
}
}
}
function toggleCart(cartId) {
const index = selectedCarts.value.indexOf(cartId);
if (index > -1) {
selectedCarts.value.splice(index, 1);
} else {
selectedCarts.value.push(cartId);
}
}
function removeCart(cartId) {
const index = selectedCarts.value.indexOf(cartId);
if (index > -1) {
selectedCarts.value.splice(index, 1);
}
}
function getCartName(cartId) {
const cart = carts.value.find((c) => c.id === cartId);
return cart ? `${cart.code} - ${cart.name}` : "";
}
function applyFilter() {
if (selectedCarts.value.length === 0) {
alert("Vui lòng chọn ít nhất một giỏ hàng");
return;
}
showCartList.value = false;
}
function clearSelection() {
selectedCarts.value = [];
showCartList.value = true;
}
function upload() {
showmodal.value = {
component: "parameter/ImportData",
title: "Phân bổ giỏ hàng",
width: "80%",
height: "400px",
vbind: { code: "product-cart" },
};
}
function addNew() {
showmodal.value = {
component: "parameter/NewCart",
title: "Thêm giỏ hàng mới",
width: "900px",
height: "500px",
};
}
function editCart(cartId) {
showmodal.value = {
component: "parameter/NewCart",
title: "Chỉnh sửa giỏ hàng",
width: "900px",
height: "500px",
vbind: {
id: cartId,
},
};
}
function dataevent() {
loadCarts();
}
async function loadCarts() {
try {
const conn = $findapi("cart");
const rs = await $getapi([conn]);
const obj = $find(rs, { name: "cart" });
if (obj) {
carts.value = $copy(obj.data.rows || []);
}
} catch (error) {
console.error("Lỗi khi fetch giỏ hàng:", error);
}
}
// Init
onMounted(() => {
loadCarts();
});
</script>