import { computed, defineComponent, onMounted, ref, toRef, watch } from 'vue'; import type { IMyElem, IMyPage } from '@src/model'; import { useGlobalStore } from '@store/globalStore'; import { LandingFooter } from '@src/components/LandingFooter'; import { CMyElem } from '@src/components/CMyElem'; import { CMyElemAdd } from '@src/components/CMyElemAdd'; import { CTitleBanner } from '@src/components/CTitleBanner'; import { CMyEditElem } from '@src/components/CMyEditElem'; import { CMyPageElem2 } from '@src/components/CMyPageElem2'; import { CExportImportPage } from '@src/components/CExportImportPage'; import { CImgTitle } from '../CImgTitle/index'; import { CTitle } from '../CTitle/index'; import { tools } from '@tools'; import { useQuasar } from 'quasar'; import { useI18n } from 'vue-i18n'; import { shared_consts } from '@src/common/shared_vuejs'; import objectId from '@src/js/objectId'; import { useRouter, useRoute } from 'vue-router'; export default defineComponent({ name: 'CMyPageElem', components: { LandingFooter, CImgTitle, CTitle, CMyElem, CMyEditElem, CMyPageElem2, CTitleBanner, CExportImportPage, CMyElemAdd, }, props: { title: String, mypath: { type: String, required: true, }, idPage: { type: String, required: false, default: '', }, img: { type: String, required: false, default: '', }, imgbackground: { type: String, required: false, default: '', }, sizes: { type: String, required: false, default: '', }, styleadd: { type: String, required: false, default: '', }, nofooter: { type: Boolean, required: false, default: false, }, }, setup(props, { emit }) { const rec = ref(null); const mypathin = toRef(props, 'mypath'); const myidPage = toRef(props, 'idPage'); const $q = useQuasar(); const { t } = useI18n(); const globalStore = useGlobalStore(); const $router = useRouter(); const $route = useRoute(); const visuadd = ref(false); const myElemSel = ref({}); const myElemParent = ref({}); const mywidthEditor = ref(400); const showexportPage = ref(false); const showimportPage = ref(false); const editOn = computed({ get(): boolean { return !!globalStore.editOn ? globalStore.editOn : false; }, set(value: boolean) { return tools.updateEditOn(value); }, }); const visuEditor = ref(false); const addOn = ref(false); const myelemVoid = ref({ _id: objectId(), active: true, type: shared_consts.ELEMTYPE.TEXT, container: '...', path: mypathin.value, } as IMyElem); const selElem = ref(globalStore.selElem); const site = ref(globalStore.site); const onloading = ref(false); const myelems = computed(() => { if (myidPage.value) return globalStore.getMyElemsByIdPage(myidPage.value); else if (mypathin.value) return globalStore.getMyElems(mypathin.value); else return null; }); const hideHeader = computed(() => { return rec.value?.hideHeader || $route.query?.hideHeader; }); const instampa = computed(() => { return $route.query?.stampa === '1'; }); async function load() { console.log('load', mypathin.value, 'idapp', tools.getEnv('VITE_APP_ID')); const query = $router.currentRoute.value.query; if (query.edit === '1') { globalStore.editOn = true; } if (mypathin.value !== '') { onloading.value = true; await globalStore.loadPage('/' + mypathin.value, 'cmypageelem').then((ris) => { rec.value = ris; if (ris && hideHeader.value) { globalStore.setshowHeader(false); } if (ris && instampa.value) { globalStore.setinStampa(true); } // console.log('LoadPage', ris) }); onloading.value = false; } if ( mypathin.value === 'home_logout' && globalStore.site.name === 'local' && !rec.value ) { $router.replace('/install_site'); } if (tools.isManager()) { // console.log('getcookie: ', editOn.value, mypathin.value) } } watch( () => props.mypath, (to: string, from: string) => { // console.log('... load', mypathin.value, props.mypath) selElem.value = {}; load(); } ); watch( () => editOn.value, () => { if (!editOn.value) { selElem.value = {}; } } ); async function mounted() { await load(); } function saveElem(myelem: IMyElem) { // } function changeVisuDrawer(path: string, edit: boolean) { globalStore.changeVisuDrawer(path, edit); } function toggleSize() { mywidthEditor.value = mywidthEditor.value === 400 ? 1050 : 400; } function deleteElem() { selElem.value = {}; visuEditor.value = false; } function selElemClick(myelem: IMyElem) { console.log('mypageelem selElemClick', myelem); try { selElem.value = {}; selElem.value = myelem; visuEditor.value = !!myelem; } catch (error) { console.log(error); } } async function duplicatePage() { await globalStore.duplicatePage(mypathin.value, $q, t); } async function deleteRow(myelemRow: any) { const row = globalStore.myelems; if (row) { // cerca la riga const myelem = globalStore.myelems.find( (elem: any) => elem.rows && elem.rows.some((r: any) => r._id === myelemRow._id) ); // Trova l'indice della riga da eliminare const rowIndex = myelem.rows.findIndex((r: any) => r._id === myelemRow._id); if (rowIndex !== -1) { // Rimuovi la riga dall'array myelem.rows.splice(rowIndex, 1); await globalStore.saveMyElem($q, t, myelem); } } else { console.error('Riga non trovata!'); } } async function deleteCol(myelemColumn: any) { const row = globalStore.myelems .flatMap((elem: any) => elem.rows || []) .find( (r: any) => r.columns && r.columns.some((col: any) => col._id === myelemColumn._id) ); if (row) { // Trova l'indice della colonna da eliminare const columnIndex = row.columns.findIndex( (col: any) => col._id === myelemColumn._id ); if (columnIndex !== -1) { // Rimuovi la colonna dall'array columns della riga row.columns.splice(columnIndex, 1); const parentElem = globalStore.myelems.find( (elem: any) => elem.rows && elem.rows.some((r: any) => r._id === row._id) ); if (parentElem) { // Trova l'indice della riga nel genitore const rowIndex = parentElem.rows.findIndex((r: any) => r._id === row._id); if (rowIndex !== -1) { // Aggiorna la riga nel suo genitore parentElem.rows[rowIndex] = row; // La riga è aggiornata // Salva l'elemento genitore che contiene la riga aggiornata await globalStore.saveMyElem($q, t, parentElem); } } } } else { console.error('Colonna non trovata!'); } } async function deleteElemento(myelem: any) { const row = globalStore.myelems .flatMap((elem: any) => elem.rows || []) .find( (r: any) => r.columns && r.columns.some( (col: any) => col.elems && col.elems.some((e: any) => e._id === myelem._id) ) ); if (row) { // Trova l'indice dell'elemento da eliminare const columnIndex = row.columns.findIndex( (col: any) => col.elems && col.elems.some((e: any) => e._id === myelem._id) ); if (columnIndex !== -1) { // Trova l'indice dell'elemento da eliminare const elemIndex = row.columns[columnIndex].elems.findIndex( (e: any) => e._id === myelem._id ); if (elemIndex !== -1) { // Rimuovi l'elemento dall'array elems della colonna row.columns[columnIndex].elems.splice(elemIndex, 1); const parentElem = globalStore.myelems.find( (elem: any) => elem.rows && elem.rows.some((r: any) => r._id === row._id) ); if (parentElem) { // Trova l'indice della riga nel genitore const rowIndex = parentElem.rows.findIndex((r: any) => r._id === row._id); if (rowIndex !== -1) { // Aggiorna la riga nel suo genitore parentElem.rows[rowIndex] = row; // La riga è aggiornata // Salva l'elemento genitore che contiene la riga aggiornata await globalStore.saveMyElem($q, t, parentElem); } } } } } else { console.error('Elemento non trovato!'); } } async function addNewElemSectRow( neword: number, myelemOrig: any, // di solito è la SECTION type: number, // shared_consts.ELEMTYPE.ROW o COLUMN idRowToAddDown?: string // _id della riga dopo cui inserire ) { // preparo il record da aggiungere (NON deve salvare qui dentro) const myelemDest = { path: myelemOrig.path, idPage: myelemOrig.idPage }; const newrec = await globalStore.prepareAddNewElem( neword, $q, t, myelemOrig, myelemDest, type ); // caso: stiamo aggiungendo una RIGA dentro una SECTION if ( myelemOrig.type === shared_consts.ELEMTYPE.SECTION && type === shared_consts.ELEMTYPE.ROW ) { if (idRowToAddDown) { await insertRowIntoSection(newrec, myelemOrig, idRowToAddDown, neword); return; } } // fallback: usa il flusso generico dello store (aggiunta colonna o altro) await globalStore.addNewElem($q, t, myelemOrig, newrec); } /** * Inserisce una riga dentro la section: * - se `idRowToAddDown` è dato, inserisce subito dopo quella riga * - altrimenti decide la posizione con `neword` (se fornito) o in coda * - reindicizza gli order e salva la SECTION */ async function insertRowIntoSection( newElem: any, sectionCandidate: any, idRowToAddDown?: string, neword?: number ) { const section = newElem // trova la section “vera” nello store (per sicurezza) const newRow = newElem.rows[newElem.rows.length - 1] if (!section) return; if (!Array.isArray(section.rows)) section.rows = []; // set campi minimi della riga appena creata newRow.type = shared_consts.ELEMTYPE.ROW; newRow.idElemParent = section._id; if (!Array.isArray(newRow.columns)) newRow.columns = []; let insertAt = section.rows.length; // default: in coda if (idRowToAddDown) { const idx = section.rows.findIndex((r: any) => r._id === idRowToAddDown); if (idx !== -1) { insertAt = idx; } } else if (Number.isFinite(neword)) { // se è stato passato un order desiderato, inserisci nella posizione coerente // (l’array è 0-based, order tipicamente 1-based) insertAt = Math.max(0, Math.min(section.rows.length, Number(neword) - 1)); } section.rows.splice(insertAt, 0, newRow); // reindex orders: 1,2,3,... for (let i = 0; i < section.rows.length - 1; i++) { section.rows[i].order = i + 1; } // elimina l'ultima riga section.rows.pop(); // salva SEMPRE la section (contenitore) await globalStore.saveMyElem($q, t, section); } async function swapRows(row1: any, row2: any) { const parentElem = globalStore.myelems.find( (elem: any) => elem.rows && elem.rows.some((r: any) => r._id === row1._id) ); if (parentElem) { // Trova l'indice della riga nel genitore const rowIndex1 = parentElem.rows.findIndex((r: any) => r._id === row1._id); const rowIndex2 = parentElem.rows.findIndex((r: any) => r._id === row2._id); if (rowIndex1 !== -1 && rowIndex2 !== -1) { // Scambia le righe nel genitore [parentElem.rows[rowIndex1], parentElem.rows[rowIndex2]] = [ parentElem.rows[rowIndex2], parentElem.rows[rowIndex1], ]; // Salva l'elemento genitore che contiene la riga aggiornata await globalStore.saveMyElem($q, t, parentElem); } } else { console.error('Elemento non trovato!'); } } function AddedNewElem(newrec: any) { emit('selElemClick', newrec); } function getColClasses(col: any, rowOrCount?: any, idx = 0) { // 1) Quante colonne ci sono nella riga? const colsCount = typeof rowOrCount === 'number' ? rowOrCount : rowOrCount?.columns?.length || 1; const n = Math.max(1, Number(colsCount) || 1); // 2) Suddivisione equa su md+ (tablet orizz. / desktop) const base = Math.floor(12 / n); const rest = 12 % n; // avanzo da distribuire alle prime 'rest' colonne const auto = base + (idx < rest ? 1 : 0); // 3) Override da DB se presenti (vincono sull'auto) const xs = clamp12(col?.xs ?? 12); // mobile: stack const sm = clamp12(col?.sm ?? 12); // piccoli tablet: stack const md = clamp12(col?.md ?? auto); const lg = clamp12(col?.lg ?? auto); const xl = clamp12(col?.xl ?? auto); return { 'q-pa-sm': true, [`col-${xs}`]: true, [`col-sm-${sm}`]: true, [`col-md-${md}`]: true, [`col-lg-${lg}`]: true, [`col-xl-${xl}`]: true, }; } function clamp12(v: any) { const n = Number(v); if (!Number.isFinite(n) || n <= 0) return 12; return Math.max(1, Math.min(12, Math.round(n))); } onMounted(mounted); return { rec, myelems, mypathin, editOn, visuEditor, addOn, tools, shared_consts, myelemVoid, selElemClick, selElem, saveElem, changeVisuDrawer, mywidthEditor, toggleSize, onloading, deleteElem, duplicatePage, showexportPage, showimportPage, hideHeader, myidPage, addNewElemSectRow, deleteCol, deleteRow, deleteElemento, visuadd, AddedNewElem, myElemSel, myElemParent, getColClasses, }; }, });