- Esporta Lista Carrello (Totale)

- Sconto Applicato
This commit is contained in:
Surya Paolo
2025-06-09 09:48:34 +02:00
parent 664975b1fd
commit 56d1870bc1
17 changed files with 1325 additions and 327 deletions

View File

@@ -1,21 +1,21 @@
import { defineComponent, onMounted, ref, computed, watch } from 'vue'
import { tools } from '@tools'
import { useUserStore } from '@store/UserStore'
import { useRouter } from 'vue-router'
import { useGlobalStore } from '@store/globalStore'
import { useProducts } from '@store/Products'
import { useI18n } from 'vue-i18n'
import { toolsext } from '@store/Modules/toolsext'
import { useQuasar } from 'quasar'
import { costanti } from '@costanti'
import { defineComponent, onMounted, ref, computed, watch } from 'vue';
import { tools } from '@tools';
import { useUserStore } from '@store/UserStore';
import { useRouter } from 'vue-router';
import { useGlobalStore } from '@store/globalStore';
import { useProducts } from '@store/Products';
import { useI18n } from 'vue-i18n';
import { toolsext } from '@store/Modules/toolsext';
import { useQuasar } from 'quasar';
import { costanti } from '@costanti';
import type { ICart, IOrder, IOrderCart, IProduct } from '@src/model/Products';
import { IShareWithUs } from '@src/model/Products'
import { IShareWithUs } from '@src/model/Products';
import { shared_consts } from '@src/common/shared_vuejs'
import { shared_consts } from '@src/common/shared_vuejs';
import { CSingleCart } from '../CSingleCart'
import { CTitleBanner } from '@src/components/CTitleBanner'
import { CSelectUserActive } from '@src/components/CSelectUserActive'
import { CSingleCart } from '../CSingleCart';
import { CTitleBanner } from '@src/components/CTitleBanner';
import { CSelectUserActive } from '@src/components/CSelectUserActive';
export default defineComponent({
name: 'CCart',
@@ -30,148 +30,160 @@ export default defineComponent({
required: false,
default: null,
},
},
components: { CSingleCart, CTitleBanner, CSelectUserActive },
setup(props) {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const productStore = useProducts()
const $router = useRouter()
const $q = useQuasar()
const userStore = useUserStore();
const globalStore = useGlobalStore();
const productStore = useProducts();
const $router = useRouter();
const $q = useQuasar();
const { t } = useI18n();
const mycart = ref(<ICart>{})
const myrec = ref(<any[string]>[])
const oldrec = ref(<any[string]>[])
const note = ref('')
const endload = ref(false)
const recOrderCart = ref(<IOrderCart>{})
const mycart = ref(<ICart>{});
const myrec = ref(<any[string]>[]);
const oldrec = ref(<any[string]>[]);
const note = ref('');
const codice_sconto = ref('');
const endload = ref(false);
const caricamentodati = ref(false);
const recOrderCart = ref(<IOrderCart>{});
const search = ref('')
const search = ref('');
const isfinishLoading = computed(() => globalStore.finishLoading)
const isfinishLoading = computed(() => globalStore.finishLoading);
watch(() => isfinishLoading.value, (newval: boolean, oldval: boolean) => {
if (isfinishLoading.value) {
load()
watch(
() => isfinishLoading.value,
(newval: boolean, oldval: boolean) => {
if (isfinishLoading.value) {
load();
}
}
})
);
const statusnow = computed(() => (): number => {
if (recOrderCart.value) {
return recOrderCart.value.status
return recOrderCart.value.status;
}
return 0
})
return 0;
});
function mounted() {
// Inizializza
load()
load();
}
function getOrdersCart() {
if (props.iscash) {
return productStore.getOrdersCartById(props.idOrdersCart)
return productStore.getOrdersCartById(props.idOrdersCart);
} else {
return productStore.getCart()
return productStore.getCart();
}
}
function getItemsCart() {
const cart = getOrdersCart()
return cart.items || null
const cart = getOrdersCart();
return cart.items || null;
}
function getNumItems(): number {
const cart = getOrdersCart()
if (cart.items)
return cart.items.length || 0
else
return 0
const cart = getOrdersCart();
if (cart.items) return cart.items.length || 0;
else return 0;
}
function getCart(): ICart {
return getOrdersCart()
return getOrdersCart();
}
function getNote() {
const cart = getOrdersCart()
return cart.note
const cart = getOrdersCart();
return cart.note;
}
function change_field(fieldname: string) {
if (myrec.value[fieldname] !== oldrec.value[fieldname]) {
myrec.value[fieldname] = oldrec.value[fieldname]
myrec.value[fieldname] = oldrec.value[fieldname];
const mydata = {
[fieldname]: myrec.value[fieldname]
}
[fieldname]: myrec.value[fieldname],
};
const aggiorna = fieldname !== 'status'
tools.saveFieldToServer($q, 'carts', mycart.value._id, mydata, aggiorna)
oldrec.value[fieldname] = myrec.value[fieldname]
const aggiorna = fieldname !== 'status';
tools.saveFieldToServer($q, 'carts', mycart.value._id, mydata, aggiorna);
oldrec.value[fieldname] = myrec.value[fieldname];
}
}
function myTotalPrice(): string {
if (productStore.cart && productStore.cart.totalPrice) {
return productStore.cart.totalPrice.toFixed(2)
return productStore.cart.totalPrice.toFixed(2);
} else {
return '0'
return '0';
}
}
function myTotalQty(): number {
if (productStore.cart) {
return productStore.cart.totalQty!
return productStore.cart.totalQty!;
} else {
return 0
return 0;
}
}
async function aggiornaCarrello() {
if (mycart.value) {
recOrderCart.value = await productStore.CreateOrdersCart({
cart_id: mycart.value._id,
status: 0,
note: note.value,
});
}
}
async function load() {
if (isfinishLoading.value) {
console.log('Load CCART')
mycart.value = getCart()
myrec.value = Object.keys(mycart)
oldrec.value = myrec.value
note.value = mycart.value.note!
console.log('Load CCART');
mycart.value = getCart();
myrec.value = Object.keys(mycart);
oldrec.value = myrec.value;
note.value = mycart.value.note!;
// codice_sconto.value = mycart.value.codice_sconto!;
const options = {};
if (mycart.value) {
recOrderCart.value = await productStore.CreateOrdersCart({ cart_id: mycart.value._id, status: 0, note: note.value })
}
aggiornaCarrello();
// console.log('myrec', myrec.value)
endload.value = true
endload.value = true;
}
}
function CanBeShipped() {
return productStore.cart.items ? productStore.cart.items.filter((rec: any) => rec.order.product.canBeShipped).length : false
return productStore.cart.items
? productStore.cart.items.filter((rec: any) => rec.order.product.canBeShipped)
.length
: false;
}
function CanBeBuyOnline() {
return productStore.cart.items ? productStore.cart.items.filter((rec: any) => rec.order.product.canBeBuyOnline).length : false
return productStore.cart.items
? productStore.cart.items.filter((rec: any) => rec.order.product.canBeBuyOnline)
.length
: false;
}
function getnumsteps() {
let numsteps = 1
let numsteps = 1;
if (CanBeShipped())
numsteps++
if (CanBeBuyOnline())
numsteps++
if (CanBeShipped()) numsteps++;
if (CanBeBuyOnline()) numsteps++;
return numsteps
return numsteps;
}
function docheckout() {
// Può essere spedito?
if (CanBeShipped()) {
@@ -188,40 +200,53 @@ export default defineComponent({
message: t('ecomm.conferma_acq', { qty: myTotalQty() }),
ok: {
label: t('dialog.yes'),
push: true
push: true,
},
cancel: {
label: t('dialog.cancel')
label: t('dialog.cancel'),
},
title: t('ecomm.order')
title: t('ecomm.order'),
}).onOk(async () => {
const status = shared_consts.OrderStatus.CHECKOUT_SENT
const status = shared_consts.OrderStatus.CHECKOUT_SENT;
recOrderCart.value = await productStore.CreateOrdersCart({ cart_id: mycart.value._id, status, note: note.value })
try {
caricamentodati.value = true;
// statusnow.value = myordercart ? myordercart.status : 0
recOrderCart.value = await productStore.CreateOrdersCart({
cart_id: mycart.value._id,
status,
note: note.value,
codice_sconto: codice_sconto.value,
});
if (recOrderCart.value.status === status) {
tools.showPositiveNotif($q, t('ecomm.ord_confirmed'))
setTimeout(() => {
$router.push('/orderinfo')
}, 2000)
} else {
tools.showNegativeNotif($q, t('ecomm.ord_not_confirmed'))
// statusnow.value = myordercart ? myordercart.status : 0
if (recOrderCart.value.status === status) {
tools.showPositiveNotif($q, t('ecomm.ord_confirmed'));
setTimeout(() => {
$router.push('/orderinfo');
}, 2000);
} else {
tools.showNegativeNotif($q, t('ecomm.ord_not_confirmed'));
}
} catch (e) {
console.error('Err', e);
} finally {
caricamentodati.value = false;
}
// change_field('status')
// change_field('status')
})
});
}
function getActualIdStorehouse(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.storehouses.length === 1) {
return myprod.storehouses[0]._id
return myprod.storehouses[0]._id;
} else {
// Ottieni il negozio attualmente scelto !
return ''
return '';
}
}
@@ -229,10 +254,10 @@ export default defineComponent({
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.gasordine) {
return myprod.gasordine._id
return myprod.gasordine._id;
} else {
// Ottieni il gasordine attualmente scelto !
return ''
return '';
}
}
@@ -242,18 +267,111 @@ export default defineComponent({
const myprod = productStore.getProductByCode(lowerSearchText);
if (myprod && myprod.active) {
const myorder: IOrder = {
quantity: 1, quantitypreordered: 0,
TotalPriceProduct: 0, TotalPriceProductCalc: 0, price: 0,
quantity: 1,
quantitypreordered: 0,
TotalPriceProduct: 0,
TotalPriceProductCalc: 0,
price: 0,
idStorehouse: getActualIdStorehouse(myprod),
idGasordine: getActualGasordine(myprod),
}
await productStore.addtoCartBase({ $q, t, id: myprod._id, order: myorder, addqty: true })
search.value = ''
load()
};
await productStore.addtoCartBase({
$q,
t,
id: myprod._id,
order: myorder,
addqty: true,
});
search.value = '';
load();
}
}
onMounted(mounted)
function esportaCsv() {
const csvRows: string[] = [];
const sep = '|';
const headers = `Num${sep}Codice${sep}Titolo${sep}Quantità${sep}Prezzo${sep}Totale\n`;
csvRows.push(headers);
let index = 1
for (const itemorder of getItemsCart()) {
const productCode = itemorder.order.product?.productInfo.code || '';
const productName = itemorder.order.product?.productInfo.name || '';
const quantity = itemorder.order.quantity + itemorder.order.quantitypreordered;
const price = Number(itemorder.order.price).toFixed(2);
const totalPrice = (price * quantity).toFixed(2);
const row = `${index}${sep}${productCode}${sep}${productName}${sep}${quantity}${sep}${price}${sep}${totalPrice}\n`;
csvRows.push(row);
index++;
}
const totalQuantity = getItemsCart().reduce((sum, itemorder) => sum + itemorder.order.quantity + itemorder.order.quantitypreordered, 0);
const totalAmount = getItemsCart().reduce((sum, itemorder) => sum + parseFloat((itemorder.order.price * (itemorder.order.quantity + itemorder.order.quantitypreordered)).toFixed(2)), 0);
const totalRow = `${sep}${sep}Totale${sep}${totalQuantity}${sep}${sep}${totalAmount.toFixed(2)}\n`;
csvRows.push(totalRow);
console.log('csvRows', csvRows)
const csvContent = csvRows.join('').trim();
const today = new Date();
tools.createAndDownloadCSVFromData(
csvContent,
`ordine_${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`
);
}
async function applicaSconto(codice: string) {
try {
caricamentodati.value = true;
const rissconto = await productStore.ApplicaSconto({
cart_id: mycart.value._id,
codice_sconto: codice,
});
if (rissconto) {
if (rissconto.msg) {
tools.showNeutralNotif($q, `${rissconto.msg}`);
} else if (rissconto.valido && rissconto.mycart) {
tools.showPositiveNotif($q, 'Sconto Applicato!');
} else {
tools.showNegativeNotif($q, `${rissconto.errmsg}`);
}
codice_sconto.value = '';
if (rissconto.mycart) recOrderCart.value = rissconto.mycart;
}
} catch (error) {
console.log('error ApplicaSconto', error);
tools.showNegativeNotif($q, `Sconto Non Applicato! ${error.message}`);
codice_sconto.value = '';
} finally {
caricamentodati.value = false;
}
}
async function confermaCodiceSconto() {
await applicaSconto(codice_sconto.value);
}
async function rimuoviCodiceSconto() {
$q.dialog({
message: `Vuoi rimuovere il codice sconto "${recOrderCart.value.codice_sconto}"?`,
ok: {
label: 'Si',
push: true,
},
cancel: {
label: 'No',
},
}).onOk(async () => {
await applicaSconto('RIMUOVI');
});
}
onMounted(mounted);
return {
userStore,
@@ -277,6 +395,11 @@ export default defineComponent({
insertArticolo,
globalStore,
isfinishLoading,
}
}
})
esportaCsv,
codice_sconto,
confermaCodiceSconto,
rimuoviCodiceSconto,
caricamentodati,
};
},
});

View File

@@ -1,107 +1,204 @@
<template>
<q-spinner v-if="!endload" color="primary" size="3em" :thickness="2" />
<div v-if="isfinishLoading && endload">
<CSelectUserActive></CSelectUserActive>
<div v-if="recOrderCart" class="panel">
<div>
<div class="container">
<div
style="min-height: 100vh; display: flex; justify-content: center; align-items: center"
>
<q-spinner
v-if="!endload"
color="primary"
size="3em"
:thickness="2"
/>
<div v-if="isfinishLoading && endload">
<CSelectUserActive></CSelectUserActive>
<div
v-if="recOrderCart"
class="panel"
>
<div>
<div class="container">
<div
class="q-pa-sm col items-start q-gutter-xs"
v-for="(itemorder, index) in getItemsCart()"
:key="index"
>
<CSingleCart
:order="itemorder.order"
:idOrdersCart="recOrderCart._id"
:showall="true"
/>
</div>
</div>
<q-separator></q-separator>
<div
class="q-pa-sm col items-start q-gutter-xs"
v-for="(itemorder, index) in getItemsCart()"
:key="index"
class="col-6 q-mr-sm"
style="text-align: right"
>
<CSingleCart
:order="itemorder.order"
:idOrdersCart="recOrderCart._id"
:showall="true"
/>
<span class="text-grey q-mr-xs">{{ $t('ecomm.totale') }}:</span>
<span class="text-subtitle1 q-mr-sm"> {{ myTotalPrice() }}</span>
</div>
<q-separator />
<div
v-if="getNumItems() > 0"
style="max-width: 500px"
class="row items-center q-gutter-x-xs"
>
<div class="column items-center q-gutter-x-xs">
<div
v-if="recOrderCart.codice_sconto"
class="row items-center q-gutter-x-xs"
>
<div
class="text-subtitle1 q-mr-sm q-pa-xs"
style="background-color: #f0f0f0; border-radius: 4px"
>
{{ $t('ecomm.sconto_appl') }}
</div>
<q-btn
dense
flat
icon="fas fa-times"
color="negative"
@click="rimuoviCodiceSconto"
>
Rimuovi {{ recOrderCart.codice_sconto }}
</q-btn>
</div>
</div>
<div v-if="!recOrderCart.codice_sconto" class="row">
<q-input
v-model="codice_sconto"
:label="$t('ecomm.codice_sconto')"
style="width: 200px"
filled
dense
@keyup.enter="confermaCodiceSconto"
/>
<q-btn
:disabled="!codice_sconto || codice_sconto.trim() === ''"
:label="$t('ecomm.applica_sconto')"
icon="fas fa-check-circle"
color="primary"
class="q-mt-sm"
@click="confermaCodiceSconto"
/>
</div>
<!--<q-btn
v-if="recOrderCart.codice_sconto"
:label="$t('ecomm.rimuovi_sconto')"
icon="fas fa-times-circle"
color="negative"
class="q-mt-sm"
@click="rimuoviCodiceSconto"
/>-->
</div>
<q-input
v-if="getNumItems() > 0"
v-model="note"
style="min-width: 400px"
class="q-mt-md"
:label="$t('ecomm.note')"
filled
dense
debounce="1000"
autogrow
@input="change_field('note')"
>
</q-input>
<div
v-if="recOrderCart.note_ordine_gas"
class="note_ordine_gas"
v-html="recOrderCart.note_ordine_gas"
></div>
</div>
<div class="text-center">
<q-btn
v-if="
recOrderCart &&
recOrderCart.status < shared_consts.OrderStatus.CHECKOUT_SENT
"
icon="fas fa-file-csv"
flat
filled
:label="$t('ecomm.esporta_csv')"
class="q-mb-sm"
@click="esportaCsv()"
></q-btn>
<q-btn
v-if="
recOrderCart &&
recOrderCart.status < shared_consts.OrderStatus.CHECKOUT_SENT
"
rounded
icon="fas fa-shopping-cart"
color="green"
:label="$t('ecomm.completa_ord')"
class="q-mb-sm"
:disabled="myTotalQty() < 1"
@click="completeOrder()"
></q-btn>
</div>
<div class="center-text">
<br />
<div
class="q-ma-sm q-pa-sm text-h8 text-grey"
v-if="globalStore && globalStore.site.ecomm.NoteExtraOnCart"
>
{{ globalStore.site.ecomm.NoteExtraOnCart }}
</div>
</div>
<q-separator></q-separator>
<div class="col-6 q-mr-sm" style="text-align: right">
<span class="text-grey q-mr-xs">{{ $t('ecomm.totale') }}:</span>
<span class="text-subtitle1 q-mr-sm"> {{ myTotalPrice() }}</span>
</div>
<q-input
v-if="getNumItems() > 0"
v-model="note"
style="max-width: 400px"
:label="$t('ecomm.note')"
filled
dense
debounce="1000"
autogrow
@input="change_field('note')"
>
</q-input>
<div
v-if="recOrderCart.note_ordine_gas"
class="note_ordine_gas"
v-html="recOrderCart.note_ordine_gas"
>
</div>
</div>
<div class="text-center">
<q-btn
v-if="
recOrderCart &&
recOrderCart.status < shared_consts.OrderStatus.CHECKOUT_SENT
"
rounded
icon="fas fa-shopping-cart"
color="green"
:label="$t('ecomm.completa_ord')"
class="q-mb-sm"
:disabled="myTotalQty() < 1"
@click="completeOrder()"
></q-btn>
</div>
<div class="center-text">
<br />
<div
class="q-ma-sm q-pa-sm text-h8 text-grey"
v-if="globalStore && globalStore.site.ecomm.NoteExtraOnCart"
>
{{ globalStore.site.ecomm.NoteExtraOnCart }}
</div>
</div>
</div>
<div v-else style="text-align: center" class="text-grey">
{{ $t('ecomm.carrello_vuoto') }}
</div>
<br />
<div
class="q-gutter-y-md column text-center q-mx-auto"
style="width: 350px; max-width: 100%"
>
<q-input
filled
stack-label
dense
:label="$t('ecomm.code_add_to_cart')"
v-model="search"
class="q-ml-md"
@keyup.enter="insertArticolo()"
<div
v-else
style="text-align: center"
class="text-grey"
>
<template v-slot:append>
<q-icon
class="insert"
name="fas fa-shopping-cart"
color="green"
@click="insertArticolo()"
/>
</template>
</q-input>
{{ $t('ecomm.carrello_vuoto') }}
</div>
<br />
<div
class="q-gutter-y-md column text-center q-mx-auto"
style="width: 350px; max-width: 100%"
>
<q-input
filled
stack-label
dense
:label="$t('ecomm.code_add_to_cart')"
v-model="search"
class="q-ml-md"
@keyup.enter="insertArticolo()"
>
<template v-slot:append>
<q-icon
class="insert"
name="fas fa-shopping-cart"
color="green"
@click="insertArticolo()"
/>
</template>
</q-input>
</div>
</div>
<div
v-if="caricamentodati"
class="overlay"
>
<q-spinner-hourglass
color="primary"
size="50px"
/>
</div>
</div>
</template>
<script lang="ts" src="./CCart.ts">
</script>
<script lang="ts" src="./CCart.ts"></script>
<style lang="scss" scoped>
@import './CCart';

View File

@@ -44,6 +44,7 @@ export default defineComponent({
const myrec = ref(<any[string]>[])
const oldrec = ref(<any[string]>[])
const note = ref('')
const codice_sconto = ref('')
const note_per_gestore = ref('')
const note_per_admin = ref('')
const endload = ref(false)
@@ -129,6 +130,7 @@ export default defineComponent({
if (recOrderCart.value) {
oldrec.value = recOrderCart.value
myrec.value.note = recOrderCart.value.note!
myrec.value.codice_sconto = recOrderCart.value.codice_sconto!
myrec.value.note_per_gestore = recOrderCart.value.note_per_gestore!
myrec.value.note_per_admin = recOrderCart.value.note_per_admin!
}

View File

@@ -97,6 +97,7 @@
<div v-else>
<q-field> Note: {{ myrec.note }} </q-field>
<q-field color="red"> Note per il Gestore: {{ myrec.note_per_gestore }} </q-field>
<q-field color="blue"> Codice Sconto: {{ myrec.codice_sconto }} </q-field>
</div>
<q-input
@@ -111,6 +112,18 @@
@update:model-value="change_field('note_per_gestore')"
>
</q-input>
<q-input
v-if="editOn && tools.isManager() && getNumItems() > 0"
v-model="myrec.codice_sconto"
style="max-width: 400px"
:label="t('ecomm.codice_sconto')"
filled
dense
debounce="1000"
autogrow
@update:model-value="change_field('codice_sconto')"
>
</q-input>
<q-input
v-if="editOn && tools.isAdmin() && getNumItems() > 0"
v-model="myrec.note_per_admin"

View File

@@ -828,6 +828,7 @@ export default defineComponent({
: [
'pos',
'image',
'addtocart',
'name',
'authors',
'isbn',
@@ -835,7 +836,6 @@ export default defineComponent({
'stato',
'date_pub',
'pagine',
// 'trafiletto',
'quantity',
'prezzo',
]

View File

@@ -47,7 +47,198 @@
.qta{
font-size: 1.15rem;
font-weight: bold;
border-radius: 12px;
padding: 8px;
}
.autori{
font-style: italic;
}
.elimina-btn{
width: 36px;
height: 36px;
border: none;
border-radius: 12px;
background: linear-gradient(135deg, #ff3860, #e61e4d); /*negative gradient */
color: white;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.quantity-btn {
width: 36px;
height: 36px;
border: none;
border-radius: 12px;
background: linear-gradient(135deg, #34c759, #2ecc71); /*positive gradient */
&[data-gradiente="negative"] {
background: linear-gradient(135deg, #ff3860, #e61e4d); /*negative gradient */
}
color: white;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.quantity-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
.quantity-btn:active {
transform: translateY(0);
}
.quantity-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.quantity-display {
min-width: 60px;
text-align: center;
font-size: 1.4rem;
font-weight: 600;
color: #1f2937;
background: #f8fafc;
border-radius: 12px;
padding: 12px 16px;
border: 2px solid #e2e8f0;
transition: all 0.3s ease;
}
.quantity-display.updating {
transform: scale(1.1);
border-color: #667eea;
background: #eff6ff;
}
.remove-btn {
background: linear-gradient(135deg, #ef4444, #dc2626);
color: white;
border: none;
border-radius: 12px;
padding: 12px 20px;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
margin-left: auto;
}
.remove-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(239, 68, 68, 0.3);
}
.cart-summary {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border-radius: 20px;
padding: 24px;
margin-top: 32px;
text-align: center;
opacity: 1;
transition: all 0.3s ease;
}
.cart-summary.hidden {
opacity: 0;
transform: translateY(20px);
}
.total-amount {
font-size: 2rem;
font-weight: 700;
margin-bottom: 8px;
}
.total-items {
opacity: 0.9;
margin-bottom: 20px;
}
.checkout-btn {
background: rgba(255, 255, 255, 0.2);
border: 2px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 16px 32px;
border-radius: 12px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.checkout-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.empty-cart {
text-align: center;
padding: 60px 20px;
color: #6b7280;
opacity: 0;
transition: opacity 0.5s ease;
}
.empty-cart.show {
opacity: 1;
}
.empty-cart i {
font-size: 4rem;
margin-bottom: 20px;
opacity: 0.5;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.pulse {
animation: pulse 0.3s ease-in-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeInUp 0.5s ease forwards;
}
@media (max-width: 768px) {
.product-content {
flex-direction: column;
text-align: center;
}
.quantity-controls {
justify-content: center;
}
.remove-btn {
margin: 16px auto 0;
}
}

View File

@@ -1,16 +1,16 @@
import { tools } from '../../store/Modules/tools'
import { CCardState } from '../CCardState'
import { CCopyBtn } from '../CCopyBtn'
import { tools } from '../../store/Modules/tools';
import { CCardState } from '../CCardState';
import { CCopyBtn } from '../CCopyBtn';
import type { IOrder} from '@src/model';
import { IOperators, IProduct } from '@src/model'
import type { PropType} from 'vue';
import { defineComponent, toRef, ref, watch, onMounted } from 'vue'
import { CTitleBanner } from '@src/components/CTitleBanner'
import { useProducts } from '@store/Products'
import { useI18n } from 'vue-i18n'
import { useQuasar } from 'quasar'
import { loadRouteLocation } from 'vue-router'
import type { IOrder } from '@src/model';
import { IOperators, IProduct } from '@src/model';
import type { PropType } from 'vue';
import { defineComponent, toRef, ref, watch, onMounted } from 'vue';
import { CTitleBanner } from '@src/components/CTitleBanner';
import { useProducts } from '@store/Products';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import { loadRouteLocation } from 'vue-router';
export default defineComponent({
name: 'CSingleCart',
@@ -42,11 +42,11 @@ export default defineComponent({
},
components: { CTitleBanner, CCardState, CCopyBtn },
setup(props, { emit }) {
const products = useProducts()
const order = toRef(props, 'order')
const { t } = useI18n()
const products = useProducts();
const order = toRef(props, 'order');
const { t } = useI18n();
const $q = useQuasar()
const $q = useQuasar();
const orderQuantity = ref(<number | undefined>undefined);
const weight = ref(<number | undefined>undefined);
@@ -54,161 +54,179 @@ export default defineComponent({
const orderQuantityPreordered = ref(<number | undefined>undefined);
const orderTotalPriceProduct = ref(<number | undefined>undefined);
const enableQty = ref(false)
const endload = ref(false)
const enableQtyPreordered = ref(false)
const enableChangeTotalPrice = ref(false)
const enableQty = ref(false);
const endload = ref(false);
const enableQtyPreordered = ref(false);
const enableChangeTotalPrice = ref(false);
watch(orderQuantity, (newValue: any) => {
if (!newValue)
order.value.quantity = 0
else
order.value.quantity = parseFloat(newValue);
if (!newValue) order.value.quantity = 0;
else order.value.quantity = parseFloat(newValue);
enableChangeTotalPrice.value = false
enableChangeTotalPrice.value = false;
});
watch(weight, (newValue: any) => {
if (order.value.product) {
if (!newValue)
order.value.product.productInfo.weight = 0
else
order.value.product.productInfo.weight = parseFloat(newValue);
if (!newValue) order.value.product.productInfo.weight = 0;
else order.value.product.productInfo.weight = parseFloat(newValue);
}
enableChangeTotalPrice.value = false
enableChangeTotalPrice.value = false;
});
watch(price, (newValue: any) => {
if (order.value) {
if (!newValue)
order.value.price = 0
else
order.value.price = parseFloat(newValue);
if (!newValue) order.value.price = 0;
else order.value.price = parseFloat(newValue);
}
enableChangeTotalPrice.value = false
enableChangeTotalPrice.value = false;
});
watch(orderQuantityPreordered, (newValue: any) => {
if (!newValue)
order.value.quantitypreordered = 0
else
order.value.quantitypreordered = parseFloat(newValue);
if (!newValue) order.value.quantitypreordered = 0;
else order.value.quantitypreordered = parseFloat(newValue);
enableChangeTotalPrice.value = false
enableChangeTotalPrice.value = false;
});
watch(orderTotalPriceProduct, (newValue: any) => {
if (!newValue)
order.value.TotalPriceProduct = 0
else
order.value.TotalPriceProduct = parseFloat(newValue);
if (!newValue) order.value.TotalPriceProduct = 0;
else order.value.TotalPriceProduct = parseFloat(newValue);
});
watch(() => props.order.TotalPriceProduct, (newValue: any) => {
if (!newValue)
orderTotalPriceProduct.value = 0
else
orderTotalPriceProduct.value = parseFloat(newValue);
});
watch(
() => props.order.TotalPriceProduct,
(newValue: any) => {
if (!newValue) orderTotalPriceProduct.value = 0;
else orderTotalPriceProduct.value = parseFloat(newValue);
}
);
function myimgclass() {
if (props.showall) {
return 'imgNormal'
return 'imgNormal';
} else {
return 'imgSmall'
return 'imgSmall';
}
}
function qtyInCart() {
return props.order.quantity + props.order.quantitypreordered;
}
async function addsubqty(addqty: boolean, subqty: boolean) {
if (products.isQtyAvailableByOrder(props.order)) {
if (addqty) {
if (props.order.quantity >= 100)
return false
if (props.order.quantity >= 100) return false;
}
if (subqty) {
if (props.order.quantity === 0)
return false
if (props.order.quantity === 0) return false;
}
} else {
if (products.isInPreorderByOrder(props.order)) {
if (addqty) {
if (props.order.quantitypreordered >= 100)
return false
if (props.order.quantitypreordered >= 100) return false;
}
if (subqty) {
if (props.order.quantitypreordered === 0)
return false
if (props.order.quantitypreordered === 0) return false;
}
}
}
return await products.addSubQtyToItem({
addqty,
subqty,
order: props.order,
}).then((res: any) => {
if (res.risult) {
if (res.myord) {
order.value.quantity = res.myord.quantity
order.value.quantitypreordered = res.myord.quantitypreordered
return await products
.addSubQtyToItem({
addqty,
subqty,
order: props.order,
})
.then((res: any) => {
if (res.risult) {
if (res.myord) {
order.value.quantity = res.myord.quantity;
order.value.quantitypreordered = res.myord.quantitypreordered;
}
}
}
})
});
}
function isApplicatoSconto() {
const totalipotetico = order.value.product!.price * (order.value.quantity + order.value.quantitypreordered)
const totalipotetico =
order.value.product!.price *
(order.value.quantity + order.value.quantitypreordered);
if (totalipotetico.toFixed(2) > order.value.TotalPriceProduct.toFixed(2)) {
return true
return true;
}
return false
return false;
}
function removeFromCard() {
products.removeFromCart({ order: order.value })
$q.dialog({
title: order.value.product.productInfo.name,
message: 'Sicuro di voler rimuovere il prodotto dal carrello?',
ok: {
label: 'Rimuovi',
color: 'negative',
rounded: true,
},
cancel: {
label: 'Annulla',
color: 'primary',
rounded: true,
},
}).onOk(() => {
products.removeFromCart({ order: order.value });
});
}
async function updateOrder(paramstoupdate: any) {
endload.value = false
endload.value = false;
if (enableChangeTotalPrice.value) {
paramstoupdate = { ...paramstoupdate, TotalPriceProduct: order.value.TotalPriceProduct }
paramstoupdate = {
...paramstoupdate,
TotalPriceProduct: order.value.TotalPriceProduct,
};
}
const myOrdersCart = await products.updateOrderByOrder(props.idOrdersCart, order.value._id, paramstoupdate)
emit('update')
mounted()
const myOrdersCart = await products.updateOrderByOrder(
props.idOrdersCart,
order.value._id,
paramstoupdate
);
emit('update');
mounted();
}
function getRisparmio(): string {
return ((order.value.product!.price * order.value.quantity) - order.value.TotalPriceProduct).toFixed(2)
return (
order.value.product!.price * order.value.quantity -
order.value.TotalPriceProduct
).toFixed(2);
}
function mounted() {
endload.value = false
weight.value = props.order.product?.productInfo.weight
price.value = props.order.price
endload.value = false;
weight.value = props.order.product?.productInfo.weight;
price.value = props.order.price;
if (props.order.quantity !== 0) {
orderQuantity.value = props.order.quantity
enableQty.value = true
orderQuantity.value = props.order.quantity;
enableQty.value = true;
}
if (props.order.quantitypreordered !== 0) {
orderQuantityPreordered.value = props.order.quantitypreordered
enableQtyPreordered.value = true
orderQuantityPreordered.value = props.order.quantitypreordered;
enableQtyPreordered.value = true;
}
orderTotalPriceProduct.value = props.order.TotalPriceProduct
endload.value = true
orderTotalPriceProduct.value = props.order.TotalPriceProduct;
endload.value = true;
}
function changeTotalPrice() {
console.log('changeTotalPrice')
enableChangeTotalPrice.value = true
console.log('changeTotalPrice');
enableChangeTotalPrice.value = true;
}
onMounted(mounted)
onMounted(mounted);
return {
myimgclass,
@@ -229,6 +247,7 @@ export default defineComponent({
changeTotalPrice,
orderTotalPriceProduct,
endload,
}
qtyInCart,
};
},
})
});

View File

@@ -86,26 +86,30 @@
<div class="row q-mb-xs no-wrap items-center centeritems">
<q-btn
v-if="showall && !nomodif && products.CanDeleteIfSub(order)"
icon="fas fa-trash"
color="negative"
icon="fas fa-trash-alt"
round
size="xs"
size="sm"
class="elimina-btn"
@click="removeFromCard"
>
</q-btn>
<q-btn
v-else-if="showall && !nomodif"
:disable="!products.enableSubQty(order)"
size="sm"
icon="fas fa-cart-arrow-down"
:color="products.enableSubQty(order) ? 'negative' : 'grey'"
@click="addsubqty(false, true)"
rounded
:label="
<!--
:label="
t('products.subcart', {
qta: products.qtaNextSub(order, order.product),
})
"
-->
<q-btn
v-else-if="!nomodif"
:disable="!products.enableSubQty(order)"
size="sm"
class="quantity-btn"
data-gradiente="negative"
:icon="qtyInCart() === 1 ? 'fas fa-trash': 'fas fa-minus'"
:color="products.enableSubQty(order) ? undefined : 'grey'"
@click="qtyInCart() === 1 ? removeFromCard(): addsubqty(false, true)"
rounded
></q-btn>
<div v-if="editmode">
<q-input
@@ -115,6 +119,7 @@
debounce="500"
borderless
rounded
class="quantity-display"
dense
:label="t('products.quantity')"
></q-input>
@@ -124,6 +129,7 @@
autofocus
debounce="500"
borderless
class="quantity-display"
rounded
densep
:label="t('ecomm.preord')"
@@ -159,24 +165,25 @@
</q-btn>
</div>
<div
v-else-if="showall"
v-else
:class="`q-mx-sm text-blue-14 qta`"
>
{{ order.quantity + order.quantitypreordered }}
</div>
<q-btn
v-if="showall && !nomodif"
icon-right="fas fa-cart-plus"
color="positive"
:disable="!products.enableAddQty(order, order.product)"
rounded
size="sm"
:label="
<!-- :label="
t('products.addcart', {
qta: products.qtaNextAdd(order, order.product),
})
"
-->
<q-btn
v-if="!nomodif"
icon-right="fas fa-plus"
class="quantity-btn"
:disable="!products.enableAddQty(order, order.product)"
rounded
size="sm"
@click="addsubqty(true, false)"
>
</q-btn>
@@ -229,7 +236,7 @@
</div>
</q-item-label>
</q-item-section>
<q-item-section side>
<!--<q-item-section side>
<q-item-label>
<div class="col-2">
<q-btn
@@ -243,7 +250,7 @@
</q-btn>
</div>
</q-item-label>
</q-item-section>
</q-item-section>-->
<!--<q-item-section side top>
<q-item-label caption>meta</q-item-label>