- Creazione "AbitareGliIblei"

- Mappa Interattiva con i markers
This commit is contained in:
Surya Paolo
2024-07-31 15:02:30 +02:00
parent 3ab18b591f
commit 822585cf33
252 changed files with 3600294 additions and 4300 deletions

View File

@@ -7,6 +7,8 @@
// @ts-ignore
import { boot } from 'quasar/wrappers'
import { useGlobalStore } from '@src/store/globalStore';
export default boot(({ app, router }) => {
// ******************************************
// *** Per non permettere di accedere alle pagine in cui è necessario essere Loggati ! ***
@@ -16,6 +18,39 @@ export default boot(({ app, router }) => {
// runs the default `next()` callback but also triggers
// the subsequent Middleware function.
router.beforeEach((to, from, next) => {
console.log('beforeEach ROUTER')
// Execute your command before each navigation
// executeCommand();
const globalStore = useGlobalStore()
try {
globalStore.editOn = false
} catch(e) {
}
next()
/* const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
*/
//if (to.matched.some(record => record.meta.requiresAuth) && !userStore.isLogged) {
// next({ name: 'login', query: { next: to.fullPath } })
//} else {
// next()
//}
// Continue with the navigation
});
/* router.beforeEach((to, from, next) => {
var accessToken = store.state.session.userSession.accessToken
// ESTANDO LOGEADO

View File

@@ -0,0 +1,20 @@
import { boot } from 'quasar/wrappers';
import { VueHtmlToPaper } from 'vue-html-to-paper';
const options = {
name: '_blank',
specs: [
'fullscreen=yes',
'titlebar=yes',
'scrollbars=yes'
],
styles: [
'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css',
// Aggiungi qui i link ai tuoi stili CSS, se necessario
]
};
// Definisce un componente di boot per Vue
export default boot(({ app }) => {
app.use(VueHtmlToPaper, options);
});

View File

@@ -164,6 +164,8 @@ export const shared_consts = {
MAPPA: 350,
MAPPAUTENTI: 360,
MAPPACOMUNI: 370,
MAPPAGETCOORDINATE: 380,
EDITADDRESSBYCOORD: 390,
},
QUERYTYPE_MYGROUP: 1,
@@ -1764,6 +1766,14 @@ export const shared_consts = {
value: 370,
label: 'MAPPACOMUNI',
},
{
value: 380,
label: 'MAPPA GET COORD',
},
{
value: 390,
label: 'EDIT ADDRESS BY COORD',
},
],

View File

@@ -18,6 +18,7 @@ export default defineComponent({
formato: [],
Categoria: [],
Editore: [],
pdf: false,
}),
},
},

View File

@@ -65,6 +65,7 @@ export default defineComponent({
formato: [],
Categoria: [],
Editore: [],
pdf: false,
}),
},
},

View File

@@ -27,7 +27,7 @@
v-if="complete"
position="bottom-right"
:offset="[18, 0]"
style="z-index: 1000;"
style="z-index: 1000"
>
<q-btn
fab
@@ -57,11 +57,6 @@
}"
@click="click_opendetail()"
>
<!--@click="
complete
? toggleFullScreen
: naviga(`/catalogo/` + myproduct._id + '/' + cosa)
"-->
<div
class="absolute transparent"
style="left: 90%; top: -18px; transform: translateX(-50%)"
@@ -77,6 +72,12 @@
</div>
</q-img>
<!--@click="
complete
? toggleFullScreen
: naviga(`/catalogo/` + myproduct._id + '/' + cosa)
"-->
<div class="scheda-book">
<q-card-title>
<span class="book-title" :data-col="options.quante_col">
@@ -324,7 +325,7 @@
style="align-items: center"
>
<span class="q-mr-sm">{{ $t('products.editore') }}:</span>
<q-badge
<q-badge
:color="
tools.getRecByVersioneProd(variazione.versione).color
"

View File

@@ -52,6 +52,7 @@ export default defineComponent({
formato: [],
Categoria: [],
Editore: [],
pdf: false,
}),
},
},

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div>
<CCatalogoCard
:id="id"
:complete="complete"

View File

@@ -1,10 +1,11 @@
<template>
<div class="q-ma-xs">
<div
v-if="tools.visualizzaHomeApp()"
v-if="true"
class="row q-my-xs shadow"
style="border-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.12)"
>
<!--<div class="col-md-3 col-lg-3 col-sm-12 col-xs-12 box_4" style="border-left: 1px solid #efefef;"
v-bind:class="{'border-top': $q.platform.is.mobile}">
<q-card class="no-shadow q-pa-sm">

View File

@@ -35,6 +35,11 @@ export default defineComponent({
required: false,
default: true,
},
showMap: {
type: Boolean,
required: false,
default: false,
},
noButtAdd: {
type: Boolean,
required: false,
@@ -81,7 +86,6 @@ export default defineComponent({
const strextra = ref('')
const myoptions = ref(<any>[])
const col = ref(<IColGridTable>{})
/*

View File

@@ -60,6 +60,7 @@
:prop_SortFieldsAvailable="mySortFieldsAvailable"
:labelBtnAddExtra="noButtAdd ? `` : (ind >= 0) ? `Aggiungi ` + costanti.MAINCARDS[ind].strsingolo : ''"
:extraparams="tools.extraparams(table, {myrecfiltertoggle})"
:prop_showMap="showMap"
>
</CGridTableRec>
</div>

View File

@@ -46,3 +46,9 @@
.q-table__top{
padding-top: 0 !important;
}
.right-align-dialog .q-dialog {
right: 0; /* Allinea a destra */
left: auto; /* Disabilita l'allineamento a sinistra */
margin: 0; /* Rimuovi qualsiasi margine */
}

View File

@@ -1,4 +1,4 @@
import { defineComponent, PropType, ref, watch, toRef, onMounted, toRefs, computed, inject } from 'vue'
import { defineComponent, PropType, ref, watch, toRef, onMounted, onBeforeUnmount, toRefs, computed, inject, onUnmounted } from 'vue'
import { useI18n } from '@src/boot/i18n'
import { tools } from '../../store/Modules/tools'
@@ -25,6 +25,7 @@ import { CMyUser } from '../CMyUser'
import { CMyGroups } from '../CMyGroups'
import { CMyFieldDb } from '../CMyFieldDb'
import { CMyRecCard } from '../CMyRecCard'
import { CMapByTable } from '../CMapByTable'
import { CMyRecGrpCard } from '../CMyRecGrpCard'
import { CMyRecCircuitCard } from '../CMyRecCircuitCard'
import { CMySelect } from '../CMySelect'
@@ -40,7 +41,12 @@ import { CMyCardPopup } from '@/components/CMyCardPopup'
import { CMyCardService } from '@/components/CMyCardService'
import { CMyCardGrpPopup } from '@/components/CMyCardGrpPopup'
import { CMyCardCircuitPopup } from '@/components/CMyCardCircuitPopup'
import { useRouter } from 'vue-router'
import { onBeforeRouteLeave, onBeforeRouteUpdate, beforeRouteEnter, useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
import { NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
import { Dialog } from 'quasar'; // Assicurati di importare correttamente Dialog da Quasar.
export default defineComponent({
name: 'CGridTableRec',
@@ -295,14 +301,22 @@ export default defineComponent({
required: false,
default: '',
},
prop_showMap: {
type: Boolean,
required: false,
default: false,
}
},
components: {
CMyPopupEdit, CTitleBanner, CMyFieldDb, CMySelect, CMyFriends, CMyGroups,
CMyUser, CMyRecCard, CMyCardPopup, CMyRecGrpCard, CMyCardGrpPopup, CMyCardCircuitPopup,
CMyRecCircuitCard, CMyCardService, CNotifSettings
CMyRecCircuitCard, CMyCardService, CNotifSettings, CMapByTable,
},
setup(props, { emit }) {
const $q = useQuasar()
const router = useRouter()
const route = useRoute()
const { t } = useI18n()
const userStore = useUserStore()
const globalStore = useGlobalStore()
@@ -314,6 +328,8 @@ export default defineComponent({
const actmonth = ref('')
const drawmonth = ref(true)
const showMap = ref(false)
const newRecordBool = ref(false)
const newRecordBoolOld = ref(false)
@@ -347,12 +363,11 @@ export default defineComponent({
const visupagedialog = ref(false)
const myrecdialog = ref(null)
const myIdRecDialog = ref(null)
const startsearch = ref(false)
const clickbuttsearch = ref(false)
const $router = useRouter()
const myinfscroll = ref(null)
const serverData: any = ref([] as any[])
@@ -397,7 +412,53 @@ export default defineComponent({
const ordinam = ref('')
const ordinam_desc = ref(false)
/*onBeforeRouteUpdate((to: any, from: any, next: any) => {
console.log('onBeforeRouteUpdate', 'to', to, 'from', from, 'next', next)
next()
})*/
onBeforeRouteLeave((to: any, from: any, next: any) => {
console.log('onBeforeRouteLeave', 'to', to, 'from', from, 'next', next)
if (checkForChanges()) {
const answer = window.confirm(t('dialog.uscire'))
if (answer) {
next()
} else {
next(false)
}
} else {
next()
}
})
// Funzione per simulare il controllo delle modifiche
const checkForChanges = (): boolean => {
// Funzione di utilità per confrontare due valori
const isEqual = (val1: any, val2: any): boolean => {
if (typeof val1 !== typeof val2) return false
if (typeof val1 === 'object' && val1 !== null && val2 !== null) {
const keys1 = Object.keys(val1)
const keys2 = Object.keys(val2)
if (keys1.length !== keys2.length) return false
return keys1.every(key => isEqual(val1[key], val2[key]))
}
return val1 === val2
}
// Confronta recModif con recSaved
return !isEqual(recModif.value, recSaved.value)
// return true
}
function saveChanges() {
if (editRecordBool.value) {
saverecModif()
}
if (newRecordBool.value) {
saveNewRecord()
}
}
const getNumRecFromQuery = computed(() => () => {
return serverData.value.length
})
@@ -493,8 +554,8 @@ export default defineComponent({
}
})
$router.beforeResolve((to: any) => {
// console.log('beforeResolve', visupagedialog.value, 'to', to)
router.beforeResolve((to: any) => {
console.log('beforeResolve', visupagedialog.value, 'to', to)
if (visupagedialog.value && !to.meta.newpage) {
// visupagedialog.value = false
@@ -1544,8 +1605,11 @@ export default defineComponent({
}
function mounted() {
console.log('mounted...')
searchList.value = props.prop_searchList
showMap.value = props.prop_showMap
// console.log('GridTable mounted', tablesel.value)
@@ -1583,6 +1647,9 @@ export default defineComponent({
changeTable(tablesel.value, true)
// Aggiungi gli listener agli eventi della tastiera
document.addEventListener('keydown', onEscapeKey);
// window.addEventListener('popstate', onBackButton);
}
@@ -2077,7 +2144,7 @@ export default defineComponent({
}
async function saverecModif() {
// console.log('saverecModif')
// console.log('saverecModif', recModif.value)
const mydata = {
table: mytable.value,
data: {}
@@ -2110,9 +2177,6 @@ export default defineComponent({
})
}
function hidewindow() {
annulla(0)
}
function getlabelAddRow() {
return props.labelBtnAddRow
@@ -2159,7 +2223,7 @@ export default defineComponent({
}
function cmdExt(cmd: any, id: any, val2: any) {
function cmdExt(cmd: any, id: any, myrec: any) {
console.log('cmd', cmd)
if (cmd === costanti.CMD_CLONE) {
@@ -2172,10 +2236,11 @@ export default defineComponent({
if (cmd === costanti.CMD_SHOW_PAGE) {
visupagedialog.value = true
myrecdialog.value = id
myrecdialog.value = myrec
myIdRecDialog.value = id
return true
} else if (cmd === costanti.CMD_OPEN_PAGE) {
$router.push(tools.getPathByTableAndRec(mytable.value, id))
router.push(tools.getPathByTableAndRec(mytable.value, myrec))
return true
}
@@ -2193,7 +2258,7 @@ export default defineComponent({
const col = props.prop_mycolumns.find((rec: any) => rec.action === action)
if (col) {
console.log('col action', col)
// console.log('col action', col)
const myarr = serverData.value.find((rec: any) => rec._id === id)
if (myarr)
clickFunz(myarr, col)
@@ -2326,11 +2391,36 @@ export default defineComponent({
}
/*function showNotification() {
$router.push('/notifs')
router.push('/notifs')
} */
// Questa funzione viene chiamata quando il dialogo cerca di chiudersi
const onEscapeKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
event.preventDefault(); // Previene la chiusura da ESC
}
};
// Rimuovi i listener al distruggere del componente
onBeforeUnmount(() => {
document.removeEventListener('keydown', onEscapeKey);
// window.removeEventListener('popstate', onBackButton);
});
onMounted(() => {
mounted()
})
function hidewindow() {
annulla(0)
}
function clickMarker(id: any) {
console.log('clickMarker', id)
cmdExt(costanti.CMD_SHOW_PAGE, id, null)
}
created()
mounted()
return {
selItem,
@@ -2410,6 +2500,7 @@ export default defineComponent({
cmdExt,
visupagedialog,
myrecdialog,
myIdRecDialog,
showDate,
getActualDate,
actualDate,
@@ -2440,6 +2531,8 @@ export default defineComponent({
withdate,
setShowMonth,
ifShowMonth,
showMap,
clickMarker,
}
}
})

File diff suppressed because it is too large Load Diff

View File

@@ -2103,7 +2103,7 @@ export default defineComponent({
}
function cmdExt(cmd: any, id: any, val2: any) {
function cmdExt(cmd: any, id: any, myrec: any) {
console.log('cmd', cmd)
if (cmd === costanti.CMD_CLONE) {
@@ -2116,10 +2116,10 @@ export default defineComponent({
if (cmd === costanti.CMD_SHOW_PAGE) {
visupagedialog.value = true
myrecdialog.value = id
myrecdialog.value = myrec
return true
} else if (cmd === costanti.CMD_OPEN_PAGE) {
$router.push(tools.getPathByTableAndRec(mytable.value, id))
$router.push(tools.getPathByTableAndRec(mytable.value, myrec))
return true
}

View File

@@ -0,0 +1,3 @@
.map-container {
height: 400px;
}

View File

@@ -0,0 +1,177 @@
import { tools } from '@store/Modules/tools'
import { useQuasar } from 'quasar'
import { PropType, defineComponent, onMounted, ref, computed, toRef, watch } from 'vue'
import 'leaflet/dist/leaflet.css'
// @ts-ignore
import * as L from 'leaflet'
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster'
import { useUserStore } from '@src/store/UserStore'
export default defineComponent({
name: 'CMapByTable',
props: {
mytable: {
type: String,
required: true,
},
arrcord: {
type: Array as PropType<any[]>,
required: false,
default: () => { return [] }
}
},
setup(props, { emit }) {
const $q = useQuasar()
const userStore = useUserStore()
const iconWidth = ref(25)
const iconHeight = ref(40)
const map = ref(<any>null)
const zoom = ref(6)
const initialMap = ref(<any>null);
const markers = ref(<any>null);
const myIcon = L.icon({
iconUrl: 'images/icon.png',
iconSize: [30, 30],
iconAnchor: [22, 35],
popupAnchor: [-6, -36],
shadowUrl: 'images/marker-shadow.png',
shadowSize: [60, 30],
shadowAnchor: [22, 35]
});
const arrcord = toRef(props, 'arrcord')
function mywidth() {
return tools.getwidth($q) - 20
}
function myheight() {
return $q.screen.height - 150
}
const iconUrl = computed(() => {
return `https://placekitten.com/${iconWidth.value}/${iconHeight.value}`;
})
const iconSize = computed(() => {
return [iconWidth.value, iconHeight.value];
})
function changeIcon() {
iconWidth.value += 2;
if (iconWidth.value > iconHeight.value) {
iconWidth.value = Math.floor(iconHeight.value / 2);
}
}
function getColor(d: any) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature: any) {
return {
fillColor: getColor(feature.properties.density),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
watch(arrcord, () => {
updateMap()
})
onMounted(async () => {
// Ottengo la lista degli utenti con i lat e long
// arrcord.value = await userStore.getProvincesForMap()
// @ts-ignore
markers.value = L.markerClusterGroup()
initialMap.value = L.map('map',
{
zoomControl: true, zoom: zoom.value, zoomAnimation: true,
fadeAnimation: true, markerZoomAnimation: true,
center: [42.71, 12.934],
}
);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 15,
attribution: ''
}).addTo(initialMap.value);
updateMap()
// @ts-ignore
});
function log(str: string) {
console.log(str)
}
function getCoordinates(e: any) {
// Ottieni la latitudine e la longitudine dal click
const lat = e.latlng.lat
const lng = e.latlng.lng
// Fai qualcosa con le coordinate, ad esempio stamparle in console
console.log(`Latitudine: ${lat}, Longitudine: ${lng}`)
}
function updateMap() {
if (initialMap.value) {
markers.value.clearLayers();
for (const rec of arrcord.value) {
if (rec.coordinate_gps.coordinates) {
// @ts-ignore
let each_marker = new L.marker(
[rec.coordinate_gps.coordinates[1], rec.coordinate_gps.coordinates[0]], { icon: myIcon })
.bindPopup(`<strong>${rec.descr}</strong>`)
.on('click', () => markerClick(rec._id)); // Collega il click al bottone
markers.value.addLayer(each_marker);
}
}
// Aggiungi il gruppo di marker cluster alla mappa
initialMap.value.addLayer(markers.value);
}
}
function markerClick(id: any) {
emit('clickMarker', id)
}
return {
mywidth,
myheight,
map,
iconWidth,
iconHeight,
iconUrl,
iconSize,
changeIcon,
zoom,
log,
getCoordinates,
arrcord,
}
}
})

View File

@@ -0,0 +1,12 @@
<template>
<div>
<div id="map" :style="`height:${myheight()}px; width:99%`">
</div>
</div>
</template>
<script lang="ts" src="./CMapByTable.ts">
</script>
<style lang="scss" scoped>
@import './CMapByTable.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CMapByTable} from './CMapByTable.vue'

View File

@@ -187,7 +187,7 @@ export default defineComponent({
initialMap.value = L.map('map',
{
zoomControl: true, zoom: zoom.value, zoomAnimation: false,
zoomControl: true, zoom: zoom.value, zoomAnimation: true,
fadeAnimation: true, markerZoomAnimation: true,
center: center.value,
}

View File

@@ -0,0 +1,13 @@
.map-container {
width: 100%; /* Imposta la larghezza del contenitore */
height: 400px; /* Imposta un'altezza fissa o usa % */
position: relative; /* Assicurati che la posizione sia relativa o assoluta */
}
#map {
width: 100%;
height: 100%;
}
.leaflet-popup-content >* {
display: block !important;
}

View File

@@ -0,0 +1,390 @@
import { tools } from '@store/Modules/tools'
import { useQuasar } from 'quasar'
import { defineComponent, onMounted, onBeforeUnmount, ref, watch, computed, PropType, nextTick } from 'vue'
import 'leaflet/dist/leaflet.css'
import * as L from 'leaflet'
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster'
import { useUserStore } from '@src/store/UserStore'
// Importa le immagini dei marker
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
import { ICoordGPS, ICoordLatLng } from '@src/model'
export default defineComponent({
name: 'CMapEditAddressByCoord',
props: {
modelValue: {
type: Object as PropType<ICoordGPS>,
required: true,
},
editaddress: {
type: Boolean,
required: true,
},
visuMappa: {
type: Boolean,
required: false,
default: true,
}
},
setup(props, { emit }) {
const $q = useQuasar()
const userStore = useUserStore()
const mapContainer = ref(<any>null);
const iconWidth = ref(25)
const iconHeight = ref(41)
const map = ref<L.Map | null>(null)
const marker = ref<L.Marker | null>(null)
const suggestions = ref([]);
const isMapDialogOpen = ref(false)
const mostraMappa = ref(true)
const localAddress = ref(props.modelValue.address);
const localAddressObj = ref({ label: '', value: '' });
const localCoordinates = ref(<ICoordLatLng>{ lat: props.modelValue.coordinates[1], lng: props.modelValue.coordinates[0] });
const modificato = ref(false)
const fineLoad = ref(false)
const zoomLevel = ref(17)
const updateAll = () => {
if (localAddress.value)
emit('update:modelValue',
{
address: localAddress.value,
type: 'Point',
coordinates: [localCoordinates.value.lng, localCoordinates.value.lat]
} as ICoordGPS);
};
// Funzione per aggiornare il nome
const updateAddress = () => {
if (localAddress.value)
updateAll()
};
// Funzione per aggiornare il cognome
const updateCoordinates = () => {
updateAll()
};
// Monitoraggio delle modifiche alle props
watch(() => props.modelValue.address, (newValue) => {
localAddress.value = newValue;
});
watch(() => props.modelValue.coordinates, (newValue) => {
localCoordinates.value.lat = newValue[1];
localCoordinates.value.lng = newValue[0];
});
watch(() => localCoordinates.value.lng, (newValue) => {
if (fineLoad.value) {
modificato.value = true
}
updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng);
});
watch(() => localCoordinates.value.lng, (newValue) => {
if (fineLoad.value) {
modificato.value = true
}
updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng);
});
const myheight = computed(() => {
return $q.screen.height - 150
})
// Funzione per ottenere e stampare il livello di zoom
function getZoomLevel() {
zoomLevel.value = map.value ? map.value.getZoom() : 17;
// console.log('Current zoom level:', zoomLevel);
}
const initMap = () => {
// Configura l'icona di default
const DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
iconSize: [iconWidth.value, iconHeight.value],
iconAnchor: [iconWidth.value / 2, iconHeight.value],
popupAnchor: [1, -iconHeight.value],
shadowSize: [iconHeight.value, iconHeight.value]
})
L.Marker.prototype.options.icon = DefaultIcon
zoomLevel.value = 17
map.value = L.map(mapContainer.value,
{
zoomControl: true, zoom: zoomLevel.value, zoomAnimation: true,
fadeAnimation: true, markerZoomAnimation: true,
center: [42.71, 12.934],
}
)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map.value)
getZoomLevel();
// Ottenere il livello di zoom quando la mappa viene ridimensionata
map.value.on('zoomend', getZoomLevel);
/*
const closeButton = L.control({ position: 'topright' });
closeButton.onAdd = function () {
const button = L.DomUtil.create('button', 'leaflet-control-button');
button.innerHTML = 'Chiudi'; // Testo del pulsante
button.style.backgroundColor = 'red';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.padding = '10px';
button.style.cursor = 'pointer';
button.onclick = () => {
mostraMappa.value = false; // Chiudi il dialog della mappa
};
return button;
};
closeButton.addTo(map.value);
*/
}
const onResize = () => {
if (map.value) {
map.value.invalidateSize();
}
};
const updateMarker = (lat: number, lng: number) => {
// console.log('aggiorna marker', lat, lng)
if (fineLoad.value) {
modificato.value = true
}
if (marker.value) {
marker.value.setLatLng([lat, lng])
} else {
marker.value = L.marker([lat, lng], { draggable: true }).addTo(map.value!)
marker.value.on('dragend', (event: L.LeafletEvent) => {
const position = (event.target as L.Marker).getLatLng()
localCoordinates.value = {
lat: parseFloat(position.lat.toFixed(6)),
lng: parseFloat(position.lng.toFixed(6)),
};
if (fineLoad.value) {
mostraMappa.value = true
}
getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng);
// updateCoordinates()
})
}
map.value?.setView([lat, lng], zoomLevel.value)
}
function updateMap() {
map.value?.setView([localCoordinates.value.lat, localCoordinates.value.lng], zoomLevel.value)
}
const searchAddress = async () => {
try {
const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(localAddress.value)}`)
const data = await response.json()
if (data && data.length > 0) {
localCoordinates.value = { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon) }
localAddress.value = data[0].display_name
if (fineLoad.value) {
mostraMappa.value = true
}
isMapDialogOpen.value = true
}
} catch (error) {
console.error('Error searching address:', error)
}
}
const getAddressSuggestions = async (val: string, update: Function) => {
try {
if (val.length === 0) {
suggestions.value = [];
update();
return;
}
const response = await fetch(
`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(val)}`
);
const data = await response.json();
suggestions.value = data.map((item: any) => ({
label: item.display_name,
value: item.display_name,
lat: item.lat,
lon: item.lon
}));
update();
} catch (error) {
console.error('Error fetching address suggestions:', error);
}
};
const getAddressFromCoordinates = async (lat: number, lon: number) => {
const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Errore nella richiesta di geocoding');
}
const data = await response.json();
localAddress.value = data.display_name; // Ottieni l'indirizzo
localAddressObj.value = { label: localAddress.value, value: localAddress.value }
} catch (error) {
console.error('Errore durante il geocoding:', error);
localAddress.value = ''; // In caso di errore, resetta l'indirizzo
localAddressObj.value = { label: '', value: '' }
}
};
watch(localAddressObj, (newAddress: any) => {
if (newAddress) {
const match: any = suggestions.value.find((suggestion: any) => suggestion.value === newAddress.value);
if (match && match.lat) {
localAddress.value = match.value;
localCoordinates.value = {
lat: parseFloat(parseFloat(match.lat).toFixed(6)),
lng: parseFloat(parseFloat(match.lon).toFixed(6)),
};
updateCoordinates()
updateAddress()
updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
}
}
});
function salvaCoordinate() {
updateCoordinates()
updateAddress()
$q.notify({
type: 'positive',
message: 'Coordinate modificate, Salvare per rendere effettiva la modifica',
position: 'bottom',
timeout: 2000
})
modificato.value = false
mostraMappa.value = false
}
onMounted(() => {
if (!props.modelValue.address) {
localAddress.value = ''
localAddressObj.value = { label: '', value: '' }
} else {
localAddressObj.value = { label: props.modelValue.address, value: props.modelAddress }
}
if (!props.modelValue.coordinates) {
localCoordinates.value = { lat: 0, lng: 0 }
}
initMap()
updateMap()
updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
if (!localCoordinates.value || !localCoordinates.value.lat) {
mostraMappa.value = false
}
fineLoad.value = true
window.addEventListener('resize', onResize);
nextTick(() => {
mostraMappa.value = props.visuMappa
})
})
onBeforeUnmount(() => {
window.removeEventListener('resize', onResize);
});
const getCurrentLocation = () => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
localCoordinates.value = {
lat: parseFloat(position.coords.latitude.toFixed(6)),
lng: parseFloat(position.coords.longitude.toFixed(6)),
};
if (fineLoad.value) {
mostraMappa.value = true;
}
updateCoordinates();
updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
},
(error) => {
console.error('Error getting location:', error);
$q.notify({
type: 'negative',
message: 'Errore durante il rilevamento della posizione.',
});
}
);
} else {
$q.notify({
type: 'negative',
message: 'Geolocalizzazione non supportata dal browser.',
});
}
};
function annullaSalvataggio() {
localCoordinates.value.lng = props.modelValue.coordinates[0]
localCoordinates.value.lat = props.modelValue.coordinates[1]
localAddress.value = props.modelValue.address
updateMarker(localCoordinates.value.lat, localCoordinates.value.lng);
mostraMappa.value = false
modificato.value = false
}
// evento dopo il mounting
return {
searchAddress,
myheight,
isMapDialogOpen,
suggestions,
getAddressSuggestions,
localAddress,
localCoordinates,
updateAddress,
updateCoordinates,
mostraMappa,
localAddressObj,
getCurrentLocation,
salvaCoordinate,
modificato,
annullaSalvataggio,
mapContainer,
fineLoad,
}
}
})

View File

@@ -0,0 +1,90 @@
<template>
<div class="q-pa-sm">
<div class="q-gutter-sm">
<div class="row q-col-gutter-sm q-mb-sm items-center">
<div class="col">
<q-select
v-model="localAddressObj"
label="Indirizzo"
use-input
input-debounce="300"
:options="suggestions"
@filter="getAddressSuggestions"
filled
dense
hide-dropdown-icon
clearable
/>
</div>
<div class="col-auto">
<q-btn @click="searchAddress" label="Cerca" color="primary" />
</div>
</div>
<div class="row q-col-gutter-sm q-mb-sm items-center no-wrap">
<q-col class="q-col-auto" style="width: 120px">
<q-input
v-model="localCoordinates.lat"
label="Latitudine:"
filled
:label-color="modificato ? 'negative' : 'primary'"
dense
/>
</q-col>
<q-col class="q-col-auto" style="width: 120px">
<q-input
v-model="localCoordinates.lng"
label="Longitudine:"
filled
:label-color="modificato ? 'negative' : 'primary'"
dense
/>
</q-col>
<q-col class="q-col-auto" style="width: 60px">
<q-btn
@click="getCurrentLocation"
label=""
color="primary"
icon="gps_fixed"
/>
</q-col>
<q-col class="q-col-auto" style="width: 60px">
<q-btn
@click="mostraMappa = !mostraMappa"
:color="mostraMappa ? 'negative' : 'positive'"
class="q-ma-sm"
icon="fas fa-map"
/>
</q-col>
</div>
<div v-if="modificato" class="row justify-center q-ma-sm">
<q-btn
@click="salvaCoordinate"
color="primary"
label="Salva"
:disable="!modificato"
class="q-ma-sm"
/>
<q-btn
@click="annullaSalvataggio"
label="Annulla"
class="q-ma-sm"
:disable="!modificato"
/>
</div>
</div>
<div
id="map"
ref="mapContainer"
v-show="mostraMappa"
:style="`height:${myheight}px; width:99%`"
></div>
</div>
</template>
<script lang="ts" src="./CMapEditAddressByCoord.ts">
</script>
<style lang="scss" scoped>
@import './CMapEditAddressByCoord.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CMapEditAddressByCoord} from './CMapEditAddressByCoord.vue'

View File

@@ -0,0 +1,3 @@
.map-container {
height: 400px;
}

View File

@@ -0,0 +1,170 @@
import { tools } from '@store/Modules/tools'
import { useQuasar } from 'quasar'
import { defineComponent, onMounted, ref, watch, computed } from 'vue'
import 'leaflet/dist/leaflet.css'
import * as L from 'leaflet'
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster'
import { useUserStore } from '@src/store/UserStore'
// Importa le immagini dei marker
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
export default defineComponent({
name: 'CMapGetCoordinates',
setup(props, { emit }) {
const $q = useQuasar()
const userStore = useUserStore()
const iconWidth = ref(25)
const iconHeight = ref(41)
const map = ref<L.Map | null>(null)
const marker = ref<L.Marker | null>(null)
const address = ref('')
const suggestions = ref([]);
const coordinates = ref(<[number, number]>[0, 0])
const isMapDialogOpen = ref(false)
const zoomLevel = ref(17)
const myheight = computed(() => {
return $q.screen.height - 150
})
const initMap = () => {
// Configura l'icona di default
const DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
iconSize: [iconWidth.value, iconHeight.value],
iconAnchor: [iconWidth.value / 2, iconHeight.value],
popupAnchor: [1, -iconHeight.value],
shadowSize: [iconHeight.value, iconHeight.value]
})
L.Marker.prototype.options.icon = DefaultIcon
map.value = L.map('map',
{
zoomControl: true, zoom: zoomLevel.value, zoomAnimation: true,
fadeAnimation: true, markerZoomAnimation: true,
center: [42.71, 12.934],
}
)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map.value)
const closeButton = L.control({ position: 'topright' });
closeButton.onAdd = function () {
const button = L.DomUtil.create('button', 'leaflet-control-button');
button.innerHTML = 'Chiudi'; // Testo del pulsante
button.style.backgroundColor = 'red';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.padding = '10px';
button.style.cursor = 'pointer';
button.onclick = () => {
isMapDialogOpen.value = false; // Chiudi il dialog della mappa
};
return button;
};
closeButton.addTo(map.value);
}
const updateMarker = (lat: number, lng: number) => {
console.log('aggiorna marker', lat, lng)
if (marker.value) {
marker.value.setLatLng([lat, lng])
} else {
marker.value = L.marker([lat, lng], { draggable: true }).addTo(map.value!)
marker.value.on('dragend', (event: L.LeafletEvent) => {
const position = (event.target as L.Marker).getLatLng()
coordinates.value = [
parseFloat(position.lng.toFixed(6)),
parseFloat(position.lat.toFixed(6)),
]
emit('update:coordinates', coordinates.value)
})
}
map.value?.setView([lat, lng], 17)
}
const searchAddress = async () => {
try {
const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address.value)}`)
const data = await response.json()
if (data && data.length > 0) {
coordinates.value = [
parseFloat(data[0].lon),
parseFloat(data[0].lat)
]
emit('update:coordinates', coordinates.value)
isMapDialogOpen.value = true
}
} catch (error) {
console.error('Error searching address:', error)
}
}
const getAddressSuggestions = async (val: string, update: Function) => {
try {
if (val.length === 0) {
suggestions.value = [];
update();
return;
}
const response = await fetch(
`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(val)}`
);
const data = await response.json();
suggestions.value = data.map((item: any) => ({
label: item.display_name,
value: item.display_name,
lat: item.lat,
lon: item.lon
}));
update();
} catch (error) {
console.error('Error fetching address suggestions:', error);
}
};
watch(address, (newAddress) => {
const match: any = suggestions.value.find((suggestion: any) => suggestion.value === newAddress.value);
if (match && match.lat) {
coordinates.value = [
parseFloat(parseFloat(match.lon).toFixed(6)),
parseFloat(parseFloat(match.lat).toFixed(6))
]
};
updateMarker(coordinates.value[1], coordinates.value[0]);
});
onMounted(() => {
initMap()
})
return {
address,
coordinates,
searchAddress,
myheight,
isMapDialogOpen,
suggestions,
getAddressSuggestions,
}
}
})

View File

@@ -0,0 +1,57 @@
<template>
<div class="q-pa-sm">
<div class="q-gutter-sm">
<div class="row q-col-gutter-sm q-mb-sm items-center no-wrap">
<div class="col-grow">
<q-select
v-model="address"
label="Indirizzo"
use-input
input-class="col-auto"
input-debounce="300"
:options="suggestions"
@filter="getAddressSuggestions"
filled
dense
hide-dropdown-icon
clearable
/>
</div>
<div class="col-3">
<q-btn @click="searchAddress" label="Cerca" color="primary" />
</div>
</div>
<div class="row q-col-gutter-sm">
<q-col cols="6">
<q-input
v-model="coordinates.lat" label="Latitudine:"
filled dense />
</q-col>
<q-col cols="6">
<q-input
v-model="coordinates.lng"
label="Longitudine:"
filled
dense
/>
</q-col>
</div>
</div>
<div
id="map"
:style="`height:${myheight}px; width:99%`"
>
<p v-if="coordinates && coordinates.lat">
Coordinate: {{ coordinates.lat.toFixed(6) }},
{{ coordinates.lng.toFixed(6) }}
</p>
</div>
</div>
</template>
<script lang="ts" src="./CMapGetCoordinates.ts">
</script>
<style lang="scss" scoped>
@import './CMapGetCoordinates.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CMapGetCoordinates} from './CMapGetCoordinates.vue'

View File

@@ -87,7 +87,7 @@ export default defineComponent({
initialMap.value = L.map('map',
{
zoomControl: true, zoom: zoom.value, zoomAnimation: false,
zoomControl: true, zoom: zoom.value, zoomAnimation: true,
fadeAnimation: true, markerZoomAnimation: true,
center: [42.71, 12.934],
}

View File

@@ -153,4 +153,28 @@ $graytext: #555;
.container_butt{
display: flex;
justify-content: space-between;
}
}
.expand-fade-enter-active, .expand-fade-leave-active {
transition: height 0.3s ease, opacity 0.3s ease; /* Aggiunge transizioni per height e opacity */
}
.expand-fade-enter, .expand-fade-leave-to {
height: 0; /* Imposta l'altezza a 0 per l'uscita */
opacity: 0; /* Rende invisibile durante l'uscita */
}
.height-transition {
transition: height 0.3s ease-in-out;
}
.well-positioned-dialog {
width: 50vw; /* Imposta la larghezza al 50% della vista */
height: auto; /* Puoi regolare l'altezza come preferisci */
margin-left: auto; /* Allinea il dialogo a destra */
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); /* Aggiunge una leggera ombra */
}
.riempi {
width: 100%;
}

View File

@@ -1,4 +1,4 @@
import { computed, defineComponent, onMounted, PropType, ref, watch } from 'vue'
import { computed, defineComponent, onMounted, PropType, ref, watch, nextTick } from 'vue'
import { CMyFieldDb } from '@/components/CMyFieldDb'
import { CTitleBanner } from '@/components/CTitleBanner'
@@ -58,6 +58,11 @@ export default defineComponent({
required: false,
default: false
},
showAnteprima: {
type: Boolean,
required: false,
default: false,
}
},
setup(props) {
@@ -143,6 +148,17 @@ export default defineComponent({
const idnotif = computed(() => $route.query.idnotif ? $route.query.idnotif.toString() : '')
const arrbookings = computed(() => calendarStore.findAllBookedByIdEvent(myrec.value._id))
const isSmall = ref(props.showAnteprima);
const cardRef = ref(<any>null)
const smallHeight = ref('30vh')
const largeHeight = ref('100vh')
const cardStyle = computed(() => ({
height: isSmall.value ? smallHeight.value : largeHeight.value,
transition: 'height 0.3s ease-in-out'
}))
const filtercustom: any = computed(() => {
let queryreact = {}
@@ -201,8 +217,18 @@ export default defineComponent({
load()
})
function mounted() {
async function mounted() {
load()
await nextTick()
}
function updateCard() {
if (cardRef.value) {
largeHeight.value = !isSmall.value ? `${cardRef.value.clientHeight}px` : largeHeight.value
if (isSmall.value)
smallHeight.value = `${cardRef.value.clientHeight}px`
}
}
function getlinkpage() {
@@ -610,9 +636,20 @@ export default defineComponent({
tools.openUrl(tools.getLinkBotTelegram('', ''))
}
const expandDialog = () => {
isSmall.value = false; // Cambia lo stato a 'non piccolo'
};
function toggleShowScheda() {
// updateCard()
isSmall.value = !isSmall.value
}
onMounted(mounted)
return {
expandDialog,
profile,
tools,
costanti,
@@ -659,6 +696,11 @@ export default defineComponent({
extraparams,
condividi,
getTipodiAttivita,
isSmall,
cardStyle,
cardRef,
smallHeight,
toggleShowScheda,
}
}
})

File diff suppressed because it is too large Load Diff

View File

@@ -1044,6 +1044,9 @@
>
</q-select>
Versione PDF: <q-toggle v-model="myel.catalogo.pdf" color="positive" icon="fas fa-file-pdf"
@update:model-value="modifElem">
</q-toggle>
</div>
</div>
</div>

View File

@@ -3,7 +3,7 @@ import {
defineComponent, onMounted, PropType, ref, toRef, watch,
} from 'vue'
import { IMyCard, IMyElem, IMyPage, IOperators, ISocial } from '@src/model'
import { ICoordGPS, IMyCard, IMyElem, IMyPage, IOperators, ISocial } from '@src/model'
import { useGlobalStore } from '@store/globalStore'
import { CImgTitle } from '../CImgTitle/index'
@@ -18,6 +18,8 @@ import { CAITools } from '@/components/CAITools'
import { CCatalogo } from '@/components/CCatalogo'
// import { CMapMarker } from '@src/components/CMapMarker.off'
import { CMapUsers } from '@/components/CMapUsers'
import { CMapGetCoordinates } from '@/components/CMapGetCoordinates'
import { CMapEditAddressByCoord } from '@/components/CMapEditAddressByCoord'
import { CMapComuni } from '@/components/CMapComuni'
import { COpenStreetMap } from '@src/components/COpenStreetMap'
import { CCardCarousel } from '@src/components/CCardCarousel'
@@ -48,6 +50,7 @@ import MixinBase from '@/mixins/mixin-base'
import { useQuasar } from 'quasar'
import { useI18n } from '@/boot/i18n'
import { useRouter } from 'vue-router'
import { LatLng } from 'leaflet'
export default defineComponent({
@@ -61,7 +64,8 @@ export default defineComponent({
CMyProfileTutorial, CSendRISTo,
CTitleBanner, CShareSocial, CCheckAppRunning, CRegistration,
CVisuVideoPromoAndPDF, CECommerce, CCatalogo, CAITools,
CMapComuni, CMapUsers, CDashGroup,
CMapComuni, CMapUsers, CMapGetCoordinates, CMapEditAddressByCoord,
CDashGroup,
// , //CMapMarker,
},
emits: ['selElemClick'],
@@ -119,6 +123,8 @@ export default defineComponent({
const isAppRunning = computed(() => globalStore.isAppRunning)
const coordaddr = ref(<ICoordGPS> { address: '', coordinates: [0, 0] })
watch(() => myel.value.order, (value, oldval) => {
mounted()
})
@@ -289,6 +295,7 @@ export default defineComponent({
social,
clickshare,
isAppRunning,
coordaddr,
}
},

View File

@@ -573,6 +573,18 @@
<CMapUsers
></CMapUsers>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPAGETCOORDINATE">
<div v-if="editOn" class="elemEdit">MAPPA COORDINATE:</div>
<CMapGetCoordinates
></CMapGetCoordinates>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.EDITADDRESSBYCOORD">
<div v-if="editOn" class="elemEdit">EDIT ADDRESS BY COORD:</div>
<CMapEditAddressByCoord
:editaddress="true"
v-model:model-value="coordaddr"
></CMapEditAddressByCoord>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPACOMUNI">
<div v-if="editOn" class="elemEdit">MAPPA COMUNI:</div>
<CMapComuni

View File

@@ -11,6 +11,7 @@ import { CLabel } from '../CLabel'
import { CMyToggleList } from '../CMyToggleList'
import { CMySelect } from '../CMySelect'
import { CCurrencyValue } from '../CCurrencyValue'
import { CMapEditAddressByCoord } from '../CMapEditAddressByCoord'
import { CMyEditor } from '../CMyEditor'
import { CGallery } from '../CGallery'
import { CSelectImage } from '../CSelectImage'
@@ -221,7 +222,7 @@ export default defineComponent({
},
components: {
CMyChipList, CDateTime, CDate, CMyToggleList, CMySelect, CMyEditor, CGallery,
CCurrencyValue, CLabel, CAccomodation, CSelectImage
CCurrencyValue, CLabel, CAccomodation, CSelectImage, CMapEditAddressByCoord,
},
setup(props, { emit }) {
const $q = useQuasar()
@@ -240,6 +241,8 @@ export default defineComponent({
const $router = useRouter()
const loaded = ref(false)
const col = ref(<IColGridTable>{
name: 'test',
fieldtype: 0,
@@ -389,7 +392,23 @@ export default defineComponent({
return null
}
function changeValRecCoordAddr(newval: any) {
// console.log('changeValRecCoordAddr', newval, 'myrow', myrow.value[col.value.name])
if (!myrow.value[col.value.name]) {
myrow.value[col.value.name] = {}
}
if (newval.coordinates && newval.coordinates.lat) {
newval.coordinates.lat = tools.convertToDecimal6(newval.coordinates.lat)
newval.coordinates.lng = tools.convertToDecimal6(newval.coordinates.lng)
}
// console.log('newval...', newval)
return changevalRecOrig(newval)
}
function changevalRec(newval: any) {
return changevalRecOrig(newval, '')
}
function changevalRecOrig(newval: any, subcol: string = '') {
// console.log('changevalRec', newval)
// if (!props.insertMode || (props.insertMode && col.value.fieldtype !== costanti.FieldType.multioption)) {
if (col.value && col.value.allowchar === costanti.ALLOWCHAR_CODE) {
@@ -407,7 +426,15 @@ export default defineComponent({
newval = tools.rimuoviAtPrimoCarattere(newval)
}
myrow.value[col.value.name] = newval
if (subcol) {
if (!myrow.value[col.value.name]) {
myrow.value[col.value.name] = {}
}
myrow.value[col.value.name][subcol] = newval
// console.log('myrow.value[col.value.name]', myrow.value[col.value.name])
} else {
myrow.value[col.value.name] = newval
}
// console.log('changevalRec update:row', myrow.value)
@@ -434,6 +461,7 @@ export default defineComponent({
}
function mounted() {
console.log('mounted')
myrow.value = props.rec && props.isrec ? { ...props.rec } : { ...props.row }
@@ -466,30 +494,50 @@ export default defineComponent({
// console.log('popupedit: myvalue.value', myvalue.value)
if (col.value.fieldtype === costanti.FieldType.listimages) {
if (myvalue.value === '' || myvalue.value === undefined) {
// console.log('set default myvalue.value ')
myvalue.value = {
title: 'Galleria',
directory: 'none',
list: []
}
}
} else if (col.value.fieldtype === costanti.FieldType.listobj) {
if (myvalue.value === '' || myvalue.value === undefined) {
// console.log('set default myvalue.value ')
myvalue.value = [{
type: 0, // Letto matrimoniale / letto singolo / divano-letto / almaca / a terra sul tappeto (per sacco a pelo)
location: 0, // in camera privata / in camera condivisa / in soggiorno / in camper / in tenda / in giardino / all'aperto
num: 0,
}]
}
}
// console.log('myvalue.value', myvalue.value)
myvalueprec.value = myvalue.value
crea()
if (!loaded.value) {
if (col.value.fieldtype === costanti.FieldType.listimages) {
if (myvalue.value === '' || myvalue.value === undefined) {
// console.log('set default myvalue.value ')
myvalue.value = {
title: 'Galleria',
directory: 'none',
list: []
}
}
} else if (col.value.fieldtype === costanti.FieldType.listobj) {
if (myvalue.value === '' || myvalue.value === undefined) {
// console.log('set default myvalue.value ')
myvalue.value = [{
type: 0, // Letto matrimoniale / letto singolo / divano-letto / almaca / a terra sul tappeto (per sacco a pelo)
location: 0, // in camera privata / in camera condivisa / in soggiorno / in camper / in tenda / in giardino / all'aperto
num: 0,
}]
}
} else if (col.value.fieldtype === costanti.FieldType.coordinates) {
if (myvalue.value === '' || myvalue.value === undefined) {
// console.log('set default myvalue.value ')
myvalue.value = {
address: '',
coordinates: [0, 0]
}
}
if (!myvalue.value.address) {
myvalue.value.address = ''
}
if (!myvalue.value.coordinates) {
myvalue.value.coordinates = [0, 0]
}
}
}
loaded.value = true
// console.log('myvalueprec', myvalueprec)
}
@@ -868,6 +916,7 @@ export default defineComponent({
nameKeydown,
gotoPage,
mypath,
changeValRecCoordAddr,
}
}
})

View File

@@ -299,6 +299,14 @@
</span>
</div>
</div>
<div v-else-if="col.fieldtype === costanti.FieldType.coordinates">
<CMapEditAddressByCoord
:visuMappa="false"
:editaddress="true"
v-model:model-value="myvalue"
@update:model-value="changeValRecCoordAddr"
></CMapEditAddressByCoord>
</div>
<div
v-else-if="
col.fieldtype === costanti.FieldType.number ||
@@ -368,6 +376,9 @@
v-else-if="col.fieldtype === costanti.FieldType.listimages"
style="text-align: center"
>
<span class="text-h7 text-weight-bold row justify-center">
{{ $t(col.label_trans) }}
</span>
<CGallery
:imagebak="
col.showpicprofile_ifnotset
@@ -399,10 +410,14 @@
>
</CAccomodation>
</div>
<div v-else-if="col.fieldtype === costanti.FieldType.image"
style="text-align: center">
<div
v-else-if="col.fieldtype === costanti.FieldType.image"
style="text-align: center"
>
<div v-if="canEdit">
{{ $t('reg.photo') }}
<span class="text-h7 text-weight-bold row justify-center">
{{ $t(col.label_trans) }}
</span>
<CGallery
:imagebak="
col.showpicprofile_ifnotset
@@ -1120,7 +1135,11 @@
<q-popup-edit
v-if="!isInModif && canEdit && noPopupeditByCol(col)"
v-model="myvalue"
:disable="(col.disable || disable) || (col.fieldtype === costanti.FieldType.image_and_filename)"
:disable="
col.disable ||
disable ||
col.fieldtype === costanti.FieldType.image_and_filename
"
:readonly="col.disable || disable"
:title="col.title ? col.title : col.titlepopupedit"
buttons
@@ -1197,6 +1216,14 @@
>
</CCurrencyValue>
</div>
<div v-else-if="col.fieldtype === costanti.FieldType.coordinates">
<CMapEditAddressByCoord
:visuMappa="false"
:editaddress="true"
v-model:model-value="scope.value"
@update:model-value="changeValRec"
></CMapEditAddressByCoord>
</div>
<div v-else-if="col.fieldtype === costanti.FieldType.hours">
<div v-if="visulabel">
<q-input
@@ -1552,7 +1579,11 @@
</CMyEditor>
</div>
</div>
<div v-else-if="col.fieldtype === costanti.FieldType.image_and_filename">
<div
v-else-if="
col.fieldtype === costanti.FieldType.image_and_filename
"
>
<div v-if="canEdit">
{{ $t('reg.photo') }}
<q-input

View File

@@ -92,7 +92,7 @@ export default defineComponent({
}
function navigaExt(obj: any) {
cmdExt(costanti.CMD_SHOW_PAGE, obj, null)
cmdExt(costanti.CMD_SHOW_PAGE, null, obj)
//let link = shared_consts.getDirectoryByTable(props.table) + '/' + obj._id
//console.log('link', link)
//$router.push(link)

View File

@@ -32,7 +32,7 @@
img-class="imgprofile"
height="270px"
fit="contain"
@click="cmdExt(costanti.CMD_SHOW_PAGE, myrec)"
@click="cmdExt(costanti.CMD_SHOW_PAGE, null, myrec)"
/>
<div>
{{ tools.getstrDateTimeEvent($t, myrec, false) }}
@@ -57,7 +57,7 @@
(myrec.mygrp && myrec.mygrp.photos.length > 0)
"
avatar
@click="cmdExt(costanti.CMD_SHOW_PAGE, myrec)"
@click="cmdExt(costanti.CMD_SHOW_PAGE, null, myrec)"
>
<q-badge
v-if="showBadge()"
@@ -286,7 +286,7 @@
<q-item
clickable
v-close-popup
@click="cmdExt(costanti.CMD_MODIFY, myrec._id)"
@click="cmdExt(costanti.CMD_MODIFY, myrec._id, null)"
>
<q-item-section side>
<q-icon name="fas fa-pencil-alt" />
@@ -298,7 +298,7 @@
<q-item
clickable
v-close-popup
@click="cmdExt(costanti.CMD_CLONE, myrec._id)"
@click="cmdExt(costanti.CMD_CLONE, myrec._id, null)"
>
<q-item-section side>
<q-icon name="fas fa-copy" />
@@ -310,7 +310,7 @@
<q-item
clickable
v-close-popup
@click="cmdExt(costanti.CMD_DELETE, myrec._id)"
@click="cmdExt(costanti.CMD_DELETE, myrec._id, null)"
>
<q-item-section side>
<q-icon name="fas fa-trash-alt" />

View File

@@ -21,7 +21,7 @@
v-if="circuit.photos"
avatar
class="items-center"
@click="cmdExt(costanti.CMD_OPEN_PAGE, circuit)"
@click="cmdExt(costanti.CMD_OPEN_PAGE, null, circuit)"
>
<q-avatar size="60px">
<q-img
@@ -48,7 +48,7 @@
</span>
</q-item-section>
<q-item-section @click="cmdExt(costanti.CMD_OPEN_PAGE, circuit)">
<q-item-section @click="cmdExt(costanti.CMD_OPEN_PAGE, null, circuit)">
<q-item-label
@click="naviga(tools.getPathByTableAndRec(table, circuit))"
><strong>{{ circuit.name }}</strong>
@@ -132,7 +132,7 @@
<q-item
clickable
v-close-popup
@click="cmdExt(costanti.CMD_MODIFY, circuit._id)"
@click="cmdExt(costanti.CMD_MODIFY, circuit._id, null)"
>
<q-item-section side>
<q-icon name="fas fa-pencil-alt" />
@@ -144,7 +144,7 @@
<q-item
clickable
v-close-popup
@click="cmdExt(costanti.CMD_DELETE, circuit._id)"
@click="cmdExt(costanti.CMD_DELETE, circuit._id, null)"
>
<q-item-section side>
<q-icon name="fas fa-trash-alt" />

View File

@@ -17,7 +17,7 @@
</q-avatar>
</q-item-section>
<q-item-section @click="cmdExt(costanti.CMD_OPEN_PAGE, myrec)">
<q-item-section @click="cmdExt(costanti.CMD_OPEN_PAGE, null, myrec)">
<q-item-label class="full-width">
<span v-for="(rec, ind) of myrec.recCatGrp" :key="ind"> <q-chip
dense
@@ -46,7 +46,7 @@
<q-menu>
<q-list style="min-width: 150px">
<q-item clickable v-close-popup
@click="cmdExt(costanti.CMD_MODIFY, myrec._id)">
@click="cmdExt(costanti.CMD_MODIFY, myrec._id, null)">
<q-item-section side>
<q-icon name="fas fa-pencil-alt"/>
</q-item-section>
@@ -54,7 +54,7 @@
</q-item>
</q-list>
<q-list style="min-width: 150px">
<q-item clickable v-close-popup @click="cmdExt(costanti.CMD_DELETE, myrec._id)">
<q-item clickable v-close-popup @click="cmdExt(costanti.CMD_DELETE, myrec._id, null)">
<q-item-section side>
<q-icon name="fas fa-trash-alt"/>
</q-item-section>

View File

@@ -1,9 +1,9 @@
const msg_website_it = {
ws: {
sitename: 'Riso',
siteshortname: 'RISO',
description: 'Siamo la Rete Italiana di Scambio Orizzontale, abbiamo creato questa piattaforma per metterla al servizio di chi vuole riscoprire il valore della condivisione e della cooperazione. Valori semplici e profondi che ci aiutano a ritrovare il Senso della Vita, perduto in questa società consumista, e riporti quei Sani Pricìpi Naturali ed Umani di Fratellanza che intere popolazioni antiche conoscevano bene.',
keywords: 'riso, piattaforma di scambio, rete italiana scambio orizzontale, riso app, riso piattaforma, scambio e baratto, momenta RIS',
sitename: 'AbitareGliIblei',
siteshortname: 'AbitareGliIblei',
description: 'Abitare Gli Iblei',
keywords: '',
},
hours: {
descr: 'Descrizione',

View File

@@ -10,7 +10,7 @@
<meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="version" content="1.0.53">
<meta name="version" content="1.0.55">
<meta name="viewport"
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">

View File

@@ -645,6 +645,7 @@ export interface ICatalogo {
formato: string[]
Categoria: string[]
Editore: string[]
pdf: boolean
}
@@ -1234,18 +1235,34 @@ export interface IAnim {
timingtype: string,
}
export interface ICoordLatLng {
lat: any
lng: any
}
export interface ICoordinates {
lat: any
long: any
}
export interface ICoordinatesGPS {
coordinates: [number, number]; // [lng, lat]
}
export interface ITipoDiAttivita {
_id: string
label: string
note: string
}
export interface ICoordGPS {
address: string
type: string
coordinates: [number, number]
}
export interface IAttivita {
_id: string
@@ -1256,7 +1273,7 @@ export interface IAttivita {
idSector: number[]
idCity: number[]
coordinate_gps: string
coordinate_gps: ICoordGPS
// FOTO
logo: IGallery

View File

@@ -8,6 +8,7 @@
<CFinder
:ind="tools.getIndMainCardsByTable(shared_consts.TABLES_ATTIVITAS)"
:table="shared_consts.TABLES_ATTIVITAS"
:showMap="true"
/>
</div>

View File

@@ -3,11 +3,14 @@ import {
} from 'vue-router'
import { cfgrouter } from './route-config'
import { useGlobalStore } from '@src/store/globalStore';
export default function (/* { store, ssrContext } */) {
import { useUserStore } from '@src/store/UserStore';
export default function ({ store, /*ssrContext } */}: {store: any}) {
const routermode = process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory
const userStore = useUserStore(store)
const createHistory = process.env.SERVER
? createMemoryHistory
: routermode
@@ -20,8 +23,10 @@ export default function (/* { store, ssrContext } */) {
),
});
/*
// Add the beforeEach hook
router.beforeEach((to, from, next) => {
console.log('beforeEach ROUTER')
// Execute your command before each navigation
// executeCommand();
@@ -31,11 +36,18 @@ export default function (/* { store, ssrContext } */) {
} catch(e) {
}
//if (to.matched.some(record => record.meta.requiresAuth) && !userStore.isLogged) {
// next({ name: 'login', query: { next: to.fullPath } })
//} else {
// next()
//}
// Continue with the navigation
next();
});
}); */
return router;
}

5
src/shims-vue.d.ts vendored
View File

@@ -6,3 +6,8 @@ declare module '*.vue' {
export default Component;
}
declare module '*.png' {
const value: string;
export default value;
}

View File

@@ -14,6 +14,8 @@ const msg_it = {
csv: 'Esporta Movimenti',
},
grid: {
showlist: 'Mostra la Lista',
showmap: 'Mostra la Mappa',
editvalues: 'Modifica Valori',
addrecord: 'Aggiungi Riga',
showprevedit: 'Mostra Eventi Passati',
@@ -277,6 +279,7 @@ const msg_it = {
},
scrivi: 'Contatta',
telegram: 'Messaggia su Telegram',
uscire: 'Uscire senza salvare?',
},
comp: {
Conta: 'Conta',
@@ -1807,7 +1810,7 @@ const msg_it = {
},
attivita: {
tipodiattivita: 'Tipologia',
name: 'Nome Attività',
nome_attivita: 'Nome Attività',
email: 'Email',
cell_phone: 'Telefono',
whatsapp: 'Whatsapp',

View File

@@ -262,7 +262,7 @@ export const costanti = {
small: true,
table: '',
},
/*{
{
visible: false,
title: ' Attività ',
subtitle: 'Artigiani, Aziende, Società, Negozi',
@@ -275,7 +275,7 @@ export const costanti = {
visuonstat: true,
small: false,
showfavorite: true,
},*/
},
],
GROUPCARDS: [
@@ -409,6 +409,7 @@ export const costanti = {
image: 3000,
image_and_filename: 3100,
imgcard: 3500,
coordinates: 3800,
select_by_server: 4000,
multiselect_by_server: 4010,
nationality: 4096,

View File

@@ -1261,6 +1261,13 @@ export const colAttivita = [
isadvanced_field: true,
numpag_carousel: 3,
}),
AddCol({
name: 'coordinate_gps',
label_trans: 'attivita.coordinate_gps',
fieldtype: costanti.FieldType.coordinates,
showWhen: costanti.showWhen.NewRec + costanti.showWhen.InPage + costanti.showWhen.InEdit + costanti.showWhen.InView_OnlyifExist,
required: false,
}),
AddCol({
name: 'idCity',
label_trans: 'skill.city',
@@ -1314,8 +1321,6 @@ export const colAttivita = [
}),
AddCol({ name: 'website', label_trans: 'attivita.website' }),
AddCol({ name: 'coordinate_gps', label_trans: 'attivita.coordinate_gps', fieldtype: costanti.FieldType.string }),
AddCol({
name: 'logo',
label_trans: 'attivita.logo',

View File

@@ -0,0 +1,19 @@
// geocoding.ts
export const getCityFromCoordinates = async (lat: number, lon: number): Promise<string | null> => {
const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Errore nella richiesta di geocoding');
}
const data = await response.json();
// Controlla se la città è presente nei risultati
return data.address?.city || data.address?.town || data.address?.village || null;
} catch (error) {
console.error('Errore durante il geocoding:', error);
return null;
}
};

View File

@@ -73,6 +73,7 @@ export const tools = {
COOK_MAP_CENTER_LAT: 'MAP_LAT',
COOK_MAP_CENTER_LONG: 'MAP_LONG',
COOK_MAP_ZOOM: 'MAP_Z',
COOK_CATEGORIA: 'CATEG',
FRIENDS_SEARCH: 'FR_SE',
GROUP_SEARCH: 'GR_SE',
@@ -6561,7 +6562,7 @@ export const tools = {
userStore.my.profile.useraccounts = res.useraccounts
}
$router.push('/circuits')
tools.showPositiveNotif($q, t('circuit.coins_sent', {qty: sendcoinrec.qty, symbol: circuit.symbol, dest}))
tools.showPositiveNotif($q, t('circuit.coins_sent', { qty: sendcoinrec.qty, symbol: circuit.symbol, dest }))
//tools.showPositiveNotif($q, t('circuit.coins_sendrequest_sent'))
} else {
tools.showNegativeNotif($q, res.errormsg)
@@ -8687,8 +8688,27 @@ export const tools = {
},
getRecByVersioneProd(versione: number) {
return shared_consts.VERSIONI_PRODOTTO.find((rec: any) => rec.value === versione)
return shared_consts.VERSIONI_PRODOTTO.find((rec: any) => rec.value === versione)
},
convertToDecimal6(stringValue: string) {
// Converti la stringa in un numero
try {
const numberValue = parseFloat(stringValue);
// Controlla se la conversione è un numero valido
if (isNaN(numberValue)) {
// console.error('Valore non valido:', stringValue);
return 0
}
// Usa toFixed per creare un numero con 6 decimali
return parseFloat(numberValue.toFixed(6));
} catch (error) {
console.error('Errore durante la conversione:', error);
return 0
}
}
// FINE !

View File

@@ -2122,6 +2122,7 @@ export const useGlobalStore = defineStore('GlobalStore', {
formato: [],
Categoria: [],
Editore: [],
pdf: false,
}
}

View File

@@ -16,6 +16,10 @@ import { CContainerCatalogoCard } from '@src/components/CContainerCatalogoCard'
import { CSelectUserActive } from '@src/components/CSelectUserActive'
import { ICatalogo, IProduct, ISearchList } from 'model'
import html2canvas from 'html2canvas'
// import { VueHtmlToPaper } from 'vue-html-to-paper'
import html2pdf from 'html2pdf.js'
import { fieldsTable } from '@store/Modules/fieldsTable'
export default defineComponent({
@@ -32,6 +36,7 @@ export default defineComponent({
formato: [],
Categoria: [],
Editore: [],
pdf: false,
}),
},
},
@@ -46,6 +51,9 @@ export default defineComponent({
const search = ref('')
const optauthors = ref(<any>[])
const pdfContent = ref(null);
const filter = ref(<any>{
author: '',
sort: 1,
@@ -105,6 +113,8 @@ export default defineComponent({
watch(() => cat.value, (newval, oldval) => {
if (cat.value) {
if (loadpage.value)
tools.setCookie(tools.COOK_CATEGORIA, cat.value.toString())
filter.value.author = '' // disattivo il filtro autore
resetSearch()
}
@@ -127,6 +137,8 @@ export default defineComponent({
// Se filtroAuthor attivato, allora evito il filtro per Categoria
if (filter.value.author) {
cat.value = '' // disattivo il filtro categoria
if (loadpage.value)
tools.setCookie(tools.COOK_CATEGORIA, '')
resetSearch()
}
@@ -145,10 +157,15 @@ export default defineComponent({
})
watch(() => cosa.value, (newval, oldval) => {
tools.setCookie(tools.COOK_COSA_PRODOTTI, cosa.value.toString())
if (cosa.value !== shared_consts.PROD.TUTTI)
cat.value = ''
calcArrProducts()
if (oldval !== 0) {
tools.setCookie(tools.COOK_COSA_PRODOTTI, cosa.value.toString())
if (cosa.value !== shared_consts.PROD.TUTTI) {
cat.value = ''
if (loadpage.value)
tools.setCookie(tools.COOK_CATEGORIA, '')
}
calcArrProducts()
}
})
function resetSearch() {
@@ -272,10 +289,10 @@ export default defineComponent({
if (!search.value) {
return arrprod
}
let lowerSearchText = search.value.toLowerCase();
let catstr = cat.value;
return arrprod.filter((product: IProduct) => {
let lowerName = product.productInfo.name!.toLowerCase();
const hasCategoria = !catstr || (catstr && product.productInfo.idCatProds?.includes(catstr));
@@ -309,6 +326,8 @@ export default defineComponent({
//++Todo: Per ora visualizzo solo il "Negozio" e non i GAS...
cosa.value = shared_consts.PROD.BOTTEGA
cat.value = tools.getCookie(tools.COOK_CATEGORIA, '')
//cosa.value = tools.getCookie(tools.COOK_COSA_PRODOTTI, shared_consts.PROD.GAS, true)
//if (cosa.value === shared_consts.PROD.TUTTI)
@@ -398,6 +417,49 @@ export default defineComponent({
return globalStore.getTableJoinByName(item.table, addall, addnone, item.filter)
})
const loadImage = (src) => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = src
})
}
const generatePDF = async () => {
$q.loading.show({
message: 'Caricamento immagini e generazione PDF in corso...'
})
try {
const element = document.getElementById('pdf-content')
const opt = {
margin: 1,
filename: 'catalogo_libri.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, useCORS: true },
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' }
}
await html2pdf().from(element).set(opt).save()
$q.loading.hide()
$q.notify({
color: 'positive',
message: 'PDF generato con successo!',
icon: 'check'
})
} catch (error) {
$q.loading.hide()
$q.notify({
color: 'negative',
message: 'Errore nella generazione del PDF',
icon: 'error'
})
console.error('Errore nella generazione del PDF:', error)
}
}
onMounted(mounted)
@@ -434,6 +496,8 @@ export default defineComponent({
mycolumns,
tabvisu,
getSearchText,
generatePDF,
pdfContent,
}
}
})

View File

@@ -1,11 +1,12 @@
<template>
<q-page>
<q-btn v-if="optcatalogo.pdf" label="Crea PDF" @click="generatePDF"></q-btn>
<!--<div ref="pdfContent" class="pdf-content">-->
<div class="text-center">
<q-spinner v-if="!loadpage" color="primary" size="3em" :thickness="2" />
</div>
<div v-if="loadpage" class="panel">
<div v-if="true"></div>
<div class="container">
<q-tabs v-model="tabvisu" dense class="bg-indigo text-white">
<q-tab name="categorie" icon="fas fa-folder-open" label="Categorie">
@@ -140,7 +141,6 @@
</q-tab-panel>
</q-tab-panels>
<div class="row justify-center q-mx-auto">
<q-select
v-model="filter.sort"
@@ -175,19 +175,62 @@
</div>
<div class="row justify-around">
<q-infinite-scroll
v-if="arrLoaded && arrLoaded.length > 0"
ref="myinfscroll"
:initial-index="0"
@load="onLoadScroll"
:offset="2000"
debounce="200"
class="q-pa-xs row items-start"
style="place-content: center"
>
<div>
<q-infinite-scroll
v-if="!optcatalogo.pdf && arrLoaded && arrLoaded.length > 0"
ref="myinfscroll"
:initial-index="0"
@load="onLoadScroll"
:offset="2000"
debounce="200"
class="q-pa-xs row items-start"
style="place-content: center"
>
<div
class="q-pa-xs"
v-for="(product, index) in arrLoaded"
:key="index"
>
<CContainerCatalogoCard
v-if="
product.active ||
(show_hide &&
productInfo.productTypes.includes(
shared_consts.PRODUCTTYPE.PRODUCT
))
"
:id="product._id"
:complete="false"
:cosa="cosa"
:optcatalogo="optcatalogo"
:options="{
show_short_descr: false,
show_price: false,
show_cat: false,
quante_col: 'c2',
in_3d: false,
}"
@selauthor="selauthor"
/>
<CProductCard
v-else-if="product.active || show_hide"
:id="product._id"
:complete="false"
:cosa="cosa"
/>
</div>
<template v-slot:loading>
<div class="text-center">
<q-spinner-dots color="primary" size="40px" />
</div>
</template>
</q-infinite-scroll>
<div
class="q-pa-xs"
v-for="(product, index) in arrLoaded"
v-else
id="pdf-content"
class="q-pa-xs row items-start"
style="place-content: center"
v-for="(product, index) in arrProducts"
:key="index"
>
<CContainerCatalogoCard
@@ -218,12 +261,7 @@
:cosa="cosa"
/>
</div>
<template v-slot:loading>
<div class="text-center">
<q-spinner-dots color="primary" size="40px" />
</div>
</template>
</q-infinite-scroll>
</div>
</div>
</div>
</div>