- inizio di modifiche all'editor di Pagine Web
This commit is contained in:
4
.env
4
.env
@@ -1,6 +1,6 @@
|
||||
VITE_APP_VERSION="1.2.68"
|
||||
VITE_APP_VERSION="1.2.69"
|
||||
VITE_LANG_DEFAULT="it"
|
||||
VITE_PAO_APP_ID="KKPPAA5KJK435J3KSS9F9D8S9F8SD98F9SDF"
|
||||
VITE_SERVICE_WORKER_FILE="sw-1.2.68.js"
|
||||
VITE_SERVICE_WORKER_FILE="sw-1.2.69.js"
|
||||
VITE_PROJECT_ID_MAIN="5cc0a13fe5c9d156728f400a"
|
||||
VITE_VUE_ROUTER_MODE="history"
|
||||
@@ -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.2.68">
|
||||
<meta name="version" content="1.2.69">
|
||||
<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<% } %>">
|
||||
|
||||
|
||||
96
package.json
96
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuovomondo",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "Nuovo Mondo",
|
||||
"productName": "Nuovo Mondo",
|
||||
"author": "Surya",
|
||||
@@ -9,11 +9,11 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "APP_VERSION='1.2.69' PORT=8083 quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "quasar build -m spa",
|
||||
@@ -21,117 +21,117 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
"postinstall": "quasar prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cubejs-client/core": "^1.2.26",
|
||||
"@quasar/extras": "^1.16.17",
|
||||
"@cubejs-client/core": "^1.3.21",
|
||||
"@quasar/extras": "^1.17.0",
|
||||
"@quasar/quasar-ui-qcalendar": "^4.1.2",
|
||||
"@types/jsbarcode": "^3.11.4",
|
||||
"@types/leaflet": "^1.9.17",
|
||||
"@vue/compat": "^3.5.13",
|
||||
"@vue/compiler-sfc": "^3.5.13",
|
||||
"@types/leaflet": "^1.9.18",
|
||||
"@vue/compat": "^3.5.16",
|
||||
"@vue/compiler-sfc": "^3.5.16",
|
||||
"@vuelidate/core": "^2.0.3",
|
||||
"@vuelidate/validators": "^2.0.4",
|
||||
"acorn": "^8.14.1",
|
||||
"acorn": "^8.15.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"apexcharts": "^4.7.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"axios": "^1.8.4",
|
||||
"axios": "^1.9.0",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"chart.js": "^4.4.8",
|
||||
"core-js": "^3.41.0",
|
||||
"chart.js": "^4.4.9",
|
||||
"core-js": "^3.43.0",
|
||||
"crypto-browserify": "^3.12.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"echarts": "5.6.0",
|
||||
"eslint-plugin-n": "^17.16.2",
|
||||
"eslint-plugin-n": "^17.19.0",
|
||||
"eslint-plugin-quasar": "^1.1.0",
|
||||
"graphql": "^16.10.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"gsap": "^3.12.7",
|
||||
"gsap": "^3.13.0",
|
||||
"html2pdf.js": "^0.10.3",
|
||||
"jquery": "^3.7.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsbarcode": "^3.11.6",
|
||||
"jsbarcode": "^3.12.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-routing-machine": "^3.2.12",
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mongoose-paginate-v2": "^1.9.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.1",
|
||||
"qrcode-vue3": "^1.7.1",
|
||||
"pinia": "^3.0.3",
|
||||
"quasar": "^2.18.1",
|
||||
"quasar-extras": "^2.0.9",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"scrollreveal": "^4.0.9",
|
||||
"typescript-eslint": "^8.27.0",
|
||||
"vee-validate": "^4.15.0",
|
||||
"vue": "^3.5.13",
|
||||
"typescript-eslint": "^8.34.0",
|
||||
"vee-validate": "^4.15.1",
|
||||
"vue": "^3.5.16",
|
||||
"vue-class-component": "^8.0.0-rc.1",
|
||||
"vue-country-code": "^1.1.3",
|
||||
"vue-echarts": "^7.0.3",
|
||||
"vue-i18n": "^11.1.2",
|
||||
"vue-i18n": "^11.1.5",
|
||||
"vue-idb": "^0.2.0",
|
||||
"vue-image-zoomer": "^2.4.4",
|
||||
"vue-property-decorator": "^10.0.0-rc.3",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-scroll-reveal": "^2.1.0",
|
||||
"vue-social-sharing": "^4.0.0-alpha4",
|
||||
"vue-svgicon": "^4.0.0-alpha.3",
|
||||
"vue-timeago3": "^2.3.2",
|
||||
"vue2-dragula": "^2.5.5",
|
||||
"vue3-pdf-app": "^1.0.3",
|
||||
"vue3-apexcharts": "^1.8.0",
|
||||
"vue3-qr-reader": "^1.0.0",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuex": "^4.1.0",
|
||||
"vuex-router-sync": "^6.0.0-rc.1",
|
||||
"workbox-core": "^7.3.0",
|
||||
"workbox-precaching": "^7.3.0",
|
||||
"workbox-routing": "^7.3.0",
|
||||
"workbox-strategies": "^7.3.0",
|
||||
"workbox-window": "^7.3.0"
|
||||
"workbox-window": "^7.3.0",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.23.0",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.5",
|
||||
"@quasar/app-vite": "^2.1.4",
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
||||
"@quasar/app-vite": "^2.2.1",
|
||||
"@types/google.maps": "^3.58.1",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^22.13.11",
|
||||
"@types/node": "^24.0.1",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/vue-tel-input": "^2.1.7",
|
||||
"@types/vuelidate": "^0.7.22",
|
||||
"@vue/devtools": "^7.7.2",
|
||||
"@vue/devtools": "^7.7.6",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"@vue/eslint-config-typescript": "^14.5.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "9",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"eslint-plugin-vue": "^10.2.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"globals": "^16.0.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
"jest": "^29.7.0",
|
||||
"globals": "^16.2.0",
|
||||
"http-proxy-middleware": "^3.0.5",
|
||||
"jest": "^30.0.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"nodemon": "^3.1.9",
|
||||
"npm-check-updates": "^17.1.16",
|
||||
"parcel": "^2.14.1",
|
||||
"postcss": "^8.5.3",
|
||||
"nodemon": "^3.1.10",
|
||||
"npm-check-updates": "^18.0.1",
|
||||
"parcel": "^2.15.2",
|
||||
"postcss": "^8.5.5",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prettier": "3",
|
||||
"strip-ansi": "=7.1.0",
|
||||
"ts-jest": "^29.2.6",
|
||||
"typescript": "5.7.3",
|
||||
"vite-plugin-checker": "^0.9.1",
|
||||
"ts-jest": "^29.4.0",
|
||||
"typescript": "5.8.3",
|
||||
"vite-plugin-checker": "^0.9.3",
|
||||
"vue-cli-plugin-element-ui": "^1.1.4",
|
||||
"vue-eslint-parser": "^10.1.1",
|
||||
"vue-tsc": "^2.2.8",
|
||||
"vue-eslint-parser": "^10.1.3",
|
||||
"vue-tsc": "^2.2.10",
|
||||
"vueify": "^9.4.1",
|
||||
"workbox-build": "^7.3.0"
|
||||
},
|
||||
|
||||
@@ -238,7 +238,7 @@ export default defineConfig((ctx) => {
|
||||
port: parseInt(process.env.PORT, 10),
|
||||
vueDevtools: false, // automatically opening remote Vue Devtools
|
||||
open: false, // opens browser window automatically
|
||||
hot: true, // Disable hot module replacement
|
||||
hot: true, // Enable hot module replacement
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': '*',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cnm",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "Comunita Nuovo Mondo",
|
||||
"productName": "ComunitaNuovoMondo",
|
||||
"author": "Surya",
|
||||
@@ -9,7 +9,7 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production quasar build -m pwa",
|
||||
@@ -21,8 +21,8 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
|
||||
@@ -47,7 +47,7 @@ function getDynamicPages(site: ISites): IListRoutes[] {
|
||||
const baseroutes: IListRoutes[] = [
|
||||
{
|
||||
active: true,
|
||||
order: 5,
|
||||
order: -1,
|
||||
path: '/',
|
||||
materialIcon: 'home',
|
||||
name: 'pages.home',
|
||||
@@ -321,3 +321,5 @@ export const static_data = {
|
||||
preLoadImages,
|
||||
preloadedimages,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "freeplanet",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "freeplanet",
|
||||
"productName": "freeplanet",
|
||||
"author": "Surya",
|
||||
@@ -9,11 +9,11 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8087 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "PORT=8087 APP_VERSION='1.2.69' quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "quasar build -m spa",
|
||||
@@ -21,8 +21,8 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8097 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8087 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8097 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8087 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gruppomacro",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"productName": "Gruppo Macro",
|
||||
"description": "Il Gruppo Editoriale Macro, attivo dal 1987, è leader europeo nella pubblicazione di libri per il benessere e la consapevolezza. Con oltre 1.500 titoli, promuove una visione armonica del mondo, offrendo opere di autori internazionali e italiani come Gregg Braden, Bruce Lipton, Joe Dispenza, Louise Hay, Eckhart Tolle e molti altri. Scopri un'editoria che abbraccia il corpo, la mente, lo spirito e l'ecologia.",
|
||||
"author": "Surya",
|
||||
@@ -9,20 +9,20 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8089 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "PORT=8089 APP_VERSION='1.2.69' quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "APP_VERSION='1.2.68' quasar build -m spa",
|
||||
"buildspa": "APP_VERSION='1.2.69' quasar build -m spa",
|
||||
"lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"",
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8089 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8089 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "kolibrilab",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "kolibrilab",
|
||||
"productName": "kolibrilab",
|
||||
"author": "Surya Paolo",
|
||||
@@ -8,11 +8,11 @@
|
||||
"keywords": [],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "quasar build -m spa",
|
||||
@@ -20,8 +20,8 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint --ext .ts,.vue --ignore-path .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
||||
"spanorefresh": "NODE_ENV=development NODE_OPTIONS=--max_old_space_size=4096 DEBUG=v8:* quasar dev -m spa",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
VITE_APP_ID="10"
|
||||
VITE_APP_URL="https://test.nuovomondo.app"
|
||||
VITE_MONGODB_HOST="https://testapi.nuovomondo.app"
|
||||
VITE_LOGO_REG='cmn-logo-full.png'
|
||||
VITE_APP_ID="13"
|
||||
VITE_APP_URL="https://riso.app"
|
||||
VITE_MONGODB_HOST="https://api.riso.app"
|
||||
VITE_LOGO_REG='riso-logo-full.png'
|
||||
VITE_PUBLICKEY_PUSH="BGXRf1TgcqocqD6J7qnRgCG7AvM2lxAoW7peb7UEzB4SxBb6DxGRdJ0UvD9ewnrB9KrSrh0-aDCODXBm7sZ1DDs"
|
||||
VITE_DEBUG="1"
|
||||
VITE_VUE_APP_ISTEST=1
|
||||
DIRECTORY_LOCAL="myprojplanet_vite"
|
||||
DIRECTORY_SERVER="/var/www/nodejs_test.riso_server"
|
||||
SERVERDIR_WEBSITE="/var/www/test.nuovomondo.app"
|
||||
VITE_DEBUG="0"
|
||||
VITE_VUE_APP_ISTEST="0"
|
||||
DIRECTORY_LOCAL=myprojplanet_vite
|
||||
DIRECTORY_SERVER=/var/www/nodejs_riso_server
|
||||
SERVERDIR_WEBSITE="/var/www/riso.app"
|
||||
SERVERPW_WEBSITE="pwdadmin@1AOK"
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuovomondo",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "Nuovo Mondo",
|
||||
"productName": "Nuovo Mondo",
|
||||
"author": "Surya",
|
||||
@@ -9,11 +9,11 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "APP_VERSION='1.2.69' PORT=8083 quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "quasar build -m spa",
|
||||
@@ -21,74 +21,74 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
"postinstall": "quasar prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cubejs-client/core": "^1.2.26",
|
||||
"@quasar/extras": "^1.16.17",
|
||||
"@cubejs-client/core": "^1.3.21",
|
||||
"@quasar/extras": "^1.17.0",
|
||||
"@quasar/quasar-ui-qcalendar": "^4.1.2",
|
||||
"@types/jsbarcode": "^3.11.4",
|
||||
"@types/leaflet": "^1.9.17",
|
||||
"@vue/compat": "^3.5.13",
|
||||
"@vue/compiler-sfc": "^3.5.13",
|
||||
"@types/leaflet": "^1.9.18",
|
||||
"@vue/compat": "^3.5.16",
|
||||
"@vue/compiler-sfc": "^3.5.16",
|
||||
"@vuelidate/core": "^2.0.3",
|
||||
"@vuelidate/validators": "^2.0.4",
|
||||
"acorn": "^8.14.1",
|
||||
"acorn": "^8.15.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"apexcharts": "^4.7.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"axios": "^1.8.4",
|
||||
"axios": "^1.9.0",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"chart.js": "^4.4.8",
|
||||
"core-js": "^3.41.0",
|
||||
"chart.js": "^4.4.9",
|
||||
"core-js": "^3.43.0",
|
||||
"crypto-browserify": "^3.12.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"echarts": "5.6.0",
|
||||
"eslint-plugin-n": "^17.16.2",
|
||||
"eslint-plugin-n": "^17.19.0",
|
||||
"eslint-plugin-quasar": "^1.1.0",
|
||||
"graphql": "^16.10.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"gsap": "^3.12.7",
|
||||
"gsap": "^3.13.0",
|
||||
"html2pdf.js": "^0.10.3",
|
||||
"jquery": "^3.7.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsbarcode": "^3.11.6",
|
||||
"jsbarcode": "^3.12.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-routing-machine": "^3.2.12",
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mongoose-paginate-v2": "^1.9.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.1",
|
||||
"qrcode-vue3": "^1.7.1",
|
||||
"pinia": "^3.0.3",
|
||||
"quasar": "^2.18.1",
|
||||
"quasar-extras": "^2.0.9",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"scrollreveal": "^4.0.9",
|
||||
"typescript-eslint": "^8.27.0",
|
||||
"vee-validate": "^4.15.0",
|
||||
"vue": "^3.5.13",
|
||||
"typescript-eslint": "^8.34.0",
|
||||
"vee-validate": "^4.15.1",
|
||||
"vue": "^3.5.16",
|
||||
"vue-class-component": "^8.0.0-rc.1",
|
||||
"vue-country-code": "^1.1.3",
|
||||
"vue-echarts": "^7.0.3",
|
||||
"vue-i18n": "^11.1.2",
|
||||
"vue-i18n": "^11.1.5",
|
||||
"vue-idb": "^0.2.0",
|
||||
"vue-image-zoomer": "^2.4.4",
|
||||
"vue-property-decorator": "^10.0.0-rc.3",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-scroll-reveal": "^2.1.0",
|
||||
"vue-social-sharing": "^4.0.0-alpha4",
|
||||
"vue-svgicon": "^4.0.0-alpha.3",
|
||||
"vue-timeago3": "^2.3.2",
|
||||
"vue2-dragula": "^2.5.5",
|
||||
"vue3-pdf-app": "^1.0.3",
|
||||
"vue3-apexcharts": "^1.8.0",
|
||||
"vue3-qr-reader": "^1.0.0",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuex": "^4.1.0",
|
||||
"xlsx": "^0.18.5",
|
||||
"vuex-router-sync": "^6.0.0-rc.1",
|
||||
"workbox-core": "^7.3.0",
|
||||
"workbox-precaching": "^7.3.0",
|
||||
@@ -97,41 +97,41 @@
|
||||
"workbox-window": "^7.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.23.0",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.5",
|
||||
"@quasar/app-vite": "^2.1.4",
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
||||
"@quasar/app-vite": "^2.2.1",
|
||||
"@types/google.maps": "^3.58.1",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^22.13.11",
|
||||
"@types/node": "^24.0.1",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/vue-tel-input": "^2.1.7",
|
||||
"@types/vuelidate": "^0.7.22",
|
||||
"@vue/devtools": "^7.7.2",
|
||||
"@vue/devtools": "^7.7.6",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"@vue/eslint-config-typescript": "^14.5.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "9",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"eslint-plugin-vue": "^10.2.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"globals": "^16.0.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
"jest": "^29.7.0",
|
||||
"globals": "^16.2.0",
|
||||
"http-proxy-middleware": "^3.0.5",
|
||||
"jest": "^30.0.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"nodemon": "^3.1.9",
|
||||
"npm-check-updates": "^17.1.16",
|
||||
"parcel": "^2.14.1",
|
||||
"postcss": "^8.5.3",
|
||||
"nodemon": "^3.1.10",
|
||||
"npm-check-updates": "^18.0.1",
|
||||
"parcel": "^2.15.2",
|
||||
"postcss": "^8.5.5",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prettier": "3",
|
||||
"strip-ansi": "=7.1.0",
|
||||
"ts-jest": "^29.2.6",
|
||||
"typescript": "5.7.3",
|
||||
"vite-plugin-checker": "^0.9.1",
|
||||
"ts-jest": "^29.4.0",
|
||||
"typescript": "5.8.3",
|
||||
"vite-plugin-checker": "^0.9.3",
|
||||
"vue-cli-plugin-element-ui": "^1.1.4",
|
||||
"vue-eslint-parser": "^10.1.1",
|
||||
"vue-tsc": "^2.2.8",
|
||||
"vue-eslint-parser": "^10.1.3",
|
||||
"vue-tsc": "^2.2.10",
|
||||
"vueify": "^9.4.1",
|
||||
"workbox-build": "^7.3.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nutriben",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "Nutriben",
|
||||
"productName": "Nutriben",
|
||||
"author": "Surya",
|
||||
@@ -9,20 +9,20 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8093 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "PORT=8093 APP_VERSION='1.2.69' quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "APP_VERSION='1.2.68' quasar build -m spa",
|
||||
"buildspa": "APP_VERSION='1.2.69' quasar build -m spa",
|
||||
"lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"",
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "piuchebuono",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"description": "PiuCheBuono",
|
||||
"productName": "PiuCheBuono",
|
||||
"author": "Surya",
|
||||
@@ -9,11 +9,11 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PORT=8085 APP_VERSION='1.2.68' quasar dev",
|
||||
"dev": "PORT=8085 APP_VERSION='1.2.69' quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "quasar build -m spa",
|
||||
@@ -21,8 +21,8 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "riso",
|
||||
"version": "1.2.68",
|
||||
"version": "1.2.69",
|
||||
"productName": "Riso 💚 - Rete Italiana Scambi Orizzontali",
|
||||
"description": "Progetto RISO (Rete Italiana Scambi Orizzontali) promuove una rete di comunità locali che favoriscono scambi di beni, servizi e ospitalità. Con l'App RISO, sviluppata per facilitare il baratto, il dono e l'uso di monete alternative come i RIS, il progetto crea legami autentici basati sulla fiducia e sostenibilità. Partecipa agli scambi e costruisci una comunità più consapevole e autosufficiente.",
|
||||
"author": "Surya",
|
||||
@@ -9,11 +9,11 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "APP_VERSION='1.2.68' PORT=8084 quasar dev",
|
||||
"dev": "APP_VERSION='1.2.69' PORT=8084 quasar dev",
|
||||
"dev_noCheck": "SKIP_TSC=true quasar dev",
|
||||
"build": "quasar build",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.68' quasar build -m pwa",
|
||||
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.69' quasar build -m pwa",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"type-check:watch": "vue-tsc --noEmit --watch",
|
||||
"buildspa": "quasar build -m spa",
|
||||
@@ -21,8 +21,8 @@
|
||||
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
|
||||
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
|
||||
"pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.68' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8084 APP_VERSION='1.2.68' quasar dev",
|
||||
"pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.69' quasar dev -m pwa",
|
||||
"spa": "NODE_ENV=development PORT=8084 APP_VERSION='1.2.69' quasar dev",
|
||||
"debug": "quasar dev --mode debug",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"generate-sw": "workbox generateSW workbox-config.js",
|
||||
|
||||
@@ -1 +1 @@
|
||||
TERMINA DI LAVORARE SU nuovomondo.app: (Sovrascrivo!)
|
||||
TERMINA DI LAVORARE SU riso.app: (Sovrascrivo!)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* global workbox */
|
||||
/* global cfgenv */
|
||||
|
||||
const VITE_APP_VERSION = '1.2.68';
|
||||
const VITE_APP_VERSION = '1.2.69';
|
||||
|
||||
// Costanti di configurazione
|
||||
const DYNAMIC_CACHE = 'dynamic-cache-v2';
|
||||
|
||||
@@ -174,6 +174,9 @@ export const shared_consts = {
|
||||
SEARCHPRODUCT: 430,
|
||||
RACCOLTE_CATALOGHI: 450,
|
||||
STAT_PAGES: 460,
|
||||
SECTION: 1000,
|
||||
ROW: 1100,
|
||||
COLUMN: 1200,
|
||||
},
|
||||
|
||||
QUERYTYPE_MYGROUP: 1,
|
||||
@@ -2008,6 +2011,22 @@ export const shared_consts = {
|
||||
],
|
||||
|
||||
TypesElem: [
|
||||
{
|
||||
value: 1000, //ELEMTYPE.SECTION,
|
||||
label: 'Sezione',
|
||||
icon: 'fas fa-th-large',
|
||||
},
|
||||
{
|
||||
value: 1100, //ELEMTYPE.ROW,
|
||||
label: 'Riga',
|
||||
icon: 'fas fa-th-large',
|
||||
},
|
||||
{
|
||||
value: 1200, // ELEMTYPE.COLUMN,
|
||||
label: 'Colonna',
|
||||
icon: 'fas fa-th-large',
|
||||
},
|
||||
|
||||
{
|
||||
value: 20,
|
||||
label: 'Testo',
|
||||
|
||||
@@ -11,6 +11,7 @@ import { CMyTeacher } from '@src/components/CMyTeacher'
|
||||
// @ts-ignore
|
||||
import MixinOperator from '../../mixins/mixin-operator'
|
||||
import MixinUsers from '../../mixins/mixin-users'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CCardDiscipline',
|
||||
|
||||
@@ -357,7 +357,7 @@ export default defineComponent({
|
||||
recOrderCart.value = rissconto.mycart
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.log('error ApplicaSconto', error);
|
||||
tools.showNegativeNotif($q, `Sconto Non Applicato! ${error?.message || ''}`);
|
||||
codice_sconto.value = '';
|
||||
|
||||
19
src/components/CColumn/CColumn.vue
Normal file
19
src/components/CColumn/CColumn.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="column">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CColumn'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.column {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -426,6 +426,7 @@ export default defineComponent({
|
||||
function isIMG() {
|
||||
return props.filetype === shared_consts.FILETYPE.IMG;
|
||||
}
|
||||
/*
|
||||
const uploadFactory = async (files: readonly File[]) => {
|
||||
const userStore = useUserStore();
|
||||
const url = getUrl();
|
||||
@@ -451,11 +452,11 @@ export default defineComponent({
|
||||
// usa la tua logica centralizzata
|
||||
Api.checkTokenScaduto(
|
||||
status,
|
||||
/*evitaloop*/ false,
|
||||
false,
|
||||
url,
|
||||
'POST',
|
||||
null,
|
||||
/*setAuthToken*/ true
|
||||
true
|
||||
);
|
||||
if (ret !== null) {
|
||||
// token aggiornato -> ritenta UNA volta
|
||||
@@ -475,7 +476,7 @@ export default defineComponent({
|
||||
throw err2;
|
||||
}
|
||||
}
|
||||
};
|
||||
}; */
|
||||
|
||||
onMounted(created);
|
||||
|
||||
@@ -514,7 +515,6 @@ export default defineComponent({
|
||||
isIMG,
|
||||
isPDF,
|
||||
upl,
|
||||
uploadFactory,
|
||||
t,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,44 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="arrprovince" id="map" :style="`height:${myheight()}px; width:99%`">
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div :style="`height:${myheight()}px; width:99%`">
|
||||
<l-map
|
||||
v-model="zoom"
|
||||
v-model:zoom="zoom"
|
||||
:center="[42.71, 12.934]"
|
||||
@move="log('move')"
|
||||
@click="getCoordinates"
|
||||
>
|
||||
<l-tile-layer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
></l-tile-layer>
|
||||
<l-control-layers />
|
||||
<span v-for="provincia in arrprovince" :key="provincia.nome">
|
||||
<l-marker-cluster :options="clusterOptions">
|
||||
<l-marker
|
||||
v-if="provincia.userCount > 0"
|
||||
:lat-lng="[provincia.lat, provincia.long]"
|
||||
>
|
||||
<l-popup
|
||||
>{{ provincia.descr }}:
|
||||
{{ provincia.userCount }} utenti</l-popup
|
||||
>
|
||||
</l-marker>
|
||||
</l-marker-cluster>
|
||||
</span>
|
||||
|
||||
</l-map>
|
||||
<button @click="changeIcon">New kitten icon</button>
|
||||
</div>
|
||||
-->
|
||||
<div class="map-container">
|
||||
<div id="map" style="height: 500px;"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" src="./CMapUsers.ts">
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted } from 'vue'
|
||||
import { tools } from '@tools'
|
||||
import { useGlobalStore } from 'app/src/store'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CMapUsers',
|
||||
setup() {
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize map logic here
|
||||
/*tools.initUserMap('map', {
|
||||
center: { lat: 45.4642, lng: 9.1900 }, // Default to Milan coordinates
|
||||
zoom: 6
|
||||
})*/
|
||||
})
|
||||
|
||||
return { tools, globalStore }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './CMapUsers.scss';
|
||||
<style scoped>
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -628,6 +628,15 @@ export default defineComponent({
|
||||
);
|
||||
}
|
||||
|
||||
function isLayoutContainer() {
|
||||
const t = myel.value?.type;
|
||||
return (
|
||||
t === shared_consts.ELEMTYPE.SECTION ||
|
||||
t === shared_consts.ELEMTYPE.ROW ||
|
||||
t === shared_consts.ELEMTYPE.COLUMN
|
||||
);
|
||||
}
|
||||
|
||||
/*function updateElem(myvalue: any) {
|
||||
console.log('updateElem', myvalue)
|
||||
if (myel.value.type === shared_consts.ELEMTYPE.IMGTITLE) {
|
||||
|
||||
@@ -1,87 +1,122 @@
|
||||
import type { PropType } from 'vue';
|
||||
import {
|
||||
computed,
|
||||
defineComponent, onMounted, ref, toRef, watch, nextTick,
|
||||
} from 'vue'
|
||||
import { computed, defineComponent, onMounted, ref, toRef, watch, nextTick } from 'vue';
|
||||
|
||||
import type { IOptCatalogo, ICoordGPS, IMyElem, ISocial } from '@src/model';
|
||||
import { IMyCard, IMyPage, IOperators } from '@src/model'
|
||||
import { useGlobalStore } from '@store/globalStore'
|
||||
import { IMyCard, IMyPage, IOperators } from '@src/model';
|
||||
import { useGlobalStore } from '@store/globalStore';
|
||||
|
||||
import { CImgTitle } from '../CImgTitle/index'
|
||||
import { CImgPoster } from '@src/components/CImgPoster'
|
||||
import { CTitle } from '@src/components/CTitle/index'
|
||||
import { CGridOriz } from '@src/components/CGridOriz/index'
|
||||
import { ChatBot } from '@src/components/ChatBot/index'
|
||||
import { CCatalogList } from '@src/components/CCatalogList/index'
|
||||
import { CRaccoltaCataloghi } from '@src/components/CRaccoltaCataloghi/index'
|
||||
import { tools } from '@tools'
|
||||
import { shared_consts } from '@src/common/shared_vuejs'
|
||||
import { LandingFooter } from '@src/components/LandingFooter'
|
||||
import { CMyActivities } from '@src/components/CMyActivities'
|
||||
import { CECommerce } from '@src/components/CECommerce'
|
||||
import { CStatMacro } from '@src/components/CStatMacro'
|
||||
import { CSearchProduct } from '@src/components/CSearchProduct'
|
||||
import { CPageViewStats } from '@src/components/CPageViewStats'
|
||||
import { CQRCode } from '@src/components/CQRCode'
|
||||
import { CAITools } from '@src/components/CAITools'
|
||||
import { CCatalogo } from '@src/components/CCatalogo'
|
||||
import { CRaccolta } from '@src/components/CRaccolta'
|
||||
import { CImgTitle } from '../CImgTitle/index';
|
||||
import { CImgPoster } from '@src/components/CImgPoster';
|
||||
import CSection from '@src/components/CSection/CSection.vue';
|
||||
import CRow from '@src/components/CRow/CRow.vue';
|
||||
import CColumn from '@src/components/CColumn/CColumn.vue';
|
||||
import { CTitle } from '@src/components/CTitle/index';
|
||||
import { CGridOriz } from '@src/components/CGridOriz/index';
|
||||
import { ChatBot } from '@src/components/ChatBot/index';
|
||||
import { CCatalogList } from '@src/components/CCatalogList/index';
|
||||
import { CRaccoltaCataloghi } from '@src/components/CRaccoltaCataloghi/index';
|
||||
import { tools } from '@tools';
|
||||
import { shared_consts } from '@src/common/shared_vuejs';
|
||||
import { LandingFooter } from '@src/components/LandingFooter';
|
||||
import { CMyActivities } from '@src/components/CMyActivities';
|
||||
import { CECommerce } from '@src/components/CECommerce';
|
||||
import { CStatMacro } from '@src/components/CStatMacro';
|
||||
import { CSearchProduct } from '@src/components/CSearchProduct';
|
||||
import { CPageViewStats } from '@src/components/CPageViewStats';
|
||||
import { CQRCode } from '@src/components/CQRCode';
|
||||
import { CAITools } from '@src/components/CAITools';
|
||||
import { CCatalogo } from '@src/components/CCatalogo';
|
||||
import { CRaccolta } from '@src/components/CRaccolta';
|
||||
// import { CMapMarker } from '@src/components/CMapMarker.off'
|
||||
import { CMapUsers } from '@src/components/CMapUsers'
|
||||
import { CMapGetCoordinates } from '@src/components/CMapGetCoordinates'
|
||||
import { CMapEditAddressByCoord } from '@src/components/CMapEditAddressByCoord'
|
||||
import { CMapComuni } from '@src/components/CMapComuni'
|
||||
import { COpenStreetMap } from '@src/components/COpenStreetMap'
|
||||
import { CCardCarousel } from '@src/components/CCardCarousel'
|
||||
import { CMyPage } from '@src/components/CMyPage'
|
||||
import { CMyPageIntro } from '@src/components/CMyPageIntro'
|
||||
import { CEventsCalendar } from '@src/components/CEventsCalendar'
|
||||
import { CMyEditor } from '@src/components/CMyEditor'
|
||||
import { CMyFieldRec } from '@src/components/CMyFieldRec'
|
||||
import { CSelectColor } from '@src/components/CSelectColor'
|
||||
import { CMainView } from '@src/components/CMainView'
|
||||
import { CMyProfileTutorial } from '@src/components/CMyProfileTutorial'
|
||||
import { CSendRISTo } from '@src/components/CSendRISTo'
|
||||
import { CDashboard } from '@src/components/CDashboard'
|
||||
import { CDashGroup } from '@src/components/CDashGroup'
|
||||
import { CMovements } from '@src/components/CMovements'
|
||||
import { CCheckAppRunning } from '@src/components/CCheckAppRunning'
|
||||
import { CStatusReg } from '@src/components/CStatusReg'
|
||||
import { CTitleBanner } from '@src/components/CTitleBanner'
|
||||
import { CCheckIfIsLogged } from '@src/components/CCheckIfIsLogged'
|
||||
import { CSelectFontSize } from '@src/components/CSelectFontSize'
|
||||
import { CNotifAtTop } from '@src/components/CNotifAtTop'
|
||||
import { CPresentazione } from '@src/components/CPresentazione'
|
||||
import { CRegistration } from '@src/components/CRegistration'
|
||||
import { CShareSocial } from '@src/components/CShareSocial'
|
||||
import { CVisuVideoPromoAndPDF } from '@src/components/CVisuVideoPromoAndPDF'
|
||||
import { CMapUsers } from '@src/components/CMapUsers';
|
||||
import { CMapGetCoordinates } from '@src/components/CMapGetCoordinates';
|
||||
import { CMapEditAddressByCoord } from '@src/components/CMapEditAddressByCoord';
|
||||
import { CMapComuni } from '@src/components/CMapComuni';
|
||||
import { COpenStreetMap } from '@src/components/COpenStreetMap';
|
||||
import { CCardCarousel } from '@src/components/CCardCarousel';
|
||||
import { CMyPage } from '@src/components/CMyPage';
|
||||
import { CMyPageIntro } from '@src/components/CMyPageIntro';
|
||||
import { CEventsCalendar } from '@src/components/CEventsCalendar';
|
||||
import { CMyEditor } from '@src/components/CMyEditor';
|
||||
import { CMyFieldRec } from '@src/components/CMyFieldRec';
|
||||
import { CSelectColor } from '@src/components/CSelectColor';
|
||||
import { CMainView } from '@src/components/CMainView';
|
||||
import { CMyProfileTutorial } from '@src/components/CMyProfileTutorial';
|
||||
import { CSendRISTo } from '@src/components/CSendRISTo';
|
||||
import { CDashboard } from '@src/components/CDashboard';
|
||||
import { CDashGroup } from '@src/components/CDashGroup';
|
||||
import { CMovements } from '@src/components/CMovements';
|
||||
import { CCheckAppRunning } from '@src/components/CCheckAppRunning';
|
||||
import { CStatusReg } from '@src/components/CStatusReg';
|
||||
import { CTitleBanner } from '@src/components/CTitleBanner';
|
||||
import { CCheckIfIsLogged } from '@src/components/CCheckIfIsLogged';
|
||||
import { CSelectFontSize } from '@src/components/CSelectFontSize';
|
||||
import { CNotifAtTop } from '@src/components/CNotifAtTop';
|
||||
import { CPresentazione } from '@src/components/CPresentazione';
|
||||
import { CRegistration } from '@src/components/CRegistration';
|
||||
import { CShareSocial } from '@src/components/CShareSocial';
|
||||
import { CVisuVideoPromoAndPDF } from '@src/components/CVisuVideoPromoAndPDF';
|
||||
|
||||
import MixinMetaTags from '@src/mixins/mixin-metatags'
|
||||
import MixinBase from '@src/mixins/mixin-base'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { LatLng } from 'leaflet'
|
||||
|
||||
import { costanti } from '@costanti'
|
||||
import MixinMetaTags from '@src/mixins/mixin-metatags';
|
||||
import MixinBase from '@src/mixins/mixin-base';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { LatLng } from 'leaflet';
|
||||
|
||||
import { costanti } from '@costanti';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CMyElem',
|
||||
components: {
|
||||
CImgTitle, CTitle, LandingFooter, CEventsCalendar,
|
||||
CCardCarousel, COpenStreetMap, CMyPage, CMyPageIntro, CMyEditor, CMyFieldRec,
|
||||
CSelectColor, CSelectFontSize, CImgPoster,
|
||||
CCheckIfIsLogged, CStatusReg, CDashboard, CMainView, CNotifAtTop,
|
||||
CPresentazione, CMyActivities,
|
||||
CMyProfileTutorial, CSendRISTo,
|
||||
CTitleBanner, CShareSocial, CCheckAppRunning, CRegistration,
|
||||
CVisuVideoPromoAndPDF, CECommerce, CCatalogo, CRaccolta, CAITools, CStatMacro,
|
||||
CMapComuni, CMapUsers, CMapGetCoordinates, CMapEditAddressByCoord,
|
||||
CDashGroup, CMovements, CGridOriz, CQRCode, CCatalogList,
|
||||
CSearchProduct, CRaccoltaCataloghi, CPageViewStats,
|
||||
CImgTitle,
|
||||
CTitle,
|
||||
LandingFooter,
|
||||
CEventsCalendar,
|
||||
CCardCarousel,
|
||||
COpenStreetMap,
|
||||
CMyPage,
|
||||
CMyPageIntro,
|
||||
CMyEditor,
|
||||
CMyFieldRec,
|
||||
CSelectColor,
|
||||
CSelectFontSize,
|
||||
CImgPoster,
|
||||
CCheckIfIsLogged,
|
||||
CStatusReg,
|
||||
CDashboard,
|
||||
CMainView,
|
||||
CNotifAtTop,
|
||||
CPresentazione,
|
||||
CMyActivities,
|
||||
CMyProfileTutorial,
|
||||
CSendRISTo,
|
||||
CTitleBanner,
|
||||
CShareSocial,
|
||||
CCheckAppRunning,
|
||||
CRegistration,
|
||||
CVisuVideoPromoAndPDF,
|
||||
CECommerce,
|
||||
CCatalogo,
|
||||
CRaccolta,
|
||||
CAITools,
|
||||
CStatMacro,
|
||||
CMapComuni,
|
||||
CMapUsers,
|
||||
CMapGetCoordinates,
|
||||
CMapEditAddressByCoord,
|
||||
CDashGroup,
|
||||
CMovements,
|
||||
CGridOriz,
|
||||
CQRCode,
|
||||
CCatalogList,
|
||||
CSearchProduct,
|
||||
CRaccoltaCataloghi,
|
||||
CPageViewStats,
|
||||
ChatBot,
|
||||
CSection,
|
||||
CRow,
|
||||
CColumn,
|
||||
// , //CMapMarker,
|
||||
},
|
||||
emits: ['selElemClick'],
|
||||
@@ -116,205 +151,212 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const globalStore = useGlobalStore()
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
const { setmeta, getsrcbyimg } = MixinMetaTags()
|
||||
const { setValDb, getValDb } = MixinBase()
|
||||
const { setmeta, getsrcbyimg } = MixinMetaTags();
|
||||
const { setValDb, getValDb } = MixinBase();
|
||||
|
||||
const $router = useRouter()
|
||||
const $router = useRouter();
|
||||
|
||||
const $q = useQuasar()
|
||||
const { t } = useI18n()
|
||||
const $q = useQuasar();
|
||||
const { t } = useI18n();
|
||||
|
||||
const animare = ref(0)
|
||||
const animarecard = ref(0)
|
||||
const slide = ref(0)
|
||||
const slide2 = ref(0)
|
||||
const disableSave = ref(true)
|
||||
const enableEdit = ref(false)
|
||||
const enableAdd = ref(true)
|
||||
const visushare = ref(false)
|
||||
const animare = ref(0);
|
||||
const animarecard = ref(0);
|
||||
const slide = ref(0);
|
||||
const slide2 = ref(0);
|
||||
const disableSave = ref(true);
|
||||
const enableEdit = ref(false);
|
||||
const enableAdd = ref(true);
|
||||
const visushare = ref(false);
|
||||
|
||||
const tabcatalogo = ref('griglia')
|
||||
const tabcatalogo = ref('griglia');
|
||||
|
||||
const social = ref(<ISocial>{})
|
||||
const social = ref(<ISocial>{});
|
||||
|
||||
const neworder = ref(<number | undefined>0)
|
||||
const neworder = ref(<number | undefined>0);
|
||||
|
||||
const myel = ref(<IMyElem>{})
|
||||
const myel = ref(<IMyElem>{});
|
||||
|
||||
const newtype = ref(<any>'')
|
||||
const newtype = ref(<any>'');
|
||||
|
||||
const isAppRunning = computed(() => globalStore.isAppRunning)
|
||||
const isAppRunning = computed(() => globalStore.isAppRunning);
|
||||
|
||||
const currentCardsPerSlide = computed(() => {
|
||||
return myel.value.num2 ? myel.value.num2 : 2 // cardsPerSlide
|
||||
})
|
||||
return myel.value.num2 ? myel.value.num2 : 2; // cardsPerSlide
|
||||
});
|
||||
|
||||
// Raggruppa le card in base al numero di card per slide
|
||||
const cardGroups = computed(() => {
|
||||
const cards = myel.value.listcards || []
|
||||
const groups = []
|
||||
const cards = myel.value.listcards || [];
|
||||
const groups = [];
|
||||
|
||||
for (let i = 0; i < cards.length; i += currentCardsPerSlide.value) {
|
||||
groups.push(cards.slice(i, i + currentCardsPerSlide.value))
|
||||
groups.push(cards.slice(i, i + currentCardsPerSlide.value));
|
||||
}
|
||||
|
||||
return groups
|
||||
})
|
||||
return groups;
|
||||
});
|
||||
|
||||
const coordaddr = ref(<ICoordGPS>{ address: '', coordinates: [0, 0] })
|
||||
const coordaddr = ref(<ICoordGPS>{ address: '', coordinates: [0, 0] });
|
||||
const speedSafe = computed(() => (myel.value as any).speed ?? 0);
|
||||
|
||||
const carouselRef = ref(<any>null)
|
||||
const isAtStart = ref(true)
|
||||
const isAtEnd = ref(false)
|
||||
const activeIndex = ref(0)
|
||||
const carouselRef = ref(<any>null);
|
||||
const isAtStart = ref(true);
|
||||
const isAtEnd = ref(false);
|
||||
const activeIndex = ref(0);
|
||||
|
||||
watch(() => myel.value.order, (value, oldval) => {
|
||||
mounted()
|
||||
})
|
||||
watch(
|
||||
() => myel.value.order,
|
||||
(value, oldval) => {
|
||||
mounted();
|
||||
}
|
||||
);
|
||||
|
||||
function getArrDisciplines() {
|
||||
return globalStore.disciplines.filter((rec: any) => rec.showinhome)
|
||||
return globalStore.disciplines.filter((rec: any) => rec.showinhome);
|
||||
}
|
||||
|
||||
function getheightgallery() {
|
||||
if (tools.isMobile())
|
||||
return '400px'
|
||||
else
|
||||
return '600px'
|
||||
if (tools.isMobile()) return '400px';
|
||||
else return '600px';
|
||||
}
|
||||
|
||||
function saveElem(exit?: boolean) {
|
||||
// Save Elem record
|
||||
const myelem = props.myelem
|
||||
myelem.order = neworder.value
|
||||
const myelem = props.myelem;
|
||||
myelem.order = neworder.value;
|
||||
globalStore.saveMyElem($q, t, myelem).then((ris) => {
|
||||
if (ris) {
|
||||
// OK
|
||||
disableSave.value = true
|
||||
if (exit)
|
||||
enableEdit.value = false
|
||||
disableSave.value = true;
|
||||
if (exit) enableEdit.value = false;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function addNewElem(order?: number) {
|
||||
|
||||
const newrec = globalStore.prepareAddNewElem(order, $q, t, props.myelem, newtype.value)
|
||||
const newrec = globalStore.prepareAddNewElem(
|
||||
order,
|
||||
$q,
|
||||
t,
|
||||
props.myelem,
|
||||
newtype.value
|
||||
);
|
||||
}
|
||||
|
||||
function dupElem(order?: number) {
|
||||
const newrec = props.myelem;
|
||||
|
||||
const newrec = props.myelem
|
||||
newrec._id = undefined;
|
||||
newrec.order = order ? order : newrec.order! + 10;
|
||||
|
||||
newrec._id = undefined
|
||||
newrec.order = order ? order : (newrec.order! + 10)
|
||||
|
||||
globalStore.addNewElem($q, t, newrec)
|
||||
globalStore.addNewElem($q, t, newrec);
|
||||
}
|
||||
|
||||
function modifElem() {
|
||||
disableSave.value = false
|
||||
disableSave.value = false;
|
||||
}
|
||||
|
||||
const checkScrollPosition = () => {
|
||||
const container = carouselRef.value
|
||||
if (!container || !myel.value || !myel.value.listcards) return
|
||||
const container = carouselRef.value;
|
||||
if (!container || !myel.value || !myel.value.listcards) return;
|
||||
|
||||
isAtStart.value = container.scrollLeft <= 0
|
||||
isAtEnd.value = container.scrollLeft + container.clientWidth >= container.scrollWidth - 1
|
||||
isAtStart.value = container.scrollLeft <= 0;
|
||||
isAtEnd.value =
|
||||
container.scrollLeft + container.clientWidth >= container.scrollWidth - 1;
|
||||
|
||||
const cardWidth = container.scrollWidth / myel.value.listcards.length
|
||||
activeIndex.value = Math.round(container.scrollLeft / cardWidth)
|
||||
}
|
||||
const cardWidth = container.scrollWidth / myel.value.listcards.length;
|
||||
activeIndex.value = Math.round(container.scrollLeft / cardWidth);
|
||||
};
|
||||
|
||||
function mounted() {
|
||||
myel.value = props.myelem
|
||||
neworder.value = props.myelem.order
|
||||
myel.value = props.myelem;
|
||||
neworder.value = props.myelem.order;
|
||||
|
||||
if (props.myelem)
|
||||
newtype.value = props.myelem.type
|
||||
if (props.myelem) newtype.value = props.myelem.type;
|
||||
|
||||
nextTick(() => {
|
||||
checkScrollPosition()
|
||||
carouselRef.value?.addEventListener('scroll', checkScrollPosition)
|
||||
})
|
||||
checkScrollPosition();
|
||||
carouselRef.value?.addEventListener('scroll', checkScrollPosition);
|
||||
});
|
||||
}
|
||||
|
||||
function clickOnElem() {
|
||||
if (props.editOn) {
|
||||
enableEdit.value = true
|
||||
enableEdit.value = true;
|
||||
// console.log('selElemClick', props.myelem)
|
||||
emit('selElemClick', props.myelem)
|
||||
emit('selElemClick', props.myelem);
|
||||
}
|
||||
}
|
||||
|
||||
function getClass() {
|
||||
let mycl = ''
|
||||
let mycl = '';
|
||||
if (props.myelem.align === shared_consts.ALIGNTYPE.CEHTER) {
|
||||
mycl += ' align_center'
|
||||
mycl += ' align_center';
|
||||
} else if (props.myelem.align === shared_consts.ALIGNTYPE.RIGHT) {
|
||||
mycl += ' align_right'
|
||||
mycl += ' align_right';
|
||||
} else if (props.myelem.align === shared_consts.ALIGNTYPE.LEFT) {
|
||||
mycl += ' align_left'
|
||||
mycl += ' align_left';
|
||||
}
|
||||
|
||||
if (props.myelem.class2)
|
||||
mycl += ' ' + props.myelem.class2
|
||||
if (props.myelem.class2) mycl += ' ' + props.myelem.class2;
|
||||
|
||||
if (props.selElem && props.editOn) {
|
||||
if (props.myelem._id === props.selElem._id)
|
||||
mycl += ' selectedElem'
|
||||
if (props.myelem._id === props.selElem._id) mycl += ' selectedElem';
|
||||
}
|
||||
|
||||
return mycl
|
||||
return mycl;
|
||||
}
|
||||
|
||||
function showFit() {
|
||||
if (props.myelem && props.myelem.type)
|
||||
return [shared_consts.ELEMTYPE.TEXT].includes(props.myelem.type)
|
||||
else
|
||||
return false
|
||||
return [shared_consts.ELEMTYPE.TEXT].includes(props.myelem.type);
|
||||
else return false;
|
||||
}
|
||||
|
||||
function PagLogin() {
|
||||
$router.replace('/signin')
|
||||
$router.replace('/signin');
|
||||
}
|
||||
|
||||
async function clickshare() {
|
||||
tools.addToTemporaryLinkReg()
|
||||
tools.addToTemporaryLinkReg();
|
||||
|
||||
const mytext = await tools.sendMsgTelegramCmd(
|
||||
$q,
|
||||
t,
|
||||
shared_consts.MsgTeleg.SHARE_MSGREG,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
if (false) {
|
||||
social.value.description = mytext
|
||||
visushare.value = true
|
||||
social.value.description = mytext;
|
||||
visushare.value = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Classe per le colonne delle card
|
||||
function cardColumnClass() {
|
||||
const width = 12 / currentCardsPerSlide.value
|
||||
return `col-${width}`
|
||||
const width = 12 / currentCardsPerSlide.value;
|
||||
return `col-${width}`;
|
||||
}
|
||||
|
||||
function updateCatalogoEmit(updatedCatalogo: IOptCatalogo) {
|
||||
console.log('CMyElem: updateCatalogoEmit')
|
||||
myel.value.catalogo = updatedCatalogo
|
||||
function updateCatalogoEmit(updatedCatalogo?: IOptCatalogo) {
|
||||
if (!updatedCatalogo) return;
|
||||
console.log('CMyElem: updateCatalogoEmit');
|
||||
myel.value.catalogo = updatedCatalogo;
|
||||
}
|
||||
|
||||
function naviga(path?: string): void {
|
||||
if (path) {
|
||||
$router.push(path);
|
||||
} else {
|
||||
// default fallback route
|
||||
$router.push('/');
|
||||
}
|
||||
}
|
||||
|
||||
function naviga(path: string) {
|
||||
$router.push(path)
|
||||
}
|
||||
|
||||
onMounted(mounted)
|
||||
onMounted(mounted);
|
||||
|
||||
return {
|
||||
tools,
|
||||
@@ -359,8 +401,8 @@ export default defineComponent({
|
||||
tabcatalogo,
|
||||
costanti,
|
||||
naviga,
|
||||
speedSafe,
|
||||
t,
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
@@ -10,6 +10,37 @@
|
||||
"
|
||||
>
|
||||
<div v-if="myel.type">
|
||||
<div v-if="myel.children && myel.children.length">
|
||||
<template v-for="(section, sidx) in myel.children">
|
||||
<CSection
|
||||
v-if="section.type === shared_consts.ELEMTYPE.SECTION"
|
||||
:key="'sec' + sidx"
|
||||
>
|
||||
<template
|
||||
v-for="(row, ridx) in section.rows || section.children || []"
|
||||
:key="'row' + ridx"
|
||||
>
|
||||
<CRow
|
||||
v-if="row.type === shared_consts.ELEMTYPE.ROW"
|
||||
:key="'r' + ridx"
|
||||
>
|
||||
<template
|
||||
v-for="(col, cidx) in row.columns || row.children || []"
|
||||
:key="'col' + cidx"
|
||||
>
|
||||
<CColumn
|
||||
v-if="col"
|
||||
:key="'col' + cidx"
|
||||
>
|
||||
<div v-if="col.container">{{ col.container }}</div>
|
||||
<div v-else-if="col.title">{{ col.title }}</div>
|
||||
</CColumn>
|
||||
</template>
|
||||
</CRow>
|
||||
</template>
|
||||
</CSection>
|
||||
</template>
|
||||
</div>
|
||||
<q-btn
|
||||
v-if="editOn"
|
||||
class="btn-edit-floating"
|
||||
@@ -228,7 +259,7 @@
|
||||
:title="myel.container"
|
||||
:myheight="myel.heightimg"
|
||||
:vertalign="myel.vertalign"
|
||||
:speed="myel.speed"
|
||||
:speed="speedSafe"
|
||||
:elemsText="myel.elemsText"
|
||||
:logo="tools.getImgFileByFilename(myel, myel.img)"
|
||||
:logoheight="myel.height ? myel.height.toString() : '100'"
|
||||
@@ -1100,6 +1131,7 @@
|
||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.FOOTER">
|
||||
<LandingFooter />
|
||||
</div>
|
||||
|
||||
<div v-if="editOn">
|
||||
<div class="q-ma-md"></div>
|
||||
</div>
|
||||
|
||||
@@ -57,7 +57,6 @@ export default defineComponent({
|
||||
const load = async (): Promise<void> => {
|
||||
// console.log('load', mypath.value)
|
||||
if (mypath.value !== '') rec.value = await globalStore.loadPage('/' + mypath.value, 'cmypage')
|
||||
|
||||
}
|
||||
|
||||
watch(() => props.mypath, async (to: string, from: string) => {
|
||||
|
||||
@@ -78,7 +78,7 @@ export default defineComponent({
|
||||
const { t } = useI18n();
|
||||
const globalStore = useGlobalStore();
|
||||
const $router = useRouter();
|
||||
const $route = useRoute()
|
||||
const $route = useRoute();
|
||||
|
||||
const mywidthEditor = ref(400);
|
||||
|
||||
@@ -125,6 +125,12 @@ export default defineComponent({
|
||||
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) => {
|
||||
|
||||
20
src/components/CRow/CRow.vue
Normal file
20
src/components/CRow/CRow.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div class="row-container" style="display:flex; flex-direction: row;">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CRow'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.row-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
||||
19
src/components/CSection/CSection.vue
Normal file
19
src/components/CSection/CSection.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="section">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CSection'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.section {
|
||||
padding: 8px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -170,7 +170,7 @@ export default defineComponent({
|
||||
|
||||
function removeFromCard() {
|
||||
$q.dialog({
|
||||
title: order.value.product.productInfo.name,
|
||||
title: order.value.product?.productInfo?.name,
|
||||
message: 'Sicuro di voler rimuovere il prodotto dal carrello?',
|
||||
ok: {
|
||||
label: 'Rimuovi',
|
||||
@@ -222,7 +222,7 @@ export default defineComponent({
|
||||
|
||||
function mounted() {
|
||||
endload.value = false;
|
||||
weight.value = props.order.product?.productInfo.weight;
|
||||
weight.value = props.order.product?.productInfo?.weight;
|
||||
price.value = props.order.price;
|
||||
if (props.order.quantity !== 0) {
|
||||
orderQuantity.value = props.order.quantity;
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import { defineComponent, ref, computed, onMounted, watch, onBeforeUnmount } from 'vue'
|
||||
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { tools } from '@tools'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { defineComponent, ref, computed, watch } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'IconPicker',
|
||||
@@ -12,49 +6,75 @@ export default defineComponent({
|
||||
modelValue: { type: String, default: '' },
|
||||
icons: {
|
||||
type: Array as () => string[],
|
||||
default: () => ([
|
||||
// Estendi pure questo set
|
||||
'fas fa-house',
|
||||
// SOLO Font Awesome 5 (free)
|
||||
default: () => [
|
||||
'fas fa-home',
|
||||
'fas fa-book',
|
||||
'fas fa-star',
|
||||
'fas fa-heart',
|
||||
'fas fa-user',
|
||||
'fas fa-gear',
|
||||
'fas fa-circle-info',
|
||||
'fas fa-newspaper',
|
||||
'fas fa-cog',
|
||||
'fas fa-info-circle',
|
||||
'far fa-newspaper',
|
||||
'fas fa-list',
|
||||
'fas fa-tags',
|
||||
'fas fa-chart-line',
|
||||
'fas fa-briefcase',
|
||||
'fas fa-envelope',
|
||||
'fas fa-phone',
|
||||
'fas fa-earth-europe',
|
||||
])
|
||||
'fas fa-globe-europe'
|
||||
]
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue', 'change'],
|
||||
setup (props, { emit }) {
|
||||
const keyword = ref('')
|
||||
const local = ref(props.modelValue)
|
||||
const local = ref(props.modelValue) // testo inserito/valore corrente
|
||||
const dialog = ref(false) // mostra/nasconde il picker
|
||||
const keyword = ref('') // filtro dentro il dialog
|
||||
|
||||
watch(() => props.modelValue, v => { local.value = v })
|
||||
|
||||
const filteredIcons = computed(() => {
|
||||
const k = keyword.value.trim().toLowerCase()
|
||||
if (!k) return props.icons
|
||||
return props.icons.filter(i => i.toLowerCase().includes(k))
|
||||
return props.icons.filter(i =>
|
||||
i.toLowerCase().includes(k) ||
|
||||
// match anche sul nome “breve” (es: 'home')
|
||||
i.toLowerCase().split(' ').some(cls => cls.startsWith('fa-') && cls.includes(k))
|
||||
)
|
||||
})
|
||||
|
||||
function select (val: string) {
|
||||
local.value = val
|
||||
emit('update:modelValue', val)
|
||||
emit('change', val)
|
||||
// applica la stringa così com’è; nessun fallback
|
||||
emit('update:modelValue', val || '')
|
||||
emit('change', val || '')
|
||||
}
|
||||
|
||||
function onKeyword () {
|
||||
// solo aggiorna la lista; il pulsante "Usa testo" applica
|
||||
function choose (ic: string) {
|
||||
local.value = ic || ''
|
||||
select(local.value)
|
||||
dialog.value = false
|
||||
}
|
||||
|
||||
return { keyword, local, filteredIcons, select, onKeyword }
|
||||
function clear () {
|
||||
local.value = ''
|
||||
select('')
|
||||
}
|
||||
|
||||
function openPicker () {
|
||||
keyword.value = ''
|
||||
dialog.value = true
|
||||
}
|
||||
|
||||
return {
|
||||
local,
|
||||
dialog,
|
||||
keyword,
|
||||
filteredIcons,
|
||||
select,
|
||||
choose,
|
||||
clear,
|
||||
openPicker
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,67 +1,86 @@
|
||||
<template>
|
||||
<div class="q-gutter-sm">
|
||||
<div class="row items-center q-col-gutter-sm">
|
||||
<div class="col">
|
||||
<div class="col-12">
|
||||
<q-input
|
||||
v-model="keyword"
|
||||
v-model="local"
|
||||
dense
|
||||
clearable
|
||||
label="Cerca icona (es: fas fa-house)"
|
||||
@update:model-value="onKeyword"
|
||||
label="Icona"
|
||||
>
|
||||
<template #prepend>
|
||||
<q-icon :name="modelValue || 'fa-regular fa-face-smile'" />
|
||||
<q-icon v-if="local" :name="local" />
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<q-btn
|
||||
dense
|
||||
outline
|
||||
:disable="!keyword"
|
||||
label="Usa testo"
|
||||
@click="select(keyword)"
|
||||
@click="select(local)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<q-btn
|
||||
dense
|
||||
color="primary"
|
||||
outline
|
||||
label="Scegli icona"
|
||||
@click="openPicker"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-separator spaced />
|
||||
<!-- La griglia icone appare solo nel dialog -->
|
||||
<q-dialog v-model="dialog">
|
||||
<q-card style="min-width: 640px; max-width: 90vw;">
|
||||
<q-toolbar>
|
||||
<q-toolbar-title>Seleziona icona</q-toolbar-title>
|
||||
<q-btn flat round dense icon="fas fa-times" v-close-popup />
|
||||
</q-toolbar>
|
||||
|
||||
<div class="row q-col-gutter-sm">
|
||||
<div
|
||||
v-for="ic in filteredIcons"
|
||||
:key="ic"
|
||||
class="col-3 col-sm-2 col-md-1"
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
class="full-width"
|
||||
:icon="ic"
|
||||
@click="select(ic)"
|
||||
:color="ic === modelValue ? 'primary' : 'grey-7'"
|
||||
>
|
||||
<q-tooltip>{{ ic }}</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="q-pa-md">
|
||||
<q-input
|
||||
v-model="keyword"
|
||||
dense
|
||||
clearable
|
||||
autofocus
|
||||
label="Cerca (es: home, user, info...)"
|
||||
/>
|
||||
|
||||
<div class="q-mt-md">
|
||||
<q-input
|
||||
v-model="local"
|
||||
dense
|
||||
label="Valore attuale icona"
|
||||
@update:model-value="select(local)"
|
||||
>
|
||||
<template #append>
|
||||
<q-icon :name="local || 'fa-regular fa-circle-question'" />
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="row q-col-gutter-sm q-mt-sm">
|
||||
<div
|
||||
v-for="ic in filteredIcons"
|
||||
:key="ic"
|
||||
class="col-3 col-sm-2 col-md-1"
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
class="full-width"
|
||||
:icon="ic"
|
||||
@click="choose(ic)"
|
||||
>
|
||||
<q-tooltip>{{ ic }}</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-mt-md q-gutter-sm">
|
||||
<q-btn outline label="Rimuovi icona" color="negative" @click="choose('')" />
|
||||
<q-space />
|
||||
<q-btn color="primary" label="Chiudi" v-close-popup />
|
||||
</div>
|
||||
</div>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./IconPicker.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './IconPicker.scss';
|
||||
/* opzionale: spaziatura minima sulle celle */
|
||||
</style>
|
||||
|
||||
0
src/components/MenuPageItem/MenuPageItem.scss
Normal file
0
src/components/MenuPageItem/MenuPageItem.scss
Normal file
50
src/components/MenuPageItem/MenuPageItem.ts
Normal file
50
src/components/MenuPageItem/MenuPageItem.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { defineComponent, ref, computed, onMounted, watch, onBeforeUnmount } from 'vue';
|
||||
import { IMyPage } from 'app/src/model';
|
||||
|
||||
type PageWithKey = IMyPage & { __key?: string };
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MenuPageItem',
|
||||
props: {
|
||||
item: { type: Object as () => PageWithKey, required: true },
|
||||
selected: { type: Boolean, default: false },
|
||||
active: { type: Boolean, default: false }, // v-model:active
|
||||
variant: { type: String as () => 'menu' | 'off', default: 'menu' },
|
||||
showGrip: { type: Boolean, default: true },
|
||||
draggableHandleClass: { type: String, default: 'drag-handle' },
|
||||
depth: { type: Number, default: 0 },
|
||||
},
|
||||
emits: ['select', 'edit', 'delete', 'open', 'update:active', 'update:item'],
|
||||
setup(props, { emit }) {
|
||||
function displayPath(path?: string) {
|
||||
if (!path) return '-';
|
||||
return path.startsWith('/') ? path : '/' + path;
|
||||
}
|
||||
function emitSelect() {
|
||||
emit('select', props.item.__key);
|
||||
}
|
||||
function emitEdit() {
|
||||
emit('edit', props.item.__key);
|
||||
}
|
||||
function emitDelete() {
|
||||
emit('delete', props.item.__key);
|
||||
}
|
||||
function emitOpen() {
|
||||
emit('open', props.item.__key);
|
||||
}
|
||||
|
||||
const indentSpacerStyle = computed(() => {
|
||||
const px = Math.min(props.depth, 6) * 16; // max 6 livelli x 16px
|
||||
return { width: `${px}px`, minWidth: `${px}px` };
|
||||
});
|
||||
|
||||
return {
|
||||
displayPath,
|
||||
emitSelect,
|
||||
emitEdit,
|
||||
emitDelete,
|
||||
emitOpen,
|
||||
indentSpacerStyle,
|
||||
};
|
||||
},
|
||||
});
|
||||
144
src/components/MenuPageItem/MenuPageItem.vue
Normal file
144
src/components/MenuPageItem/MenuPageItem.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<q-item
|
||||
clickable
|
||||
:active="selected"
|
||||
@click="emitSelect"
|
||||
>
|
||||
<q-item-section
|
||||
v-if="showGrip"
|
||||
avatar
|
||||
>
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
dense
|
||||
:class="draggableHandleClass"
|
||||
icon="fas fa-grip-vertical"
|
||||
@click.stop
|
||||
/>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section
|
||||
v-if="depth > 0"
|
||||
avatar
|
||||
class="q-pr-none"
|
||||
>
|
||||
<div :style="indentSpacerStyle" />
|
||||
</q-item-section>
|
||||
|
||||
<!--<q-item-section side>
|
||||
<q-toggle
|
||||
:model-value="active"
|
||||
:color="active ? 'green' : 'grey'"
|
||||
@update:model-value="val => $emit('update:active', val)"
|
||||
@click.stop
|
||||
/>
|
||||
</q-item-section>-->
|
||||
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="item.icon || 'far fa-file-alt'" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side>
|
||||
<q-item-label caption>{{ item.order }}</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label :class="{ 'text-grey-7': !active }">{{
|
||||
item.title || '(senza titolo)'
|
||||
}}</q-item-label>
|
||||
<q-item-label caption>{{ displayPath(item.path) }}</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section
|
||||
v-if="active"
|
||||
side
|
||||
class="float-right"
|
||||
>
|
||||
<q-icon
|
||||
name="fas fa-circle"
|
||||
color="green"
|
||||
size="xs"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
v-if="item.only_admin"
|
||||
side
|
||||
class="float-right"
|
||||
>
|
||||
<q-icon
|
||||
name="fas fa-circle"
|
||||
color="red"
|
||||
size="xs"
|
||||
/>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side>
|
||||
<slot name="actions">
|
||||
<div
|
||||
class="column q-gutter-xs"
|
||||
v-if="true"
|
||||
>
|
||||
<q-btn
|
||||
dense
|
||||
round
|
||||
color="primary"
|
||||
icon="fas fa-ellipsis-v"
|
||||
class="q-mr-xs"
|
||||
@click.stop
|
||||
>
|
||||
<q-menu>
|
||||
<q-list style="min-width: 140px">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="emitOpen"
|
||||
>
|
||||
<q-item-section side><q-icon name="fas fa-edit" /></q-item-section>
|
||||
<q-item-section>Modifica</q-item-section>
|
||||
</q-item>
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="emitEdit"
|
||||
>
|
||||
<q-item-section side><q-icon name="fas fa-cog" /></q-item-section>
|
||||
<q-item-section>Impostazioni</q-item-section>
|
||||
</q-item>
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="emitDelete"
|
||||
>
|
||||
<q-item-section side
|
||||
><q-icon
|
||||
name="fas fa-trash"
|
||||
color="red"
|
||||
/></q-item-section>
|
||||
<q-item-section>Elimina</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</div>
|
||||
<div
|
||||
class="column q-gutter-xs"
|
||||
v-else
|
||||
>
|
||||
<q-btn
|
||||
dense
|
||||
round
|
||||
color="negative"
|
||||
icon="fas fa-trash"
|
||||
@click.stop="emitDelete"
|
||||
/>
|
||||
</div>
|
||||
</slot>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./MenuPageItem.ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
@import './MenuPageItem.scss';
|
||||
</style>
|
||||
1
src/components/MenuPageItem/index.ts
Executable file
1
src/components/MenuPageItem/index.ts
Executable file
@@ -0,0 +1 @@
|
||||
export {default as MenuPageItem} from './MenuPageItem.vue'
|
||||
@@ -1,141 +1,167 @@
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
computed,
|
||||
onMounted,
|
||||
watch,
|
||||
onBeforeUnmount,
|
||||
toRaw,
|
||||
nextTick,
|
||||
} from 'vue';
|
||||
defineComponent, ref, computed, watch, reactive, toRaw, nextTick
|
||||
} from 'vue'
|
||||
import { useQuasar } from 'quasar'
|
||||
import IconPicker from '../IconPicker/IconPicker.vue'
|
||||
import { IMyPage } from 'app/src/model'
|
||||
import { useGlobalStore } from 'app/src/store'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { costanti } from '@costanti'
|
||||
|
||||
import { useUserStore } from '@store/UserStore';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { tools } from '@tools';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { reactive } from 'vue';
|
||||
import { IMyPage } from 'app/src/model';
|
||||
import IconPicker from '../IconPicker/IconPicker.vue';
|
||||
import { useGlobalStore } from 'app/src/store';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { CMyFieldRec } from '@src/components/CMyFieldRec'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PageEditor',
|
||||
components: { IconPicker },
|
||||
components: { IconPicker, CMyFieldRec },
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object as () => IMyPage,
|
||||
required: true,
|
||||
},
|
||||
modelValue: { type: Object as () => IMyPage, required: true },
|
||||
nuovaPagina: { type: Boolean, required: true } // <-- modalità "bozza"
|
||||
},
|
||||
emits: ['update:modelValue', 'apply'],
|
||||
setup(props, { emit }) {
|
||||
const $q = useQuasar();
|
||||
const globalStore = useGlobalStore();
|
||||
const { mypage } = storeToRefs(globalStore);
|
||||
emits: ['update:modelValue', 'apply', 'hide'],
|
||||
setup (props, { emit }) {
|
||||
const $q = useQuasar()
|
||||
|
||||
// DRaft locale
|
||||
const draft = reactive<IMyPage>({ ...props.modelValue });
|
||||
const { t } = useI18n()
|
||||
const globalStore = useGlobalStore()
|
||||
const { mypage } = storeToRefs(globalStore)
|
||||
|
||||
// Draft locale indipendente dal parent (specie in nuovaPagina)
|
||||
const draft = reactive<IMyPage>({ ...props.modelValue })
|
||||
|
||||
// UI helper: path mostrato con "/" iniziale
|
||||
const ui = reactive({
|
||||
pathText: toUiPath(draft.path),
|
||||
});
|
||||
const ui = reactive({ pathText: toUiPath(draft.path) })
|
||||
|
||||
const saving = ref(false)
|
||||
const syncingFromProps = ref(false) // <-- FLAG anti-loop
|
||||
const syncingFromProps = ref(false) // anti-loop
|
||||
|
||||
// --- Watch input esterno: ricarica draft e UI path
|
||||
// --- Watch input esterno: ricarica draft e UI path (NO scritture nello store qui!)
|
||||
// --- Sync IN: quando cambia il valore del parent, aggiorna solo il draft
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (v) => {
|
||||
syncingFromProps.value = true;
|
||||
Object.assign(draft, v || {});
|
||||
ui.pathText = toUiPath(draft.path);
|
||||
await nextTick();
|
||||
syncingFromProps.value = false;
|
||||
async v => {
|
||||
syncingFromProps.value = true
|
||||
Object.assign(draft, v || {})
|
||||
ui.pathText = toUiPath(draft.path)
|
||||
await nextTick()
|
||||
syncingFromProps.value = false
|
||||
},
|
||||
{ deep: false }
|
||||
);
|
||||
)
|
||||
|
||||
// --- Ogni modifica del draft: aggiorna store.mypage e emetti update:modelValue (solo se modifica nasce da UI)
|
||||
// --- Modifiche live: SE NON è nuovaPagina, aggiorna store e v-model del parent
|
||||
watch(
|
||||
draft,
|
||||
(val) => {
|
||||
if (syncingFromProps.value) return; // evita ricorsione
|
||||
upsertIntoStore(val, mypage.value);
|
||||
emit('update:modelValue', { ...val });
|
||||
if (syncingFromProps.value) return
|
||||
if (props.nuovaPagina) return // <-- blocca ogni propagazione durante "nuova pagina"
|
||||
upsertIntoStore(val, mypage.value)
|
||||
emit('update:modelValue', { ...val })
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
)
|
||||
|
||||
// --- Helpers path
|
||||
function toUiPath(storePath?: string) {
|
||||
const p = (storePath || '').trim();
|
||||
if (!p) return '/';
|
||||
return p.startsWith('/') ? p : `/${p}`;
|
||||
function toUiPath (storePath?: string) {
|
||||
const p = (storePath || '').trim()
|
||||
if (!p) return '/'
|
||||
return p.startsWith('/') ? p : `/${p}`
|
||||
}
|
||||
function toStorePath(uiPath?: string) {
|
||||
const p = (uiPath || '').trim();
|
||||
if (!p) return '';
|
||||
return p.startsWith('/') ? p.slice(1) : p;
|
||||
function toStorePath (uiPath?: string) {
|
||||
const p = (uiPath || '').trim()
|
||||
if (!p) return ''
|
||||
return p.startsWith('/') ? p.slice(1) : p
|
||||
}
|
||||
function normalizeAndApplyPath () {
|
||||
// normalizza: niente spazi → trattini
|
||||
let p = (ui.pathText || '/').trim()
|
||||
p = p.replace(/\s+/g, '-')
|
||||
if (!p.startsWith('/')) p = '/' + p
|
||||
ui.pathText = p
|
||||
draft.path = toStorePath(p) // NB: scrive sul draft (watch sopra gestisce la propagazione)
|
||||
}
|
||||
|
||||
function normalizeAndApplyPath() {
|
||||
// normalizza: niente spazi, minuscole, trattini
|
||||
let p = (ui.pathText || '/').trim();
|
||||
p = p.replace(/\s+/g, '-');
|
||||
if (!p.startsWith('/')) p = '/' + p;
|
||||
ui.pathText = p;
|
||||
draft.path = toStorePath(p);
|
||||
function pathRule (v: string) {
|
||||
if (!v) return 'Percorso richiesto'
|
||||
if (!v.startsWith('/')) return 'Deve iniziare con /'
|
||||
if (/\s/.test(v)) return 'Nessuno spazio nel path'
|
||||
return true
|
||||
}
|
||||
|
||||
function pathRule(v: string) {
|
||||
if (!v) return 'Percorso richiesto';
|
||||
if (!v.startsWith('/')) return 'Deve iniziare con /';
|
||||
if (/\s/.test(v)) return 'Nessuno spazio nel path';
|
||||
return true;
|
||||
// --- Upsert nello store.mypage (usato solo quando NON è nuovaPagina o dopo il save)
|
||||
function upsertIntoStore (page: IMyPage, arr: IMyPage[]) {
|
||||
if (!page) return
|
||||
const keyId = page._id
|
||||
const keyPath = page.path || ''
|
||||
let idx = -1
|
||||
if (keyId) idx = arr.findIndex(p => p._id === keyId)
|
||||
if (idx < 0 && keyPath) idx = arr.findIndex(p => (p.path || '') === keyPath)
|
||||
if (idx >= 0) arr[idx] = { ...arr[idx], ...toRaw(page) }
|
||||
else arr.push({ ...toRaw(page) })
|
||||
}
|
||||
|
||||
// --- Upsert nello store.mypage
|
||||
function upsertIntoStore(page: IMyPage, arr: IMyPage[]) {
|
||||
if (!page) return;
|
||||
// chiave di matching: prima _id, altrimenti path
|
||||
const keyId = page._id;
|
||||
const keyPath = page.path || '';
|
||||
let idx = -1;
|
||||
if (keyId) {
|
||||
idx = arr.findIndex((p) => p._id === keyId);
|
||||
// --- VALIDAZIONE + COMMIT per nuova pagina (o anche per edit espliciti)
|
||||
async function checkAndSave (payloadDraft?: IMyPage) {
|
||||
const cur = payloadDraft || draft
|
||||
|
||||
// validazioni base
|
||||
if (!cur.title?.trim()) {
|
||||
$q.notify({ message: 'Inserisci il titolo della pagina', type: 'warning' })
|
||||
return
|
||||
}
|
||||
if (idx < 0 && keyPath) {
|
||||
idx = arr.findIndex((p) => (p.path || '') === keyPath);
|
||||
|
||||
const pathText = (ui.pathText || '').trim()
|
||||
if (!pathText) {
|
||||
$q.notify({ message: 'Inserisci il percorso della pagina', type: 'warning' })
|
||||
return
|
||||
}
|
||||
if (idx >= 0) {
|
||||
// merge preservando reattività
|
||||
arr[idx] = { ...arr[idx], ...toRaw(page) };
|
||||
} else {
|
||||
arr.push({ ...toRaw(page) });
|
||||
|
||||
const candidatePath = toStorePath(pathText).toLowerCase()
|
||||
|
||||
// unicità PATH (ignora se stesso quando editing)
|
||||
const existPath = globalStore.mypage.find(
|
||||
(r) => (r.path || '').toLowerCase() === candidatePath && r._id !== cur._id
|
||||
)
|
||||
if (existPath) {
|
||||
$q.notify({ message: 'Esiste già un’altra pagina con questo percorso', type: 'warning' })
|
||||
return
|
||||
}
|
||||
|
||||
// unicità TITOLO (ignora se stesso quando editing)
|
||||
const candidateTitle = (cur.title || '').toLowerCase()
|
||||
const existName = globalStore.mypage.find(
|
||||
(r) => (r.title || '').toLowerCase() === candidateTitle && r._id !== cur._id
|
||||
)
|
||||
if (existName) {
|
||||
$q.notify({ message: 'Il nome della pagina esiste già', type: 'warning' })
|
||||
return
|
||||
}
|
||||
|
||||
await save() // esegue commit vero
|
||||
emit('hide') // chiudi il dialog (se usi dialog)
|
||||
}
|
||||
async function save () {
|
||||
|
||||
// --- Salvataggio esplicito (commit). Qui propaghiamo SEMPRE al parent/store.
|
||||
async function save () {
|
||||
try {
|
||||
saving.value = true
|
||||
normalizeAndApplyPath() // assicura path coerente
|
||||
|
||||
const payload: IMyPage = { ...toRaw(draft), path: draft.path || '' }
|
||||
const saved = await globalStore.savePage(payload)
|
||||
|
||||
if (saved && typeof saved === 'object') {
|
||||
syncingFromProps.value = true
|
||||
Object.assign(draft, saved)
|
||||
upsertIntoStore(draft, mypage.value)
|
||||
upsertIntoStore(draft, mypage.value) // ora è lecito anche per nuovaPagina
|
||||
await nextTick()
|
||||
syncingFromProps.value = false
|
||||
}
|
||||
|
||||
// IMPORTANTISSIMO: in nuovaPagina non abbiamo mai emesso prima → emettiamo ora
|
||||
emit('update:modelValue', { ...draft })
|
||||
emit('apply', { ...draft })
|
||||
$q.notify({ type: 'positive', message: 'Pagina salvata' })
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio' })
|
||||
} finally {
|
||||
@@ -143,7 +169,7 @@ async function save () {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Ricarica da sorgente
|
||||
// --- Ricarica (per editing). In modalità nuovaPagina non propaghiamo al parent.
|
||||
async function reloadFromStore () {
|
||||
try {
|
||||
const absolute = ui.pathText || '/'
|
||||
@@ -153,8 +179,7 @@ async function save () {
|
||||
Object.assign(draft, page)
|
||||
ui.pathText = toUiPath(draft.path)
|
||||
upsertIntoStore(draft, mypage.value)
|
||||
console.log('page', draft)
|
||||
emit('update:modelValue', { ...draft })
|
||||
if (!props.nuovaPagina) emit('update:modelValue', { ...draft }) // <-- no propagate in nuovaPagina
|
||||
await nextTick()
|
||||
syncingFromProps.value = false
|
||||
$q.notify({ type: 'info', message: 'Pagina ricaricata' })
|
||||
@@ -167,16 +192,18 @@ async function save () {
|
||||
}
|
||||
}
|
||||
|
||||
function resetDraft() {
|
||||
console.log('resetDraft')
|
||||
function resetDraft () {
|
||||
syncingFromProps.value = true
|
||||
Object.assign(draft, props.modelValue || {})
|
||||
ui.pathText = toUiPath(draft.path)
|
||||
// aggiorna i componenti
|
||||
emit('update:modelValue', { ...draft })
|
||||
if (!props.nuovaPagina) emit('update:modelValue', { ...draft }) // <-- no propagate in nuovaPagina
|
||||
nextTick(() => { syncingFromProps.value = false })
|
||||
}
|
||||
|
||||
function modifElem() {
|
||||
|
||||
}
|
||||
|
||||
const absolutePath = computed(() => toUiPath(draft.path))
|
||||
|
||||
return {
|
||||
@@ -189,6 +216,10 @@ async function save () {
|
||||
reloadFromStore,
|
||||
resetDraft,
|
||||
absolutePath,
|
||||
};
|
||||
},
|
||||
});
|
||||
checkAndSave,
|
||||
t,
|
||||
costanti,
|
||||
modifElem,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<q-card flat bordered class="q-pa-md">
|
||||
<q-card
|
||||
flat
|
||||
bordered
|
||||
class="q-pa-md"
|
||||
>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input
|
||||
@@ -20,53 +24,99 @@
|
||||
v-model="draft.title"
|
||||
label="Titolo"
|
||||
dense
|
||||
:rules="[v => !!v || 'Titolo richiesto']"
|
||||
:rules="[(v) => !!v || 'Titolo richiesto']"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<icon-picker v-model="draft.icon" />
|
||||
<q-input
|
||||
v-model.number="draft.order"
|
||||
label="Ordine"
|
||||
dense
|
||||
type="number"
|
||||
:rules="[
|
||||
(v) => v !== null || 'Ordine richiesto',
|
||||
(v) => v >= 0 || 'Ordine deve essere positivo',
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
SottoMenu:
|
||||
<CMyFieldRec
|
||||
title="SottoMenu:"
|
||||
table="pages"
|
||||
:id="draft._id"
|
||||
:rec="draft"
|
||||
field="sottoMenu"
|
||||
@update:model-value="modifElem"
|
||||
:canEdit="true"
|
||||
:canModify="true"
|
||||
:nosaveToDb="true"
|
||||
:fieldtype="costanti.FieldType.multiselect"
|
||||
>
|
||||
</CMyFieldRec>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<q-input v-model="draft.iconsize" label="Dimensione icona (es: 24px)" dense />
|
||||
<icon-picker v-model="draft.icon" />
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<q-separator spaced />
|
||||
<div class="row items-center q-col-gutter-md">
|
||||
<div class="col-auto">
|
||||
<q-toggle v-model="draft.active" label="Attivo" />
|
||||
<q-toggle
|
||||
v-model="draft.active"
|
||||
label="Attivo"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-toggle v-model="draft.inmenu" label="Presente nel menu" />
|
||||
<q-toggle
|
||||
v-model="draft.inmenu"
|
||||
label="Presente nel menu"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-toggle v-model="draft.onlyif_logged" label="Solo se loggati" />
|
||||
<q-toggle
|
||||
v-model="draft.onlyif_logged"
|
||||
:label="t('pages.onlyif_logged')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-toggle
|
||||
v-model="draft.only_admin"
|
||||
:label="t('pages.only_admin')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-col-gutter-sm q-mt-md">
|
||||
<div class="col-auto">
|
||||
<q-btn color="primary" label="Salva" :loading="saving" @click="save" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn outline label="Ricarica" @click="reloadFromStore" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn color="grey-7" label="Chiudi" @click="$emit('close', draft.path)" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn flat color="grey-7" label="Reset draft" @click="resetDraft" />
|
||||
</div>
|
||||
</div>
|
||||
<q-card-actions
|
||||
align="center"
|
||||
class="q-pa-md q-gutter-md"
|
||||
>
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="Salva"
|
||||
:loading="saving"
|
||||
@click="checkAndSave(draft)"
|
||||
/>
|
||||
<q-btn
|
||||
outline
|
||||
label="Ricarica"
|
||||
@click="reloadFromStore"
|
||||
/>
|
||||
<q-btn
|
||||
color="grey-7"
|
||||
label="Chiudi"
|
||||
v-close-popup
|
||||
/>
|
||||
<!--<q-btn flat color="grey-7" label="Reset draft" @click="resetDraft" />-->
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./PageEditor.ts">
|
||||
</script>
|
||||
<script lang="ts" src="./PageEditor.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './PageEditor.scss';
|
||||
|
||||
@@ -1,160 +1,542 @@
|
||||
import { defineComponent, ref, computed, onMounted, watch, onBeforeUnmount } from 'vue';
|
||||
import { IMyPage } from 'app/src/model';
|
||||
import { PageEditor } from '../PageEditor';
|
||||
import { defineComponent, ref, computed, watch } from 'vue';
|
||||
import type { IMyPage } from 'app/src/model';
|
||||
import PageEditor from '@src/components/PageEditor/PageEditor.vue';
|
||||
import MenuPageItem from '@src/components/MenuPageItem/MenuPageItem.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useGlobalStore } from 'app/src/store';
|
||||
import draggable from 'vuedraggable';
|
||||
|
||||
type Bucket = 'menu' | 'off';
|
||||
type PageWithKey = IMyPage & { __key?: string };
|
||||
type PageRow = PageWithKey & { __depth: number }; // 0 = voce di menu, 1 = sottomenu
|
||||
|
||||
const byOrder = (a: IMyPage, b: IMyPage) => (a.order ?? 0) - (b.order ?? 0);
|
||||
const norm = (p?: string) => (p || '').trim().replace(/^\//, '').toLowerCase();
|
||||
|
||||
let uidSeed = 1;
|
||||
function ensureKeys(arr: PageWithKey[]) {
|
||||
for (const p of arr) {
|
||||
if (!p.__key) p.__key = p._id || `tmp_${uidSeed++}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PagesConfigurator',
|
||||
components: { PageEditor },
|
||||
components: { PageEditor, MenuPageItem, draggable },
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array as () => IMyPage[],
|
||||
required: true,
|
||||
},
|
||||
modelValue: { type: Array as () => IMyPage[], required: true },
|
||||
},
|
||||
emits: ['update:modelValue', 'save', 'change-order'],
|
||||
setup(props, { emit }) {
|
||||
const pages = ref<IMyPage[]>(props.modelValue ? [...props.modelValue] : []);
|
||||
const selectedIndex = ref<number>(-1);
|
||||
const $q = useQuasar();
|
||||
const $router = useRouter();
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
const visualizzaEditor = ref(false);
|
||||
const nuovaPagina = ref(false);
|
||||
|
||||
const ORDER_STEP = 10;
|
||||
const MIN_GAP = 1;
|
||||
|
||||
function getPageByKey(key?: string) {
|
||||
return key ? pages.value.find((p) => p.__key === key) : undefined;
|
||||
}
|
||||
|
||||
function getOrderOfRow(row?: PageRow) {
|
||||
const p = row ? getPageByKey(row.__key) : undefined;
|
||||
return typeof p?.order === 'number' ? (p!.order as number) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assegna l'order SOLO all'elemento spostato (e, se serve, a una piccola finestra attorno)
|
||||
* usando un ordinamento "sparso": media fra i vicini, oppure reseed locale.
|
||||
* Ritorna i delta {id, order} da salvare.
|
||||
*/
|
||||
function sparseAssignOrder(
|
||||
rows: PageRow[],
|
||||
movedIndex: number
|
||||
): { id: string; order: number }[] {
|
||||
const deltas: { id: string; order: number }[] = [];
|
||||
const curRow = rows[movedIndex];
|
||||
if (!curRow?.__key) return deltas;
|
||||
|
||||
const cur = getPageByKey(curRow.__key);
|
||||
if (!cur) return deltas;
|
||||
|
||||
const prevOrder = getOrderOfRow(rows[movedIndex - 1]);
|
||||
const nextOrder = getOrderOfRow(rows[movedIndex + 1]);
|
||||
|
||||
const pushDelta = (p: PageWithKey, val: number) => {
|
||||
if (p.order !== val) {
|
||||
p.order = val;
|
||||
if (p._id) deltas.push({ id: p._id, order: val });
|
||||
}
|
||||
};
|
||||
|
||||
// Caso 1: abbiamo spazio tra prev e next → usa media
|
||||
if (
|
||||
prevOrder !== undefined &&
|
||||
nextOrder !== undefined &&
|
||||
nextOrder - prevOrder > MIN_GAP
|
||||
) {
|
||||
const mid = prevOrder + Math.floor((nextOrder - prevOrder) / 2);
|
||||
pushDelta(cur, mid);
|
||||
return deltas;
|
||||
}
|
||||
|
||||
// Caso 2: in testa → prima del first
|
||||
if (prevOrder === undefined && nextOrder !== undefined) {
|
||||
pushDelta(cur, nextOrder - ORDER_STEP);
|
||||
return deltas;
|
||||
}
|
||||
|
||||
// Caso 3: in coda → dopo l'ultimo
|
||||
if (prevOrder !== undefined && nextOrder === undefined) {
|
||||
pushDelta(cur, prevOrder + ORDER_STEP);
|
||||
return deltas;
|
||||
}
|
||||
|
||||
// Caso 4: nessuno spazio (o ordini uguali) → reseed locale (finestra stretta)
|
||||
const start = Math.max(0, movedIndex - 3);
|
||||
const end = Math.min(rows.length - 1, movedIndex + 3);
|
||||
|
||||
// base = order dell’elemento appena prima della finestra (se esiste), altrimenti 0
|
||||
let base = getOrderOfRow(rows[start - 1]) ?? 0;
|
||||
for (let i = start; i <= end; i++) {
|
||||
const r = rows[i];
|
||||
const p = getPageByKey(r.__key!);
|
||||
if (!p) continue;
|
||||
base += ORDER_STEP;
|
||||
pushDelta(p, base);
|
||||
}
|
||||
|
||||
return deltas;
|
||||
}
|
||||
|
||||
/** order per append in fondo a "menu" */
|
||||
function computeAppendOrderForMenu(): number {
|
||||
let max = 0;
|
||||
for (const p of pages.value)
|
||||
if (p.inmenu && typeof p.order === 'number') max = Math.max(max, p.order!);
|
||||
return max + ORDER_STEP;
|
||||
}
|
||||
|
||||
/** order per append in fondo a "off" (dopo tutti) */
|
||||
function computeAppendOrderForOff(): number {
|
||||
let max = 0;
|
||||
for (const p of pages.value)
|
||||
if (typeof p.order === 'number') max = Math.max(max, p.order!);
|
||||
return max + ORDER_STEP;
|
||||
}
|
||||
|
||||
// ---- STATE BASE --------------------------------------------------------
|
||||
const pages = ref<PageWithKey[]>(
|
||||
props.modelValue ? props.modelValue.map((p) => ({ ...p })) : []
|
||||
);
|
||||
ensureKeys(pages.value);
|
||||
pages.value.sort(byOrder)
|
||||
|
||||
const selectedKey = ref<string | null>(null);
|
||||
|
||||
// Liste derivate per UI
|
||||
const menuRows = ref<PageRow[]>([]); // lista piatta (top + figli) con depth
|
||||
const offList = ref<PageWithKey[]>([]); // voci fuori menu (inmenu=false)
|
||||
const applyingRows = ref(false); // guard per evitare rientri
|
||||
|
||||
// ---- BUILDERS (no side-effects) ---------------------------------------
|
||||
function rebuildMenuRows() {
|
||||
const mapByPath = new Map<string, PageWithKey>();
|
||||
for (const p of pages.value) mapByPath.set(norm(p.path), p);
|
||||
|
||||
const tops = pages.value
|
||||
.filter((p) => p.inmenu && !p.submenu)
|
||||
.sort(byOrder) as PageWithKey[];
|
||||
|
||||
const rows: PageRow[] = [];
|
||||
const usedChildKeys = new Set<string>();
|
||||
|
||||
for (const parent of tops) {
|
||||
rows.push({ ...(parent as any), __depth: 0 });
|
||||
const arr = Array.isArray(parent.sottoMenu) ? parent.sottoMenu : [];
|
||||
for (const childPath of arr) {
|
||||
const child = mapByPath.get(norm(childPath));
|
||||
if (child && child.inmenu !== false && child.submenu === true) {
|
||||
rows.push({ ...(child as any), __depth: 1 });
|
||||
if (child.__key) usedChildKeys.add(child.__key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Orfani: sottomenu==true ma non referenziati da alcun parent
|
||||
const orphans = (pages.value as PageWithKey[])
|
||||
.filter((p) => p.inmenu && p.submenu && p.__key && !usedChildKeys.has(p.__key))
|
||||
.sort(byOrder);
|
||||
for (const ch of orphans) {
|
||||
rows.push({ ...(ch as any), __depth: 0 }); // fallback: top-level
|
||||
}
|
||||
|
||||
menuRows.value = rows;
|
||||
}
|
||||
|
||||
function rebuildOffList() {
|
||||
offList.value = pages.value.filter((p) => !p.inmenu).sort(byOrder);
|
||||
}
|
||||
|
||||
function rebuildAllViews() {
|
||||
rebuildMenuRows();
|
||||
rebuildOffList();
|
||||
globalStore.aggiornaMenu($router);
|
||||
}
|
||||
// ⬇️ Sostituisci completamente la funzione esistente
|
||||
function applyMenuRows(
|
||||
newRows: PageRow[],
|
||||
movedIndex?: number
|
||||
): { id: string; order: number }[] {
|
||||
// 1) svuota i sottoMenu dei parent (ricostruiremo i link)
|
||||
for (const p of pages.value) {
|
||||
if (p.inmenu && !p.submenu) p.sottoMenu = [];
|
||||
}
|
||||
|
||||
// 2) mappa chiave->page
|
||||
const key2page = new Map<string, PageWithKey>();
|
||||
for (const p of pages.value) if (p.__key) key2page.set(p.__key, p);
|
||||
|
||||
// 3) ricostruisci SOLO la struttura (inmenu/submenu e sottoMenu dei parent)
|
||||
let currentParent: PageWithKey | null = null;
|
||||
for (const row of newRows) {
|
||||
const page = row.__key ? key2page.get(row.__key) : undefined;
|
||||
if (!page) continue;
|
||||
|
||||
if (row.__depth <= 0 || !currentParent) {
|
||||
// top-level
|
||||
page.inmenu = true;
|
||||
page.submenu = false;
|
||||
currentParent = page;
|
||||
if (!Array.isArray(page.sottoMenu)) page.sottoMenu = [];
|
||||
} else {
|
||||
// child
|
||||
page.inmenu = true;
|
||||
page.submenu = true;
|
||||
page.mainMenu = true;
|
||||
const pathStr = page.path || '';
|
||||
if (currentParent) {
|
||||
if (!Array.isArray(currentParent.sottoMenu)) currentParent.sottoMenu = [];
|
||||
const exists = currentParent.sottoMenu.some((p) => norm(p) === norm(pathStr));
|
||||
if (!exists) currentParent.sottoMenu.push(pathStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4) assegna order in modalità "sparsa" SOLO per l’elemento spostato (e finestra vicina)
|
||||
if (typeof movedIndex === 'number') {
|
||||
return sparseAssignOrder(newRows, movedIndex);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// ⬇️ Sostituisci completamente la funzione esistente
|
||||
function applyOffList(
|
||||
newOff: PageWithKey[],
|
||||
movedIndex?: number
|
||||
): { id: string; order: number }[] {
|
||||
// 1) togli riferimenti dai sottoMenu dei parent
|
||||
const offPaths = new Set(newOff.map((x) => norm(x.path)));
|
||||
for (const parent of pages.value) {
|
||||
if (parent.inmenu && !parent.submenu && Array.isArray(parent.sottoMenu)) {
|
||||
parent.sottoMenu = parent.sottoMenu.filter((p) => !offPaths.has(norm(p)));
|
||||
}
|
||||
}
|
||||
|
||||
// 2) marca inmenu/submenu=false per tutti gli "off" presenti
|
||||
const offKeys = new Set(newOff.map((x) => x.__key));
|
||||
for (const p of pages.value) {
|
||||
if (p.__key && offKeys.has(p.__key)) {
|
||||
p.inmenu = false;
|
||||
p.submenu = false;
|
||||
p.mainMenu = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) assegna ordine "sparso" al solo elemento spostato
|
||||
const deltas: { id: string; order: number }[] = [];
|
||||
if (typeof movedIndex === 'number') {
|
||||
const prev = newOff[movedIndex - 1];
|
||||
const next = newOff[movedIndex + 1];
|
||||
const cur = newOff[movedIndex];
|
||||
if (cur?.__key) {
|
||||
const curP = getPageByKey(cur.__key);
|
||||
const prevO = prev ? getPageByKey(prev.__key!)?.order : undefined;
|
||||
const nextO = next ? getPageByKey(next.__key!)?.order : undefined;
|
||||
|
||||
const pushDelta = (p: PageWithKey, val: number) => {
|
||||
if (p.order !== val) {
|
||||
p.order = val;
|
||||
if (p._id) deltas.push({ id: p._id, order: val });
|
||||
}
|
||||
};
|
||||
|
||||
if (prevO !== undefined && nextO !== undefined && nextO - prevO > MIN_GAP) {
|
||||
pushDelta(curP!, prevO + Math.floor((nextO - prevO) / 2));
|
||||
} else if (prevO !== undefined && nextO === undefined) {
|
||||
pushDelta(curP!, prevO + ORDER_STEP);
|
||||
} else if (prevO === undefined && nextO !== undefined) {
|
||||
pushDelta(curP!, nextO - ORDER_STEP);
|
||||
} else {
|
||||
// reseed locale nell'offList
|
||||
const start = Math.max(0, movedIndex - 3);
|
||||
const end = Math.min(newOff.length - 1, movedIndex + 3);
|
||||
let base =
|
||||
start > 0 ? (getPageByKey(newOff[start - 1].__key!)?.order ?? 0) : 0;
|
||||
for (let i = start; i <= end; i++) {
|
||||
const r = newOff[i];
|
||||
const p = getPageByKey(r.__key!);
|
||||
if (!p) continue;
|
||||
base += ORDER_STEP;
|
||||
pushDelta(p, base);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deltas;
|
||||
}
|
||||
// ---- WATCHERS ----------------------------------------------------------
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(v) => {
|
||||
pages.value = v ? [...v] : [];
|
||||
if (selectedIndex.value >= pages.value.length) selectedIndex.value = -1;
|
||||
}
|
||||
pages.value = (v || []).map((p) => ({ ...p }));
|
||||
ensureKeys(pages.value);
|
||||
pages.value.sort(byOrder)
|
||||
rebuildAllViews();
|
||||
if (!pages.value.find((p) => p.__key === selectedKey.value))
|
||||
selectedKey.value = null;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const localPagesSorted = computed(() => {
|
||||
return [...pages.value].sort((a, b) => (a.order || 0) - (b.order || 0));
|
||||
});
|
||||
// ricostruisci la vista quando pages cambia (evita durante apply)
|
||||
watch(
|
||||
() => pages.value,
|
||||
() => {
|
||||
if (applyingRows.value) return;
|
||||
rebuildAllViews();
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
function originalIndex(sortedIdx: number) {
|
||||
// mappa l’indice sortato all’indice reale in pages
|
||||
const item = localPagesSorted.value[sortedIdx];
|
||||
return pages.value.indexOf(item);
|
||||
// ---- SELEZIONE / UTILS -------------------------------------------------
|
||||
const currentIdx = computed(() =>
|
||||
pages.value.findIndex((p) => p.__key === selectedKey.value)
|
||||
);
|
||||
|
||||
function select(key?: string) {
|
||||
selectedKey.value = key || null;
|
||||
}
|
||||
|
||||
const current = computed(() => pages.value[selectedIndex.value]);
|
||||
function displayPath(path?: string) {
|
||||
if (!path) return '-';
|
||||
return path.startsWith('/') ? path : '/' + path;
|
||||
}
|
||||
|
||||
// Removed automatic order reindexing to preserve original order values
|
||||
// ---- AZIONI UI ---------------------------------------------------------
|
||||
function addSubmenu() {
|
||||
const p = pages.value.find((x) => x.__key === selectedKey.value);
|
||||
if (!p) return;
|
||||
|
||||
// Duplicate outer function removed, keeping the inner implementation
|
||||
function addPage() {
|
||||
const newOrder =
|
||||
pages.value.reduce((max: number, p: IMyPage) => Math.max(max, p.order ?? 0), 0) +
|
||||
1;
|
||||
const np: IMyPage = {
|
||||
if (!Array.isArray(p.sottoMenu)) p.sottoMenu = [];
|
||||
if (p.submenu !== true) p.submenu = true;
|
||||
if (p.mainMenu !== true) p.mainMenu = true;
|
||||
|
||||
// placeholder path
|
||||
const base = '/nuova-voce';
|
||||
let name = base;
|
||||
let i = 1;
|
||||
while (p.sottoMenu.includes(name)) {
|
||||
i++;
|
||||
name = `${base}-${i}`;
|
||||
}
|
||||
p.sottoMenu.push(name);
|
||||
|
||||
emit(
|
||||
'update:modelValue',
|
||||
pages.value.map((x) => ({ ...x }))
|
||||
);
|
||||
rebuildAllViews();
|
||||
}
|
||||
|
||||
function addPage(bucket: Bucket) {
|
||||
visualizzaEditor.value = true; // ⬅️ aggiungi
|
||||
nuovaPagina.value = true; // ⬅️ aggiungi
|
||||
const np: PageWithKey = {
|
||||
title: '',
|
||||
path: '/nuova-pagina-' + (Math.floor(Math.random() * 8999) + 1000).toString(),
|
||||
icon: 'fa-regular fa-file-lines',
|
||||
path: '/nuova-pagina',
|
||||
icon: 'far fa-file-alt',
|
||||
iconsize: '24px',
|
||||
active: true,
|
||||
inmenu: true,
|
||||
inmenu: bucket === 'menu',
|
||||
submenu: false,
|
||||
onlyif_logged: false,
|
||||
order: newOrder,
|
||||
order:
|
||||
bucket === 'menu' ? computeAppendOrderForMenu() : computeAppendOrderForOff(),
|
||||
__key: `tmp_${uidSeed++}`,
|
||||
};
|
||||
pages.value.push(np);
|
||||
selectedIndex.value = pages.value.length - 1;
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
emit(
|
||||
'update:modelValue',
|
||||
pages.value.map((p) => ({ ...p }))
|
||||
);
|
||||
rebuildAllViews();
|
||||
selectedKey.value = np.__key!;
|
||||
}
|
||||
|
||||
function removePage(idx: number) {
|
||||
if (idx < 0) return;
|
||||
const page = pages.value[idx];
|
||||
if (!page) return;
|
||||
pages.value.splice(idx, 1);
|
||||
if (selectedIndex.value === idx) selectedIndex.value = -1;
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
// Add cleanup logic for page deletion
|
||||
if (page._id) {
|
||||
// Mark for deletion in backend
|
||||
void deletePageFromServer(page);
|
||||
}
|
||||
}
|
||||
function removeAt(bucket: Bucket, idx: number) {
|
||||
const target = bucket === 'menu' ? menuRows.value[idx] : offList.value[idx];
|
||||
if (!target) return;
|
||||
|
||||
async function deletePageFromServer(page: IMyPage) {
|
||||
if (!page._id) return;
|
||||
$q.dialog({
|
||||
title: 'Conferma cancellazione',
|
||||
message: `Sei sicuro di voler cancellare la pagina "${target.title || target.path}"?`,
|
||||
cancel: true,
|
||||
persistent: true,
|
||||
}).onOk(async () => {
|
||||
// rimuovi il record da pages
|
||||
const key = target.__key;
|
||||
const pathN = norm(target.path);
|
||||
const i = pages.value.findIndex((p) => p.__key === key);
|
||||
if (i >= 0) pages.value.splice(i, 1);
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/pages/${page._id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete page from server');
|
||||
// pulisci eventuali riferimenti nei sottoMenu dei parent
|
||||
for (const parent of pages.value) {
|
||||
if (parent.inmenu && !parent.submenu && Array.isArray(parent.sottoMenu)) {
|
||||
parent.sottoMenu = parent.sottoMenu.filter((p) => norm(p) !== pathN);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting page:', error);
|
||||
// Revert changes if deletion fails
|
||||
pages.value.splice(originalIndex, 0, page);
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
|
||||
emit(
|
||||
'update:modelValue',
|
||||
pages.value.map((p) => ({ ...p }))
|
||||
);
|
||||
rebuildAllViews();
|
||||
if (selectedKey.value === key) selectedKey.value = null;
|
||||
|
||||
// opzionale: elimina anche lato server
|
||||
try {
|
||||
await globalStore.deletePage($q, target._id || '');
|
||||
} catch {}
|
||||
});
|
||||
}
|
||||
|
||||
function move(bucket: Bucket, idx: number, delta: number) {
|
||||
if (bucket === 'menu') {
|
||||
const list = menuRows.value.slice();
|
||||
const to = idx + delta;
|
||||
if (to < 0 || to >= list.length) return;
|
||||
const [it] = list.splice(idx, 1);
|
||||
list.splice(to, 0, it);
|
||||
menuRows.value = list;
|
||||
onMenuDragChange({ moved: { newIndex: to } }); // ⬅️ usa handler con indice
|
||||
selectedKey.value = it.__key!;
|
||||
} else {
|
||||
const list = offList.value.slice();
|
||||
const to = idx + delta;
|
||||
if (to < 0 || to >= list.length) return;
|
||||
const [it] = list.splice(idx, 1);
|
||||
list.splice(to, 0, it);
|
||||
offList.value = list;
|
||||
onOffDragChange({ moved: { newIndex: to } }); // ⬅️ idem
|
||||
selectedKey.value = it.__key!;
|
||||
}
|
||||
}
|
||||
|
||||
function select(idx: number) {
|
||||
selectedIndex.value = idx;
|
||||
}
|
||||
// ⬇️ Sostituisci la tua onMenuDragChange
|
||||
function onMenuDragChange(evt?: any) {
|
||||
const movedIndex: number | undefined = evt?.moved?.newIndex;
|
||||
applyingRows.value = true;
|
||||
let deltas: { id: string; order: number }[] = [];
|
||||
try {
|
||||
deltas = applyMenuRows(menuRows.value, movedIndex);
|
||||
} finally {
|
||||
applyingRows.value = false;
|
||||
rebuildAllViews();
|
||||
}
|
||||
|
||||
function swap(i: number, j: number) {
|
||||
const a = pages.value[i];
|
||||
const b = pages.value[j];
|
||||
if (!a || !b) return;
|
||||
const ao = a.order ?? i;
|
||||
const bo = b.order ?? j;
|
||||
a.order = bo;
|
||||
b.order = ao;
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
emit(
|
||||
'update:modelValue',
|
||||
pages.value.map((p) => ({ ...p }))
|
||||
);
|
||||
if (deltas.length) emit('change-order', deltas);
|
||||
if (typeof globalStore.aggiornaMenu === 'function') {
|
||||
try {
|
||||
globalStore.aggiornaMenu($router);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
// ⬇️ Sostituisci la tua onOffDragChange
|
||||
function onOffDragChange(evt?: any) {
|
||||
const movedIndex: number | undefined = evt?.moved?.newIndex;
|
||||
const deltas = applyOffList(offList.value, movedIndex);
|
||||
|
||||
function moveUp(idx: number) {
|
||||
if (idx <= 0) return;
|
||||
const prev = idx - 1;
|
||||
const a = pages.value[idx];
|
||||
const b = pages.value[prev];
|
||||
if (!a || !b) return;
|
||||
const ao = a.order ?? idx;
|
||||
const bo = b.order ?? prev;
|
||||
a.order = bo;
|
||||
b.order = ao;
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
rebuildAllViews();
|
||||
emit(
|
||||
'update:modelValue',
|
||||
pages.value.map((p) => ({ ...p }))
|
||||
);
|
||||
if (deltas.length) emit('change-order', deltas);
|
||||
if (typeof globalStore.aggiornaMenu === 'function') {
|
||||
try {
|
||||
globalStore.aggiornaMenu($router);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
function moveDown(idx: number) {
|
||||
if (idx >= pages.value.length - 1) return;
|
||||
const next = idx + 1;
|
||||
const a = pages.value[idx];
|
||||
const b = pages.value[next];
|
||||
if (!a || !b) return;
|
||||
const ao = a.order ?? idx;
|
||||
const bo = b.order ?? next;
|
||||
a.order = bo;
|
||||
b.order = ao;
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
}
|
||||
|
||||
function onApply() {
|
||||
emit('update:modelValue', [...pages.value]);
|
||||
emit('save', current.value);
|
||||
}
|
||||
function onClose() {
|
||||
selectedIndex.value = -1;
|
||||
emit(
|
||||
'update:modelValue',
|
||||
pages.value.map((p) => ({ ...p }))
|
||||
);
|
||||
const cur = currentIdx.value >= 0 ? pages.value[currentIdx.value] : undefined;
|
||||
emit('save', cur);
|
||||
rebuildAllViews();
|
||||
|
||||
visualizzaEditor.value = false; // ⬅️ aggiungi
|
||||
nuovaPagina.value = false; // ⬅️ aggiungi
|
||||
}
|
||||
|
||||
function editAt(idx: number) {
|
||||
const key = (menuRows.value[idx] || offList.value[idx])?.__key;
|
||||
selectedKey.value = key || selectedKey.value;
|
||||
|
||||
visualizzaEditor.value = true; // ⬅️ aggiungi
|
||||
nuovaPagina.value = false; // ⬅️ aggiungi
|
||||
}
|
||||
|
||||
function openKey(key?: string) {
|
||||
const p = pages.value.find((x) => x.__key === key);
|
||||
if (!p) return;
|
||||
$router.push(`/${p.path}?edit=1`);
|
||||
}
|
||||
|
||||
// ---- EXPOSE ------------------------------------------------------------
|
||||
return {
|
||||
pages,
|
||||
selectedIndex,
|
||||
localPagesSorted,
|
||||
current,
|
||||
menuRows,
|
||||
offList,
|
||||
selectedKey,
|
||||
currentIdx,
|
||||
// actions
|
||||
select,
|
||||
addPage,
|
||||
removePage,
|
||||
moveUp,
|
||||
moveDown,
|
||||
originalIndex,
|
||||
addSubmenu,
|
||||
removeAt,
|
||||
move,
|
||||
onMenuDragChange,
|
||||
onOffDragChange,
|
||||
onApply,
|
||||
onClose,
|
||||
displayPath,
|
||||
editAt,
|
||||
openKey,
|
||||
visualizzaEditor, // ⬅️ aggiungi
|
||||
nuovaPagina, // ⬅️ aggiungi
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,67 +1,122 @@
|
||||
<template>
|
||||
<div class="row q-col-gutter-md">
|
||||
<!-- Lista pagine -->
|
||||
<div class="col-12 col-md-5">
|
||||
<q-card flat bordered>
|
||||
<!-- COLONNA: Nel menu -->
|
||||
<div class="col-12 col-md-6">
|
||||
<q-card
|
||||
flat
|
||||
bordered
|
||||
>
|
||||
<q-toolbar>
|
||||
<q-toolbar-title>Pagine</q-toolbar-title>
|
||||
<q-btn dense icon="fas fa-plus" label="Aggiungi" @click="addPage" />
|
||||
<q-toolbar-title>Menu</q-toolbar-title>
|
||||
<q-badge
|
||||
color="primary"
|
||||
:label="menuRows.length"
|
||||
/>
|
||||
<q-space />
|
||||
<q-btn
|
||||
dense
|
||||
icon="fas fa-plus"
|
||||
label="Nuovo"
|
||||
@click="addPage('menu')"
|
||||
/>
|
||||
<q-btn
|
||||
dense
|
||||
icon="fas fa-sitemap"
|
||||
label="SottoMenu"
|
||||
:disable="!selectedKey"
|
||||
@click="addSubmenu()"
|
||||
/>
|
||||
</q-toolbar>
|
||||
|
||||
<q-list separator>
|
||||
<q-item
|
||||
v-for="(p, idx) in localPagesSorted"
|
||||
:key="p._id || idx"
|
||||
clickable
|
||||
:active="selectedIndex === originalIndex(idx)"
|
||||
@click="select(originalIndex(idx))"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="p.icon || 'fa-regular fa-file-lines'" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ p.title || '(senza titolo)' }}</q-item-label>
|
||||
<q-item-label caption>{{ p.path || '-' }}</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side top>
|
||||
<div class="row items-center q-gutter-xs">
|
||||
<q-badge :color="p.active ? 'positive' : 'grey'">{{ p.active ? 'attiva' : 'spenta' }}</q-badge>
|
||||
<q-badge :color="p.inmenu ? 'primary' : 'grey'">menu</q-badge>
|
||||
</div>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side>
|
||||
<div class="column q-gutter-xs">
|
||||
<!--<q-btn dense round icon="fas fa-chevron-up" @click.stop="moveUp(originalIndex(idx))" />
|
||||
<q-btn dense round icon="fas fa-chevron-down" @click.stop="moveDown(originalIndex(idx))" />-->
|
||||
<q-btn dense round color="negative" icon="fas fa-trash" @click.stop="removePage(originalIndex(idx))" />
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
<draggable
|
||||
v-model="menuRows"
|
||||
item-key="__key"
|
||||
group="pages"
|
||||
handle=".drag-handle"
|
||||
:animation="180"
|
||||
ghost-class="bg-grey-2"
|
||||
@change="onMenuDragChange($event)"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<MenuPageItem
|
||||
:item="element"
|
||||
:selected="selectedKey === element.__key"
|
||||
v-model:active="element.active"
|
||||
:depth="element.__depth"
|
||||
variant="menu"
|
||||
@select="select(element.__key)"
|
||||
@edit="editAt(index)"
|
||||
@delete="removeAt('menu', index)"
|
||||
@open="openKey(element.__key)"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<!-- Editor pagina selezionata -->
|
||||
<div class="col-12 col-md-7">
|
||||
<!-- COLONNA: Fuori menu -->
|
||||
<div class="col-12 col-md-6">
|
||||
<q-card
|
||||
flat
|
||||
bordered
|
||||
>
|
||||
<q-toolbar>
|
||||
<q-toolbar-title>Pagine</q-toolbar-title>
|
||||
<q-badge
|
||||
color="grey-7"
|
||||
:label="offList.length"
|
||||
/>
|
||||
<q-space />
|
||||
<q-btn
|
||||
dense
|
||||
icon="fas fa-plus"
|
||||
label="Aggiungi"
|
||||
@click="addPage('off')"
|
||||
/>
|
||||
</q-toolbar>
|
||||
|
||||
<draggable
|
||||
v-model="offList"
|
||||
item-key="__key"
|
||||
group="pages"
|
||||
handle=".drag-handle"
|
||||
:animation="180"
|
||||
ghost-class="bg-grey-2"
|
||||
@change="onOffDragChange($event)"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<MenuPageItem
|
||||
:item="element"
|
||||
:selected="selectedKey === element.__key"
|
||||
v-model:active="element.active"
|
||||
variant="off"
|
||||
:depth="0"
|
||||
@select="select(element.__key)"
|
||||
@delete="removeAt('off', index)"
|
||||
@open="openKey(element.__key)"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<!-- Editor -->
|
||||
<q-dialog
|
||||
v-model="visualizzaEditor"
|
||||
persistent
|
||||
>
|
||||
<page-editor
|
||||
v-if="current"
|
||||
v-model="pages[selectedIndex]"
|
||||
v-if="currentIdx !== -1"
|
||||
v-model="pages[currentIdx]"
|
||||
@apply="onApply"
|
||||
@close="onClose"
|
||||
@hide="visualizzaEditor = false"
|
||||
:nuovaPagina="nuovaPagina"
|
||||
/>
|
||||
<q-card v-else flat bordered class="q-pa-lg flex flex-center text-grey">
|
||||
Seleziona o aggiungi una pagina.
|
||||
</q-card>
|
||||
</div>
|
||||
</q-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./PagesConfigurator.ts">
|
||||
</script>
|
||||
|
||||
<script lang="ts" src="./PagesConfigurator.ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
@import './PagesConfigurator.scss';
|
||||
</style>
|
||||
|
||||
18
src/composables/useDnd.js
Normal file
18
src/composables/useDnd.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const useDnd = () => {
|
||||
const dragging = ref(false);
|
||||
const draggedElement = ref(null);
|
||||
|
||||
const startDrag = (element) => {
|
||||
dragging.value = true;
|
||||
draggedElement.value = element;
|
||||
};
|
||||
|
||||
const endDrag = () => {
|
||||
dragging.value = false;
|
||||
draggedElement.value = null;
|
||||
};
|
||||
|
||||
return { dragging, draggedElement, startDrag, endDrag };
|
||||
};
|
||||
29
src/composables/useHistory.js
Normal file
29
src/composables/useHistory.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const useHistory = () => {
|
||||
const history = ref([]);
|
||||
const currentIndex = ref(-1);
|
||||
|
||||
const addToHistory = (state) => {
|
||||
history.value.push(state);
|
||||
currentIndex.value = history.value.length - 1;
|
||||
};
|
||||
|
||||
const undo = () => {
|
||||
if (currentIndex.value > 0) {
|
||||
currentIndex.value--;
|
||||
return history.value[currentIndex.value];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const redo = () => {
|
||||
if (currentIndex.value < history.value.length - 1) {
|
||||
currentIndex.value++;
|
||||
return history.value[currentIndex.value];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return { history, addToHistory, undo, redo };
|
||||
};
|
||||
@@ -1,65 +1,86 @@
|
||||
import type { IListRoutes } from '@src/model'
|
||||
import { useGlobalStore } from '@store/globalStore'
|
||||
import { tools } from '@tools'
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { static_data } from '@src/db/static_data'
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import type { IListRoutes } from '@src/model';
|
||||
import { useGlobalStore } from '@store/globalStore';
|
||||
import { tools } from '@tools';
|
||||
import { computed, defineComponent, ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { static_data } from '@src/db/static_data';
|
||||
import { useUserStore } from '@store/UserStore';
|
||||
|
||||
import { CMenuItem } from '../../components/CMenuItem'
|
||||
import { CMenuItem } from '../../components/CMenuItem';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MenuOne',
|
||||
|
||||
components: { CMenuItem },
|
||||
setup(props) {
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
const finishLoading = computed(() => globalStore.finishLoading)
|
||||
const finishLoading = computed(() => globalStore.finishLoading);
|
||||
const updateMenu = computed(() => globalStore.updateMenu);
|
||||
|
||||
const path = computed(() => route.path)
|
||||
const path = computed(() => route.path);
|
||||
|
||||
const getroutes = computed(() => static_data.routes)
|
||||
const getroutes = computed(() => static_data.routes);
|
||||
|
||||
const myroutes = ref(<IListRoutes[]>[])
|
||||
const myroutes = ref(<IListRoutes[]>[]);
|
||||
|
||||
const getmenu = computed(() => globalStore.getmenu)
|
||||
const getmenu = computed(() => globalStore.getmenu);
|
||||
|
||||
const islogged = computed(() => userStore.isLogged)
|
||||
const islogged = computed(() => userStore.isLogged);
|
||||
|
||||
const clBase = ref('my-menu')
|
||||
const clBase = ref('my-menu');
|
||||
|
||||
function setParentVisibilityBasedOnRoute(parent: any) {
|
||||
parent.routes.forEach((item: any) => {
|
||||
if (path.value === item.path) {
|
||||
parent.show = true
|
||||
parent.show = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function updatemenu() {
|
||||
const mymenu = globalStore.getmenu
|
||||
console.log('*** updatemenu');
|
||||
const mymenu = globalStore.getmenu;
|
||||
Object.keys(mymenu).forEach((parentName: any) => {
|
||||
// @ts-ignore
|
||||
setParentVisibilityBasedOnRoute(mymenu[parentName])
|
||||
})
|
||||
myroutes.value = []
|
||||
myroutes.value = static_data.routes
|
||||
setParentVisibilityBasedOnRoute(mymenu[parentName]);
|
||||
});
|
||||
myroutes.value = [];
|
||||
myroutes.value = static_data.routes;
|
||||
|
||||
globalStore.updateMenu = false;
|
||||
}
|
||||
|
||||
watch(() => islogged.value, (to, from) => {
|
||||
updatemenu()
|
||||
})
|
||||
watch(
|
||||
() => islogged.value,
|
||||
(to, from) => {
|
||||
updatemenu();
|
||||
}
|
||||
);
|
||||
|
||||
watch(() => finishLoading.value, (to, from) => {
|
||||
updatemenu()
|
||||
})
|
||||
watch(
|
||||
() => finishLoading.value,
|
||||
(to, from) => {
|
||||
updatemenu();
|
||||
}
|
||||
);
|
||||
|
||||
watch(() => path, (to, from) => {
|
||||
updatemenu()
|
||||
})
|
||||
watch(
|
||||
() => updateMenu.value,
|
||||
(newValue, oldValue) => {
|
||||
if (newValue) updatemenu();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => path,
|
||||
(to, from) => {
|
||||
updatemenu();
|
||||
}
|
||||
);
|
||||
|
||||
/* function replaceUnderlineToSpace(text: string) {
|
||||
while (text.indexOf('_') !== -1) {
|
||||
@@ -69,61 +90,56 @@ export default defineComponent({
|
||||
} */
|
||||
|
||||
function getroute(elem: IListRoutes) {
|
||||
let link = ''
|
||||
let link = '';
|
||||
if (elem.idelem) {
|
||||
link = tools.getUrlByTipoProj(elem.urlroute ? elem.urlroute : '') + elem.idelem
|
||||
link = tools.getUrlByTipoProj(elem.urlroute ? elem.urlroute : '') + elem.idelem;
|
||||
}
|
||||
if (!link)
|
||||
link = elem.path
|
||||
if (!link) link = elem.path;
|
||||
|
||||
// console.log('getroute LINK=', link)
|
||||
return link
|
||||
return link;
|
||||
}
|
||||
|
||||
function getmymenuclass(elem: IListRoutes) {
|
||||
let menu: string = clBase.value
|
||||
let menu: string = clBase.value;
|
||||
|
||||
if (elem.color) {
|
||||
menu += ` ${elem.color}`
|
||||
menu += ` ${elem.color}`;
|
||||
} else {
|
||||
if (elem.onlyAdmin) menu += ' isAdmin'
|
||||
if (elem.onlyManager) menu += ' isManager'
|
||||
if (elem.onlySocioResidente) menu += ' isSocioResidente'
|
||||
if (elem.onlyConsiglio) menu += ' isConsiglio'
|
||||
if (elem.onlyDepartment) menu += ' isDepartment'
|
||||
if (elem.onlyFacilitatore) menu += ' isFacilitatore'
|
||||
if (elem.onlyEditor) menu += ' isEditor'
|
||||
if (elem.onlyCommerciale) menu += ' isCommerciale'
|
||||
if (elem.onlyCollaboratore) menu += ' isCollaboratore'
|
||||
if (elem.onlyGrafico) menu += ' isGrafico'
|
||||
if (elem.onlyAdmin) menu += ' isAdmin';
|
||||
if (elem.onlyManager) menu += ' isManager';
|
||||
if (elem.onlySocioResidente) menu += ' isSocioResidente';
|
||||
if (elem.onlyConsiglio) menu += ' isConsiglio';
|
||||
if (elem.onlyDepartment) menu += ' isDepartment';
|
||||
if (elem.onlyFacilitatore) menu += ' isFacilitatore';
|
||||
if (elem.onlyEditor) menu += ' isEditor';
|
||||
if (elem.onlyCommerciale) menu += ' isCommerciale';
|
||||
if (elem.onlyCollaboratore) menu += ' isCollaboratore';
|
||||
if (elem.onlyGrafico) menu += ' isGrafico';
|
||||
}
|
||||
|
||||
if (elem.extraclass) menu += ` ${elem.extraclass}`
|
||||
if (elem.extraclass) menu += ` ${elem.extraclass}`;
|
||||
|
||||
// console.log('menu', menu)
|
||||
return menu
|
||||
return menu;
|
||||
}
|
||||
|
||||
function getimgiconclass(elem: IListRoutes) {
|
||||
if (elem.extraclass)
|
||||
return elem.extraclass
|
||||
else
|
||||
return 'imgicon'
|
||||
if (elem.extraclass) return elem.extraclass;
|
||||
else return 'imgicon';
|
||||
}
|
||||
function getimgiconclass2(elem: IListRoutes) {
|
||||
if (elem.extraclass)
|
||||
return elem.extraclass
|
||||
else
|
||||
return 'clBase'
|
||||
if (elem.extraclass) return elem.extraclass;
|
||||
else return 'clBase';
|
||||
}
|
||||
|
||||
function getmenuByPath(path: string) {
|
||||
const mymenufind = static_data.routes.find((menu: any) => menu.path === '/' + path)
|
||||
const mymenufind = static_data.routes.find((menu: any) => menu.path === '/' + path);
|
||||
|
||||
return mymenufind
|
||||
return mymenufind;
|
||||
}
|
||||
|
||||
myroutes.value = static_data.routes
|
||||
myroutes.value = static_data.routes;
|
||||
|
||||
return {
|
||||
getmenu,
|
||||
@@ -138,6 +154,6 @@ export default defineComponent({
|
||||
getimgiconclass2,
|
||||
getmenuByPath,
|
||||
clBase,
|
||||
}
|
||||
};
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
@@ -194,6 +194,8 @@ export interface IMyElem {
|
||||
elemsText?: IElemText[]
|
||||
titleBanner?: string
|
||||
classBanner?: string
|
||||
color?: string
|
||||
children?: any[]
|
||||
}
|
||||
|
||||
export interface IElemText {
|
||||
@@ -236,6 +238,7 @@ export interface IMyPage {
|
||||
elemsText?: IElemText[]
|
||||
onlyif_logged?: boolean
|
||||
only_residenti?: boolean
|
||||
only_admin?: boolean
|
||||
only_consiglio?: boolean
|
||||
only_collab?: boolean
|
||||
submenu?: boolean
|
||||
@@ -479,6 +482,7 @@ export interface ISelector {
|
||||
}
|
||||
export interface IGlobalState {
|
||||
finishLoading: boolean
|
||||
updateMenu: boolean
|
||||
showHeader?: boolean
|
||||
inStampa?: boolean
|
||||
conta: number
|
||||
|
||||
@@ -1,103 +1,153 @@
|
||||
import { defineComponent, ref, watch, onMounted } from 'vue'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { IMyPage } from 'app/src/model'
|
||||
import { useGlobalStore } from 'app/src/store'
|
||||
import { PagesConfigurator } from '@src/components/PagesConfigurator'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { defineComponent, ref, watch, onMounted } from 'vue';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { IMyPage } from 'app/src/model';
|
||||
import { useGlobalStore } from 'app/src/store';
|
||||
import { PagesConfigurator } from '@src/components/PagesConfigurator';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PagesAdmin',
|
||||
components: { PagesConfigurator },
|
||||
setup () {
|
||||
const $q = useQuasar()
|
||||
const { t } = useI18n()
|
||||
setup() {
|
||||
const $q = useQuasar();
|
||||
const { t } = useI18n();
|
||||
|
||||
const globalStore = useGlobalStore()
|
||||
const { mypage } = storeToRefs(globalStore)
|
||||
const globalStore = useGlobalStore();
|
||||
const { mypage } = storeToRefs(globalStore);
|
||||
|
||||
const $router = useRouter()
|
||||
|
||||
// Copia locale per l’editing tramite v-model
|
||||
const pagesLocal = ref<IMyPage[]>([])
|
||||
const savingAll = ref(false)
|
||||
const pagesLocal = ref<IMyPage[]>([]);
|
||||
const savingAll = ref(false);
|
||||
|
||||
// Mantieni pagesLocal <-> store allineati
|
||||
const syncFromStore = () => {
|
||||
pagesLocal.value = (mypage.value || []).map(p => ({ ...p }))
|
||||
}
|
||||
pagesLocal.value = (mypage.value || []).map((p) => ({ ...p }));
|
||||
};
|
||||
|
||||
watch(mypage, syncFromStore, { deep: true })
|
||||
watch(mypage, syncFromStore, { deep: true });
|
||||
onMounted(async () => {
|
||||
// Se hai una funzione per caricare tutte le pagine, chiamala qui
|
||||
// es. await globalStore.loadAllPages()
|
||||
syncFromStore()
|
||||
})
|
||||
syncFromStore();
|
||||
});
|
||||
|
||||
// Salva singola pagina (chiamato da PagesConfigurator @save)
|
||||
async function saveOne (page: IMyPage) {
|
||||
try {
|
||||
const saved = await globalStore.savePage({ ...page })
|
||||
if (saved && typeof saved === 'object') {
|
||||
// rimpiazza nel local e nello store (lo store viene aggiornato da savePage)
|
||||
const idx = pagesLocal.value.findIndex(p =>
|
||||
(p._id && p._id === saved._id) || (p.path && p.path === saved.path)
|
||||
)
|
||||
if (idx >= 0) pagesLocal.value[idx] = { ...saved }
|
||||
$q.notify({ type: 'positive', message: `Salvata: ${saved.title || saved.path}` })
|
||||
} else {
|
||||
$q.notify({ type: 'positive', message: 'Salvataggio completato' })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio della pagina' })
|
||||
const lastOrderSnapshot = ref<Map<string, number>>(new Map());
|
||||
const savingOrders = ref(false);
|
||||
|
||||
// crea/ricostruisce lo snapshot (solo pagine con _id)
|
||||
function initOrderSnapshot(arr: IMyPage[]) {
|
||||
const m = new Map<string, number>();
|
||||
for (const p of arr) {
|
||||
if (p._id) m.set(p._id, p.order ?? 0);
|
||||
}
|
||||
lastOrderSnapshot.value = m;
|
||||
}
|
||||
|
||||
// call una volta dopo aver caricato le pagine
|
||||
onMounted(() => {
|
||||
initOrderSnapshot(pagesLocal.value); // pagesLocal è il tuo array locale già usato
|
||||
});
|
||||
|
||||
// quando salvi una pagina singola e ottieni l'_id, aggiorna lo snapshot
|
||||
async function saveOne(p: IMyPage) {
|
||||
try {
|
||||
const saved = await globalStore.savePage({ ...p });
|
||||
if (saved && saved._id) {
|
||||
// aggiorna la copia locale
|
||||
const idx = pagesLocal.value.findIndex(
|
||||
(x) => (x._id && x._id === saved._id) || (x.path && x.path === saved.path)
|
||||
);
|
||||
if (idx >= 0) pagesLocal.value[idx] = { ...saved };
|
||||
// aggiorna lo snapshot dell'ordinamento persistito
|
||||
lastOrderSnapshot.value.set(
|
||||
saved._id,
|
||||
saved.order ?? pagesLocal.value[idx]?.order ?? 0
|
||||
);
|
||||
$q.notify({
|
||||
type: 'positive',
|
||||
message: `Salvata: ${saved.title || saved.path}`,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio della pagina' });
|
||||
}
|
||||
}
|
||||
// Salva l’ordinamento (fallback: batch di savePage per aggiornare order)
|
||||
async function saveOrder (orders: { id?: string; order: number }[]) {
|
||||
async function saveOrder(orders: { id?: string; order: number }[]) {
|
||||
try {
|
||||
// Applica l'order nella copia locale
|
||||
for (const { id, order } of orders) {
|
||||
const p = pagesLocal.value.find(x => x._id === id) ||
|
||||
pagesLocal.value.find(x => !id && typeof x.order === 'number' && x.order === order)
|
||||
if (p) p.order = order
|
||||
if (savingOrders.value) return;
|
||||
savingOrders.value = true;
|
||||
|
||||
// 1) calcola solo i cambi VERI su pagine già persistite (_id presente)
|
||||
const changedExisting = orders.filter((o) => {
|
||||
if (!o.id) return false; // ignora nuovi senza id
|
||||
const prev = lastOrderSnapshot.value.get(o.id);
|
||||
return prev === undefined ? false : prev !== o.order;
|
||||
});
|
||||
|
||||
// 2) se non è cambiato nulla di "persistito", esci silenziosamente
|
||||
if (changedExisting.length === 0) {
|
||||
// console.debug('[saveOrder] nessun cambiamento persistente')
|
||||
return;
|
||||
}
|
||||
// Fallback: se non hai un endpoint /reorder, salvi singolarmente
|
||||
|
||||
// fallback: salva solo le pagine cambiate
|
||||
await Promise.all(
|
||||
pagesLocal.value.map(p => globalStore.savePage({ ...p }))
|
||||
)
|
||||
$q.notify({ type: 'positive', message: 'Ordinamento salvato' })
|
||||
changedExisting.map(({ id, order }) => {
|
||||
const p = pagesLocal.value.find((x) => x._id === id);
|
||||
if (!p) return Promise.resolve();
|
||||
// se il tuo savePage accetta payload parziale, meglio passare solo {_id, order}
|
||||
// altrimenti manda l'oggetto intero con order aggiornato
|
||||
return globalStore.savePage({ ...p, order });
|
||||
})
|
||||
);
|
||||
|
||||
// 4) aggiorna lo snapshot solo per gli elementi realmente salvati
|
||||
for (const { id, order } of changedExisting) {
|
||||
if (id) lastOrderSnapshot.value.set(id, order);
|
||||
}
|
||||
|
||||
$q.notify({ type: 'positive', message: 'Ordinamento aggiornato' });
|
||||
|
||||
globalStore.aggiornaMenu($router);
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio dell’ordinamento' })
|
||||
console.error(err);
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
message: 'Errore nel salvataggio dell’ordinamento',
|
||||
});
|
||||
} finally {
|
||||
savingOrders.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ricarica l’elenco (se disponibile una API globale; altrimenti rilegge dallo store)
|
||||
async function reloadAll () {
|
||||
async function reloadAll() {
|
||||
try {
|
||||
// Se esiste: await globalStore.loadAllPages()
|
||||
syncFromStore()
|
||||
$q.notify({ type: 'info', message: 'Elenco ricaricato' })
|
||||
syncFromStore();
|
||||
$q.notify({ type: 'info', message: 'Elenco ricaricato' });
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel ricaricare l’elenco' })
|
||||
console.error(err);
|
||||
$q.notify({ type: 'negative', message: 'Errore nel ricaricare l’elenco' });
|
||||
}
|
||||
}
|
||||
|
||||
// Salva tutto (batch)
|
||||
async function saveAll () {
|
||||
async function saveAll() {
|
||||
try {
|
||||
savingAll.value = true
|
||||
await Promise.all(
|
||||
pagesLocal.value.map(p => globalStore.savePage({ ...p }))
|
||||
)
|
||||
$q.notify({ type: 'positive', message: 'Tutte le pagine salvate' })
|
||||
savingAll.value = true;
|
||||
await Promise.all(pagesLocal.value.map((p) => globalStore.savePage({ ...p })));
|
||||
$q.notify({ type: 'positive', message: 'Tutte le pagine salvate' });
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio massivo' })
|
||||
console.error(err);
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio massivo' });
|
||||
} finally {
|
||||
savingAll.value = false
|
||||
savingAll.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +159,6 @@ export default defineComponent({
|
||||
saveAll,
|
||||
savingAll,
|
||||
t,
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<q-page class="q-pa-md">
|
||||
<q-toolbar class="q-mb-md">
|
||||
<q-toolbar-title>Configuratore Pagine</q-toolbar-title>
|
||||
<q-toolbar-title class="text-center">Configura Pagine</q-toolbar-title>
|
||||
<q-space />
|
||||
<q-btn
|
||||
flat
|
||||
|
||||
0
src/rootgen/admin/importaprodotti/importaprodotti.scss
Executable file
0
src/rootgen/admin/importaprodotti/importaprodotti.scss
Executable file
615
src/rootgen/admin/importaprodotti/importaprodotti.ts
Executable file
615
src/rootgen/admin/importaprodotti/importaprodotti.ts
Executable file
@@ -0,0 +1,615 @@
|
||||
import { CMyPage } from '../../../components/CMyPage/index'
|
||||
|
||||
import { shared_consts } from '@src/common/shared_vuejs'
|
||||
import { tools } from '@src/store/Modules/tools'
|
||||
|
||||
import { defineComponent, ref, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import { useGlobalStore } from '@store/globalStore'
|
||||
import { useQuasar } from 'quasar'
|
||||
import type { IParamsQuery } from 'model'
|
||||
import { toolsext } from '@store/Modules/toolsext'
|
||||
import { StringDecoder } from 'string_decoder'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'importaprodotti',
|
||||
components: { CMyPage },
|
||||
setup(props, { emit }) {
|
||||
const $q = useQuasar()
|
||||
const { t } = useI18n()
|
||||
const userStore = useUserStore()
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
const arrSector = ref(<any[]>[])
|
||||
const arrSectorGood = ref(<any[]>[])
|
||||
const arrSkill = ref(<any[]>[])
|
||||
const arrGood = ref(<any[]>[])
|
||||
|
||||
const importasulserver = ref(false)
|
||||
const skipfirstrow = ref(true)
|
||||
|
||||
const incaricamento = ref(false)
|
||||
const checkAggiornaQta = ref(false)
|
||||
|
||||
const cosafare = ref(shared_consts.Cmd.PRODUCTS_V2)
|
||||
|
||||
const inputfile = ref('')
|
||||
const risultato = ref('')
|
||||
const risraw = ref('')
|
||||
|
||||
const caricaDatiToggle = ref(false)
|
||||
|
||||
const ListaCmd = ref(
|
||||
[
|
||||
{
|
||||
label: 'Importa Prodotti',
|
||||
value: shared_consts.Cmd.PRODUCTS
|
||||
},
|
||||
{
|
||||
label: 'Importa Prodotti V2',
|
||||
value: shared_consts.Cmd.PRODUCTS_V2
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
function caricadati() {
|
||||
|
||||
if (!caricaDatiToggle.value) {
|
||||
arrSector.value = []
|
||||
arrSectorGood.value = []
|
||||
arrSkill.value = []
|
||||
arrGood.value = []
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const sortBy = 'descr'
|
||||
const descending = 1
|
||||
const myobj: any = {}
|
||||
if (descending)
|
||||
myobj[sortBy] = -1
|
||||
else
|
||||
myobj[sortBy] = 1
|
||||
|
||||
const params: IParamsQuery = {
|
||||
newvers: true,
|
||||
table: '',
|
||||
startRow: 0,
|
||||
endRow: 10000,
|
||||
filter: '',
|
||||
filterand: '',
|
||||
filtersearch: '',
|
||||
filtersearch2: '',
|
||||
filtercustom: '',
|
||||
filterextra: '',
|
||||
filterextra2: '',
|
||||
filter_gte: '',
|
||||
sortBy: myobj,
|
||||
descending,
|
||||
userId: '',
|
||||
noaut: false,
|
||||
}
|
||||
|
||||
if (true) {
|
||||
params.table = toolsext.TABSECTORS
|
||||
globalStore.loadTable(params).then((data) => {
|
||||
arrSector.value = data.rows
|
||||
})
|
||||
|
||||
params.table = 'sectorgoods'
|
||||
globalStore.loadTable(params).then((data) => {
|
||||
arrSectorGood.value = data.rows
|
||||
})
|
||||
|
||||
params.table = 'skills'
|
||||
globalStore.loadTable(params).then((data) => {
|
||||
arrSkill.value = data.rows
|
||||
})
|
||||
|
||||
params.table = 'goods'
|
||||
globalStore.loadTable(params).then((data) => {
|
||||
arrGood.value = data.rows
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function created() {
|
||||
|
||||
// se idapp = 18
|
||||
if (tools.getIdApp() === tools.IDAPP_MACRO) {
|
||||
cosafare.value = shared_consts.Cmd.MACRO_CATALOGO_JSON
|
||||
}
|
||||
inputfile.value = ''
|
||||
|
||||
if (caricaDatiToggle.value) {
|
||||
caricadati()
|
||||
}
|
||||
}
|
||||
|
||||
function createSector(cat: string, cmd: number) {
|
||||
let arr = []
|
||||
if (cmd === shared_consts.Cmd.CAT_GOODS_TXT) {
|
||||
arr = arrSectorGood.value
|
||||
} else {
|
||||
arr = arrSector.value
|
||||
}
|
||||
|
||||
const myid = arr.length + 1
|
||||
arr.push({ _id: myid, descr: cat })
|
||||
return myid
|
||||
}
|
||||
|
||||
function findidSector(cat: string, cmd: number) {
|
||||
let arr = []
|
||||
if (cmd === shared_consts.Cmd.CAT_GOODS_TXT) {
|
||||
arr = arrSectorGood.value
|
||||
} else {
|
||||
arr = arrSector.value
|
||||
}
|
||||
|
||||
const rec = arr.find((rec) => rec.descr === cat)
|
||||
if (rec) {
|
||||
return rec._id
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function findidSkill(cat: string, cmd: number) {
|
||||
let arr = []
|
||||
if (cmd === shared_consts.Cmd.CAT_GOODS_TXT) {
|
||||
arr = arrGood.value
|
||||
} else {
|
||||
arr = arrSkill.value
|
||||
}
|
||||
|
||||
const rec = arr.find((rec) => rec.descr === cat)
|
||||
if (rec) {
|
||||
return rec._id
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function createSkill(cat: string, cmd: number) {
|
||||
let arr = []
|
||||
if (cmd === shared_consts.Cmd.CAT_GOODS_TXT) {
|
||||
arr = arrGood.value
|
||||
} else {
|
||||
arr = arrSkill.value
|
||||
}
|
||||
const myid = arr.length + 1
|
||||
arr.push({ _id: myid, descr: cat })
|
||||
return myid
|
||||
}
|
||||
|
||||
|
||||
function importCmdTxt(cmd: number, testo: string) {
|
||||
|
||||
const delim = '\n';
|
||||
const righe = 1;
|
||||
let indrec = 0;
|
||||
let myarr = tools.CSVToArray(testo, delim)
|
||||
|
||||
let sector = ''
|
||||
let skill = ''
|
||||
let sotto_cat = ''
|
||||
let idSector = 0
|
||||
let idSkill = 0
|
||||
|
||||
let strskills = '';
|
||||
let strsubskills = '';
|
||||
let strsectors = '';
|
||||
|
||||
let indrecsub = 1;
|
||||
|
||||
myarr = myarr[0]
|
||||
let arrstr = []
|
||||
|
||||
// debugger;
|
||||
for (let i = 0; i < myarr.length; i = i + righe) {
|
||||
arrstr = myarr[i].split(',')
|
||||
sector = arrstr[0]
|
||||
skill = arrstr[1]
|
||||
// sotto_cat = arrstr[2]
|
||||
// sotto_cat = myarr[i].replace('\'', '\\\'')
|
||||
// sector = myarr[i+2]
|
||||
if (skill)
|
||||
skill = skill.replace('\'', '\\\'')
|
||||
if (sector)
|
||||
sector = sector.replace('\'', '\\\'')
|
||||
|
||||
if (sector) {
|
||||
idSector = findidSector(sector, cmd)
|
||||
if (!idSector) {
|
||||
idSector = createSector(sector, cmd)
|
||||
|
||||
// sectors
|
||||
strsectors += '{ \n'
|
||||
strsectors += ' _id:' + idSector + ','
|
||||
strsectors += ' descr:\'' + sector + '\','
|
||||
strsectors += '}, \n'
|
||||
}
|
||||
|
||||
if (skill !== '') {
|
||||
idSkill = findidSkill(skill, cmd)
|
||||
if (!idSkill) {
|
||||
idSkill = createSkill(skill, cmd)
|
||||
|
||||
// skills
|
||||
strskills += '{ \n'
|
||||
strskills += ' _id:' + idSkill + ','
|
||||
if (cmd === shared_consts.Cmd.CAT_GOODS_TXT) {
|
||||
strskills += ' idSectorGood: [' + idSector + '],'
|
||||
} else if (cmd === shared_consts.Cmd.CAT_SKILL_TXT) {
|
||||
strskills += ' idSector: [' + idSector + '],'
|
||||
}
|
||||
|
||||
strskills += ' descr:\'' + skill + '\','
|
||||
strskills += '}, \n'
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (sotto_cat !== '') {
|
||||
// subskills
|
||||
strsubskills += '{ \n'
|
||||
strsubskills += ' idSkill: ' + idSkill + ','
|
||||
strsubskills += ' descr:\'' + sotto_cat + '\','
|
||||
strsubskills += '}, \n'
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
indrecsub++
|
||||
}
|
||||
|
||||
let ris = 'module.exports = {\n' +
|
||||
' list: [' + strsectors + ']'
|
||||
ris += '<br><br><br><br>'
|
||||
ris += 'module.exports = {\n' +
|
||||
' list: [' + strskills + ']'
|
||||
ris += '<br><br><br><br>'
|
||||
/*ris += 'module.exports = {\n' +
|
||||
' list: [' + strsubskills + ']'
|
||||
|
||||
*/
|
||||
|
||||
return ris
|
||||
|
||||
}
|
||||
|
||||
function importMacroCatalogoJson(cmd: number, testo: string) {
|
||||
return testo
|
||||
}
|
||||
|
||||
function importNoSpazi(cmd: number, testo: string) {
|
||||
|
||||
const delim = '\n';
|
||||
const righe = 3;
|
||||
let indrec = 0;
|
||||
let myarr = tools.CSVToArray(testo, delim)
|
||||
|
||||
let sector = ''
|
||||
let sotto_cat = ''
|
||||
|
||||
myarr = myarr[0]
|
||||
|
||||
let txt = ''
|
||||
|
||||
// debugger;
|
||||
for (let i = 0; i < myarr.length; i = i + righe) {
|
||||
sotto_cat = myarr[i].replace('\'', '\\\'')
|
||||
sector = myarr[i + 2]
|
||||
|
||||
txt += sotto_cat + ',' + sector + '<br>'
|
||||
}
|
||||
|
||||
return txt
|
||||
|
||||
}
|
||||
|
||||
function importCmd(cmd: number, testo: string) {
|
||||
|
||||
let risultato = '(nessuno)'
|
||||
let delim = ','
|
||||
|
||||
if (cmd === shared_consts.Cmd.PROVINCE) {
|
||||
delim = ','
|
||||
} else if ((cmd === shared_consts.Cmd.COMUNI) || (cmd === shared_consts.Cmd.CITIES_SERVER)) {
|
||||
delim = ';'
|
||||
} else if (cmd === shared_consts.Cmd.CAT_SKILL_TXT) {
|
||||
return importCmdTxt(cmd, testo);
|
||||
} else if (cmd === shared_consts.Cmd.CAT_GOODS_TXT) {
|
||||
return importCmdTxt(cmd, testo);
|
||||
} else if (cmd === shared_consts.Cmd.CAT_NO_SPAZI) {
|
||||
return importNoSpazi(cmd, testo);
|
||||
} else if ((cmd === shared_consts.Cmd.MACRO_CATALOGO_JSON || cmd === shared_consts.Cmd.MACRO_RANKING)) {
|
||||
return importMacroCatalogoJson(cmd, testo);
|
||||
} else if (cmd === shared_consts.Cmd.MACRO_DESCRELINKSITOWEB) {
|
||||
|
||||
// console.log('TESTO PRIMA:', testo)
|
||||
const testoJSON = tools.convertXMLStringToJSON(testo)
|
||||
|
||||
const testoJSONtoPrint = JSON.stringify(testoJSON, null, 2)
|
||||
// console.log(testoJSONtoPrint)
|
||||
|
||||
return importMacroCatalogoJson(cmd, testoJSONtoPrint)
|
||||
}
|
||||
|
||||
function addfield(col: number, field: string, rec: any, opt: any) {
|
||||
let risultato = ''
|
||||
try {
|
||||
let valstr = opt.strinput ? opt.strinput : rec[col]
|
||||
|
||||
if (opt.isnumero) {
|
||||
if (valstr === '')
|
||||
valstr = '0';
|
||||
valstr = valstr.replace(',', '.');
|
||||
}
|
||||
if (opt.iseuro) {
|
||||
valstr = tools.convertPriceEurToValue(valstr)
|
||||
}
|
||||
valstr = tools.removeescape_e_acapo(valstr)
|
||||
// valstr = tools.addslashes(valstr)
|
||||
if (!opt.primo)
|
||||
risultato += ', '
|
||||
|
||||
risultato += '"' + field + '":"' + valstr + '"'
|
||||
return risultato;
|
||||
} catch (e) {
|
||||
console.error('err', e);
|
||||
}
|
||||
}
|
||||
|
||||
const myarr = tools.CSVToArray(testo, delim)
|
||||
|
||||
let strris = ''
|
||||
|
||||
let ind = 1
|
||||
let primo = true
|
||||
|
||||
let arrCols: any = []
|
||||
|
||||
if (skipfirstrow.value) {
|
||||
arrCols = myarr[0]
|
||||
}
|
||||
console.log('arrCols', arrCols)
|
||||
|
||||
if (cmd === shared_consts.Cmd.PRODUCTS_V2) {
|
||||
skipfirstrow.value = false
|
||||
} else if ((cmd === shared_consts.Cmd.MACRO_CATALOGO_JSON) || (cmd === shared_consts.Cmd.MACRO_RANKING) || (cmd === shared_consts.Cmd.MACRO_DESCRELINKSITOWEB)) {
|
||||
skipfirstrow.value = false
|
||||
}
|
||||
|
||||
for (const rec of myarr) {
|
||||
|
||||
if (skipfirstrow.value) {
|
||||
if (ind === 1) {
|
||||
ind++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let lab = tools.addslashes(rec[0])
|
||||
let val = tools.addslashes(rec[1])
|
||||
if (cmd === shared_consts.Cmd.PROVINCE) {
|
||||
let reg = tools.addslashes(rec[1])
|
||||
val = tools.addslashes(rec[2])
|
||||
|
||||
strris += '{ \n'
|
||||
strris += ' _id:' + ind + ','
|
||||
strris += ' reg:\'' + reg + '\','
|
||||
strris += ' prov:\'' + val + '\','
|
||||
strris += ' descr:\'' + lab + '\','
|
||||
strris += '}, \n'
|
||||
|
||||
} else if (cmd === shared_consts.Cmd.COMUNI) {
|
||||
strris += '{ \n'
|
||||
strris += ' istat:\'' + tools.addslashes(rec[0]) + '\','
|
||||
strris += ' comune:\'' + tools.addslashes(rec[1]) + '\','
|
||||
strris += ' prov:\'' + tools.addslashes(rec[2]) + '\''
|
||||
} else if (cmd === shared_consts.Cmd.PRODUCTS) {
|
||||
if (!primo) {
|
||||
strris += ', '
|
||||
}
|
||||
|
||||
strris += '{ '
|
||||
let col = 0;
|
||||
strris += addfield(col, 'idapp', rec, { strinput: tools.appid(), primo: true });
|
||||
strris += addfield(col, 'code', rec, {}); col++;
|
||||
strris += addfield(col, 'name', rec, {}); col++;
|
||||
strris += addfield(col, 'price', rec, { iseuro: true }); col++;
|
||||
strris += addfield(col, 'stockQty', rec, { isnumero: true }); col++;
|
||||
col++;
|
||||
strris += addfield(col, 'weight', rec, { isnumero: true }); col++;
|
||||
strris += addfield(col, 'unit', rec, {}); col++;
|
||||
strris += addfield(col, 'link', rec, {}); col++;
|
||||
|
||||
|
||||
strris += addfield(col, 'perc_iva', rec, {}); col++;
|
||||
strris += addfield(col, 'price_acquistato', rec, { isnumero: true, iseuro: true }); col++;
|
||||
strris += addfield(col, 'minBuyQty', rec, { isnumero: true }); col++;
|
||||
strris += addfield(col, 'minStepQty', rec, { isnumero: true }); col++;
|
||||
strris += addfield(col, 'sconto', rec, {}); col++;
|
||||
|
||||
|
||||
strris += addfield(col, 'cat_name', rec, {}); col++;
|
||||
strris += addfield(col, 'subcat_name', rec, {}); col++;
|
||||
strris += addfield(col, 'producer_name', rec, {}); col++;
|
||||
strris += addfield(col, 'provider_name', rec, {}); col++;
|
||||
strris += addfield(col, 'magazzino_name', rec, {}); col++;
|
||||
strris += addfield(col, 'qtyToReachForGas', rec, { isnumero: true }); col++;
|
||||
strris += addfield(col, 'maxbookableGASQty', rec, { isnumero: true }); col++;
|
||||
strris += addfield(col, 'sconto1', rec, {}); col++;
|
||||
strris += addfield(col, 'sconto2', rec, {}); col++;
|
||||
strris += addfield(col, 'gas_name', rec, {}); col++;
|
||||
strris += addfield(col, 'note', rec, {}); col++;
|
||||
strris += '} '
|
||||
|
||||
} else if (cmd === shared_consts.Cmd.PRODUCTS_V2) {
|
||||
if (!primo) {
|
||||
strris += ', '
|
||||
}
|
||||
|
||||
strris += '{ '
|
||||
let col = 0;
|
||||
strris += addfield(col, 'idapp', rec, { strinput: tools.appid(), primo: true });
|
||||
for (const mycol of arrCols) {
|
||||
strris += addfield(col, mycol, rec, {}); col++;
|
||||
}
|
||||
|
||||
strris += '} '
|
||||
|
||||
} else if (cmd === shared_consts.Cmd.INVENTARIO) {
|
||||
if (!primo) {
|
||||
strris += ', '
|
||||
}
|
||||
|
||||
strris += '{ '
|
||||
let col = 0;
|
||||
strris += addfield(col, 'idapp', rec, { strinput: tools.appid(), primo: true });
|
||||
for (const mycol of arrCols) {
|
||||
strris += addfield(col, mycol, rec, {}); col++;
|
||||
}
|
||||
|
||||
strris += '} '
|
||||
|
||||
} else if (cmd === shared_consts.Cmd.CITIES_SERVER) {
|
||||
strris += '{ \n'
|
||||
strris += ' _id :' + ind + ',\n'
|
||||
strris += ' istat :\'' + rec[0] + '\'\n,'
|
||||
strris += ' comune :\'' + tools.addslashes(rec[1]) + '\'\n,'
|
||||
strris += ' prov :\'' + rec[2] + '\'\n,'
|
||||
strris += ' reg :\'' + tools.addslashes(rec[3]) + '\'\n,'
|
||||
strris += ' pref :\'' + tools.addslashes(rec[4]) + '\'\n,'
|
||||
strris += ' cap :\'' + rec[5] + '\'\n,'
|
||||
strris += ' abitanti :\'' + rec[6] + '\'\n,'
|
||||
strris += ' country : \'IT\'\n'
|
||||
strris += '}, \n'
|
||||
}
|
||||
ind += 1
|
||||
primo = false
|
||||
|
||||
}
|
||||
|
||||
if (cmd === shared_consts.Cmd.CITIES_SERVER) {
|
||||
userStore.importToServerCmd($q, t, cmd, null, true)
|
||||
} else if ((cmd === shared_consts.Cmd.PRODUCTS) || (cmd === shared_consts.Cmd.PRODUCTS_V2)) {
|
||||
let options = { aggiornaStockQty: checkAggiornaQta.value }
|
||||
if (importasulserver.value)
|
||||
userStore.importToServerCmd($q, t, cmd, { arrdata: JSON.stringify(strris, null, 2), options }, true)
|
||||
}
|
||||
risultato = strris
|
||||
|
||||
|
||||
return risultato
|
||||
}
|
||||
|
||||
function reset() {
|
||||
risultato.value = ''
|
||||
risraw.value = ''
|
||||
inputfile.value = ''
|
||||
}
|
||||
|
||||
function loadTextFromFile(ev: any) {
|
||||
try {
|
||||
console.log('ev', ev)
|
||||
reset()
|
||||
|
||||
if (ev.target && ev.target.files) {
|
||||
const file = ev.target.files[0]
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = (e: any) => {
|
||||
|
||||
const testo = e.target.result
|
||||
|
||||
risultato.value = importCmd(cosafare.value, testo)
|
||||
}
|
||||
|
||||
if (file)
|
||||
reader.readAsText(file)
|
||||
}
|
||||
} catch (e) {
|
||||
risultato.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
function eseguiCmd() {
|
||||
risultato.value = ''
|
||||
|
||||
userStore.importToServerCmd($q, t, cosafare.value, null)
|
||||
}
|
||||
|
||||
function eseguiCmdProduct() {
|
||||
let options = { aggiornaStockQty: checkAggiornaQta.value }
|
||||
userStore.importToServerCmd($q, t, cosafare.value, { arrdata: risultato.value, options }, true)
|
||||
risultato.value = ''
|
||||
}
|
||||
|
||||
function eseguiCmdInventario() {
|
||||
let options = { aggiornaStockQty: checkAggiornaQta.value }
|
||||
userStore.importToServerCmd($q, t, cosafare.value, { arrdata: risultato.value, options }, true)
|
||||
risultato.value = ''
|
||||
}
|
||||
|
||||
function eseguiCmdCatalogoJson() {
|
||||
let options = { aggiornaStockQty: checkAggiornaQta.value }
|
||||
|
||||
userStore.importToServerCmd($q, t, cosafare.value, { arrdata: risultato.value, options }, true)
|
||||
risultato.value = ''
|
||||
}
|
||||
|
||||
function createProvLink() {
|
||||
let str = ''
|
||||
|
||||
const arr = globalStore.provinces
|
||||
|
||||
let regione = ''
|
||||
let regid = ''
|
||||
|
||||
for (const prov of arr) {
|
||||
if (prov.link_grp) {
|
||||
if (prov.reg !== regid) {
|
||||
const myreg = shared_consts.Regions.find((rec: any) => rec.value === prov.reg)
|
||||
if (myreg) {
|
||||
regid = myreg.value
|
||||
regione = myreg.label
|
||||
str += '<br><div class="text-subtitle1">' + regione + '</div>'
|
||||
}
|
||||
}
|
||||
str += '<a class="prov" href="' + prov.link_grp + '" target="_blank">' + prov.descr + '</a><br>'
|
||||
}
|
||||
}
|
||||
|
||||
risultato.value = str
|
||||
risraw.value = str
|
||||
}
|
||||
|
||||
onMounted(created)
|
||||
|
||||
return {
|
||||
inputfile,
|
||||
shared_consts,
|
||||
loadTextFromFile,
|
||||
risultato,
|
||||
cosafare,
|
||||
ListaCmd,
|
||||
eseguiCmd,
|
||||
caricaDatiToggle,
|
||||
caricadati,
|
||||
createProvLink,
|
||||
risraw,
|
||||
importasulserver,
|
||||
skipfirstrow,
|
||||
eseguiCmdProduct,
|
||||
checkAggiornaQta,
|
||||
eseguiCmdInventario,
|
||||
eseguiCmdCatalogoJson,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
49
src/rootgen/admin/importaprodotti/importaprodotti.vue
Executable file
49
src/rootgen/admin/importaprodotti/importaprodotti.vue
Executable file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<CMyPage
|
||||
img=""
|
||||
title="Importa Prodotti"
|
||||
keywords=""
|
||||
description=""
|
||||
>
|
||||
<div class="q-ma-sm">
|
||||
<q-toggle
|
||||
v-model="skipfirstrow"
|
||||
label="Salta la prima riga"
|
||||
></q-toggle>
|
||||
<q-toggle
|
||||
v-model="checkAggiornaQta"
|
||||
label="Aggiorna Quantità in Magazzino"
|
||||
></q-toggle>
|
||||
<label class="text-reader">
|
||||
<input
|
||||
type="file"
|
||||
@change="loadTextFromFile"
|
||||
/>
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<br />
|
||||
<div class="row justify-center">
|
||||
<q-btn
|
||||
label="Importa Prodotti"
|
||||
@click="eseguiCmdProduct"
|
||||
></q-btn>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div>{{ risraw }}</div>
|
||||
|
||||
<div
|
||||
v-if="risultato"
|
||||
v-html="risultato.substring(0, 1000)"
|
||||
></div>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
</CMyPage>
|
||||
</template>
|
||||
<script lang="ts" src="./importaprodotti.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './importaprodotti.scss';
|
||||
</style>
|
||||
@@ -273,22 +273,6 @@ function getRoutesAd(site: ISites) {
|
||||
},
|
||||
|
||||
*/
|
||||
{
|
||||
active: site.confpages?.showMenuCoins,
|
||||
path: '/admin/ris',
|
||||
order: 60,
|
||||
faIcon: 'fa fa-list-alt',
|
||||
materialIcon: 'fas fa-coins',
|
||||
name: 'otherpages.admin.monete',
|
||||
routes2: routes_ris,
|
||||
inmenu: false,
|
||||
submenu: true,
|
||||
level_parent: 0.5,
|
||||
level_child: 0.5,
|
||||
solotitle: true,
|
||||
onlyAdmin: true,
|
||||
onlyManager: true
|
||||
},
|
||||
/*{
|
||||
active: false,
|
||||
order: 10,
|
||||
@@ -398,22 +382,6 @@ function getRoutesAd(site: ISites) {
|
||||
onlyManager: true,
|
||||
onlyEditor: false
|
||||
},
|
||||
{
|
||||
active: site.confpages && site.confpages?.sendNewsletter,
|
||||
path: '/admin/newsletter',
|
||||
order: 60,
|
||||
faIcon: 'fa fa-list-alt',
|
||||
materialIcon: 'fas fa-users',
|
||||
name: 'otherpages.admin.newsletter',
|
||||
routes2: routes_newsletter,
|
||||
inmenu: false,
|
||||
submenu: true,
|
||||
level_parent: 0.5,
|
||||
level_child: 0.5,
|
||||
solotitle: true,
|
||||
onlyAdmin: true,
|
||||
onlyManager: true
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
order: 35,
|
||||
@@ -471,6 +439,38 @@ function getRoutesAd(site: ISites) {
|
||||
onlyAdmin: true,
|
||||
onlyManager: true
|
||||
},
|
||||
{
|
||||
active: site.confpages?.showMenuCoins,
|
||||
path: '/admin/ris',
|
||||
order: 60,
|
||||
faIcon: 'fa fa-list-alt',
|
||||
materialIcon: 'fas fa-coins',
|
||||
name: 'otherpages.admin.monete',
|
||||
routes2: routes_ris,
|
||||
inmenu: false,
|
||||
submenu: true,
|
||||
level_parent: 0.5,
|
||||
level_child: 0.5,
|
||||
solotitle: true,
|
||||
onlyAdmin: true,
|
||||
onlyManager: true
|
||||
},
|
||||
{
|
||||
active: site.confpages && site.confpages?.sendNewsletter,
|
||||
path: '/admin/newsletter',
|
||||
order: 60,
|
||||
faIcon: 'fa fa-list-alt',
|
||||
materialIcon: 'fas fa-users',
|
||||
name: 'otherpages.admin.newsletter',
|
||||
routes2: routes_newsletter,
|
||||
inmenu: false,
|
||||
submenu: true,
|
||||
level_parent: 0.5,
|
||||
level_child: 0.5,
|
||||
solotitle: true,
|
||||
onlyAdmin: true,
|
||||
onlyManager: true
|
||||
},
|
||||
]
|
||||
|
||||
const menuAdmins = [
|
||||
|
||||
@@ -70,6 +70,19 @@ function getRoutesEcomm(site: ISites) {
|
||||
onlyManager: true,
|
||||
onlyEditor: true
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
order: 1040,
|
||||
path: '/products/importa',
|
||||
materialIcon: 'fas fa-upload',
|
||||
name: 'otherpages.manage.importaprodotti',
|
||||
component: () => import('@src/rootgen/admin/importaprodotti/importaprodotti.vue'),
|
||||
level_parent: 0.0,
|
||||
level_child: 0.5,
|
||||
inmenu: true,
|
||||
submenu: true,
|
||||
onlyAdmin: true
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
order: 30,
|
||||
|
||||
@@ -194,6 +194,7 @@ const msg_it = {
|
||||
nessuno: 'Nessuno',
|
||||
sendpushnotif: 'Invia Messaggi',
|
||||
importfile: 'Importa File',
|
||||
importaprodotti: 'Importa Prodotti',
|
||||
convertPDF: 'Converti PDF',
|
||||
},
|
||||
messages: {
|
||||
@@ -316,7 +317,12 @@ const msg_it = {
|
||||
comp: {
|
||||
Conta: 'Conta',
|
||||
},
|
||||
pages: {
|
||||
onlyif_logged: 'solo se Registrati',
|
||||
only_admin: 'visibile solo agli Admin',
|
||||
},
|
||||
db: {
|
||||
deletedpage: 'Pagina Cancellata',
|
||||
recupdated: 'Record Aggiornato',
|
||||
records_imported: '{num} Record Importati',
|
||||
records_updated: '{num} Record Aggiornati',
|
||||
|
||||
@@ -64,6 +64,7 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
state: (): IGlobalState => ({
|
||||
showHeader: true,
|
||||
inStampa: false,
|
||||
updateMenu: false,
|
||||
finishLoading: false,
|
||||
conta: 0,
|
||||
wasAlreadySubscribed: false,
|
||||
@@ -791,7 +792,7 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
|
||||
addDynamicPages($router: Router | null) {
|
||||
// console.log('this.mypage', this.mypage)
|
||||
/// console.log('addDynamicPages.........')
|
||||
// console.log('addDynamicPages.........')
|
||||
const arrpagesroute: IListRoutes[] = [];
|
||||
|
||||
for (const page of this.mypage) {
|
||||
@@ -886,10 +887,6 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
// Sort array
|
||||
static_data.routes = static_data.routes.sort((a, myb) => a.order - myb.order);
|
||||
|
||||
// console.log('static_data.routes', static_data.routes)
|
||||
|
||||
// console.log('$router', $router)
|
||||
|
||||
if ($router) {
|
||||
static_data.routes.forEach((route: any) => {
|
||||
if (!$router.hasRoute(route.name) && !route.noroute) {
|
||||
@@ -933,6 +930,7 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.updateMenu = true;
|
||||
},
|
||||
|
||||
async aggiornaMenu(router: Router) {
|
||||
@@ -1446,7 +1444,7 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
// console.log('mypage', mypage)
|
||||
|
||||
// Controlla se l'ho già caricato
|
||||
if ((!!mypage && (!!mypage.content || mypage.loadFirst || mypage.loaded)) && !forza) {
|
||||
if (!!mypage && (!!mypage.content || mypage.loadFirst || mypage.loaded) && !forza) {
|
||||
return mypage;
|
||||
}
|
||||
|
||||
@@ -1478,8 +1476,8 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
|
||||
return Api.SendReq('/savepage', 'POST', { page })
|
||||
.then((res) => {
|
||||
if (res && res.data && res.data.ris) {
|
||||
return res.data.ris;
|
||||
if (res && res.data && res.data.mypage) {
|
||||
return res.data.mypage;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -1713,6 +1711,25 @@ export const useGlobalStore = defineStore('GlobalStore', {
|
||||
});
|
||||
},
|
||||
|
||||
async deletePage($q: any, idpage: string) {
|
||||
console.log('deletePage', idpage);
|
||||
|
||||
return Api.SendReq('/api/mypage/' + idpage, 'DELETE', null)
|
||||
.then((res) => {
|
||||
if (res.status === 200) {
|
||||
if (res.data.code === serv_constants.RIS_CODE_OK) {
|
||||
tools.showPositiveNotif($q, t('db.deletedpage'));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
async DeleteRec({ table, id }: { table: string; id: string }) {
|
||||
console.log('DeleteRec', table, id);
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
<div class="text-center q-py-sm prod_trov">
|
||||
{{
|
||||
t('ecomm.prodotti_trovati', {
|
||||
qta: arrProducts.length,
|
||||
qta: getArrProducts.length,
|
||||
qtatot:
|
||||
productStore.getNumProdTot() > 0
|
||||
? ` ${t('ecomm.su')} ${productStore.getNumProdTot()}`
|
||||
|
||||
Reference in New Issue
Block a user