This commit is contained in:
Viet An
2026-06-16 11:35:43 +07:00
parent a9c37cfff5
commit a8aa9a3dce
6 changed files with 153 additions and 109 deletions

View File

@@ -97,11 +97,8 @@ async function removeCart(cartId) {
<style scoped>
.tabs a {
background-color: hsl(from var(--bulma-tabs-boxed-link-hover-background-color) h s calc(l + 1));
--bulma-tabs-link-padding: 0.4em 1em 0.4em 0.5em;
&.new {
--bulma-tabs-link-padding: 0.4em 0.5em 0.4em 0.5em;
}
}
.tabs a:hover {
background-color: hsl(from var(--bulma-tabs-boxed-link-hover-background-color) h s calc(l - 2));
@@ -117,13 +114,13 @@ async function removeCart(cartId) {
.close {
display: none;
background-color: var(--bulma-white-ter);
background-color: transparent;
cursor: pointer;
}
li:hover .close {
display: flex;
}
.close:hover {
background-color: var(--bulma-grey-lighter);
background-color: hsl(0, 0%, 0%, 0.1);
}
</style>

View File

@@ -1,49 +1,38 @@
<script setup>
import { without } from "es-toolkit";
import Address from "~/components/pos/Address.vue";
import CartItem from "~/components/pos/CartItem.vue";
import CartTabs from "~/components/pos/CartTabs.vue";
import useActiveCart from "~/components/pos/composables/useActiveCart";
import useCartData from "~/components/pos/composables/useCartData";
import useCustomer from "~/components/pos/composables/useCustomer";
import useOrderInfo from "~/components/pos/composables/useOrderInfo";
import SearchBox from "~/components/SearchBox.vue";
const store = useStore();
const { $findapi, $getapi, $getdata, $patchapi, $numtoString } = useNuxtApp();
const carts = ref([]);
const cartItems = ref([]);
const customers = ref([]);
const activeCartId = ref();
const activeCart = computed(() => carts.value.find((c) => c.id === activeCartId.value));
const activeCartItems = computed(() => cartItems.value.filter((ci) => ci.cart === activeCartId.value));
const isUpdating = ref(false);
const { $numtoString } = useNuxtApp();
async function getCarts() {
const apis = $findapi(["Cart", "Cart_Item", "customer"]);
const [cartsRes, cartItemsRes, customersRes] = await $getapi(apis);
const { carts, cartItems, customers, getCarts, isPending } = useCartData();
carts.value = cartsRes.data.rows || [];
cartItems.value = cartItemsRes.data.rows || [];
customers.value = customersRes.data.rows || [];
}
const customerIdsWithNoCart = computed(() => {
const cusIds = customers.value.map((c) => c.id);
const cusIdsWithCart = carts.value.filter((c) => c.customer).map((c) => c.customer);
const cusIdsWithNoCart = without(cusIds, ...cusIdsWithCart);
return cusIdsWithNoCart;
const { activeCartId, activeCart, activeCartItems, customerIdsWithNoCart, subtotal } = useActiveCart({
carts,
cartItems,
customers,
});
onMounted(async () => {
await getCarts();
activeCartId.value = carts.value[0].id;
const { addresses, getAddresses, isChangingCus, changeCustomer } = useCustomer({ activeCart, getCarts });
const { orderInfo, isOrderValid } = useOrderInfo({
activeCartId,
activeCart,
activeCartItems,
addresses,
getAddresses,
});
watch(activeCartId, () => {
orderInfo.value.deliveryMethod = null;
orderInfo.value.paymentMethod = null;
});
const showModal = ref();
const showProductSelectionModal = ref();
function openProductSelectionModal() {
showProductSelectionModal.value = {
showModal.value = {
component: "pos/ProductSelection",
title: "Chọn sản phẩm",
width: "85%",
@@ -51,70 +40,8 @@ function openProductSelectionModal() {
};
}
const orderInfo = ref({
address: null,
deliveryMethod: null,
paymentMethod: null,
});
const addresses = ref([]);
const subtotal = computed(() => {
return activeCartItems.value?.reduce((prev, curr) => prev + curr.imei__variant__price, 0);
});
async function getAddresses() {
addresses.value = await $getdata("Customer_Address", {
filter: { customer: activeCart.value.customer },
});
}
watch(activeCart, async (newVal, oldVal) => {
// set order info
if (newVal.customer) {
await getAddresses();
if (!oldVal || !oldVal.customer || oldVal.customer !== newVal.customer) {
const defaultAddress = addresses.value.find((add) => add.is_default);
orderInfo.value.address = defaultAddress;
}
} else {
addresses.value = null;
orderInfo.value.address = null;
}
});
const isChangingCus = ref(false);
async function changeCustomer(cusId) {
isChangingCus.value = true;
const updatedCart = await $patchapi("Cart", {
id: activeCartId.value,
customer: cusId,
});
await getCarts();
isChangingCus.value = false;
}
watch(
() => orderInfo.value.deliveryMethod,
(newVal) => {
if (newVal?.code === "HOME_DELIVERY") {
const defaultAddress = addresses.value.find((add) => add.is_default);
orderInfo.value.address = defaultAddress;
}
},
);
const isOrderValid = computed(() => {
if (activeCartItems.value?.length === 0) return false;
if (!activeCart.value?.customer) return false;
if (!orderInfo.value.deliveryMethod) return false;
if (!orderInfo.value.paymentMethod) return false;
if (orderInfo.value.deliveryMethod.code === "HOME_DELIVERY" && !orderInfo.value.address) return false;
return true;
});
const showConfirmModal = ref();
function openConfirmModal() {
showConfirmModal.value = {
showModal.value = {
component: "pos/ConfirmOrder",
title: "Xác nhận đơn hàng",
width: "60%",
@@ -163,7 +90,7 @@ provide("pos", {
</span>
<span>Giỏ hàng</span>
<span
v-if="isUpdating"
v-if="isPending"
class="icon"
>
<Icon
@@ -385,14 +312,9 @@ provide("pos", {
</div>
</div>
<Modal
v-if="showProductSelectionModal"
v-bind="showProductSelectionModal"
@close="showProductSelectionModal = undefined"
/>
<Modal
v-if="showConfirmModal"
v-bind="showConfirmModal"
@close="showConfirmModal = undefined"
v-if="showModal"
v-bind="showModal"
@close="showModal = undefined"
/>
</div>
</template>

View File

@@ -0,0 +1,31 @@
import { without } from "es-toolkit";
export default function useActiveCart({ carts, cartItems, customers }) {
const activeCartId = ref();
const activeCart = computed(() => carts.value.find((c) => c.id === activeCartId.value));
const activeCartItems = computed(() => cartItems.value.filter((ci) => ci.cart === activeCartId.value));
watch(
carts,
(newVal) => {
if (!activeCartId.value && newVal.length) {
activeCartId.value = newVal[0].id;
}
},
{ immediate: true },
);
const customerIdsWithNoCart = computed(() => {
const cusIds = customers.value.map((c) => c.id);
const cusIdsWithCart = carts.value.filter((c) => c.customer).map((c) => c.customer);
const cusIdsWithNoCart = without(cusIds, ...cusIdsWithCart);
return cusIdsWithNoCart;
});
const subtotal = computed(() => {
return activeCartItems.value?.reduce((prev, curr) => prev + curr.imei__variant__price, 0);
});
return { activeCartId, activeCart, activeCartItems, customerIdsWithNoCart, subtotal };
}

View File

@@ -0,0 +1,22 @@
export default function useCartData() {
const { $findapi, $getapi } = useNuxtApp();
const carts = ref([]);
const cartItems = ref([]);
const customers = ref([]);
const isPending = ref(false);
async function getCarts() {
isPending.value = true;
const apis = $findapi(["Cart", "Cart_Item", "customer"]);
const [cartsRes, cartItemsRes, customersRes] = await $getapi(apis);
isPending.value = false;
carts.value = cartsRes.data.rows || [];
cartItems.value = cartItemsRes.data.rows || [];
customers.value = customersRes.data.rows || [];
}
onMounted(getCarts);
return { carts, cartItems, customers, getCarts, isPending };
}

View File

@@ -0,0 +1,23 @@
export default function useCustomer({ activeCart, getCarts }) {
const { $getdata, $patchapi } = useNuxtApp();
const addresses = ref([]);
async function getAddresses() {
addresses.value = await $getdata("Customer_Address", {
filter: { customer: activeCart.value.customer },
});
}
const isChangingCus = ref(false);
async function changeCustomer(cusId) {
isChangingCus.value = true;
const updatedCart = await $patchapi("Cart", {
id: activeCart.value.id,
customer: cusId,
});
await getCarts();
isChangingCus.value = false;
}
return { addresses, getAddresses, isChangingCus, changeCustomer };
}

View File

@@ -0,0 +1,49 @@
export default function useOrderInfo({ activeCartId, activeCart, activeCartItems, addresses, getAddresses }) {
const orderInfo = ref({
address: null,
deliveryMethod: null,
paymentMethod: null,
});
watch(activeCartId, () => {
// reset fields when tab is switched
orderInfo.value.deliveryMethod = null;
orderInfo.value.paymentMethod = null;
});
watch(activeCart, async (newVal, oldVal) => {
// set order info
if (newVal?.customer) {
await getAddresses();
if (!oldVal || !oldVal.customer || oldVal.customer !== newVal.customer) {
const defaultAddress = addresses.value.find((add) => add.is_default);
orderInfo.value.address = defaultAddress;
}
} else {
addresses.value = null;
orderInfo.value.address = null;
}
});
watch(
() => orderInfo.value.deliveryMethod,
(newVal) => {
if (newVal?.code === "HOME_DELIVERY") {
const defaultAddress = addresses.value.find((add) => add.is_default);
orderInfo.value.address = defaultAddress;
}
},
);
const isOrderValid = computed(() => {
if (activeCartItems.value?.length === 0) return false;
if (!activeCart.value?.customer) return false;
if (!orderInfo.value.deliveryMethod) return false;
if (!orderInfo.value.paymentMethod) return false;
if (orderInfo.value.deliveryMethod.code === "HOME_DELIVERY" && !orderInfo.value.address) return false;
return true;
});
return { orderInfo, isOrderValid };
}