FormBuilderTS
This commit is contained in:
parent
dd2af7f810
commit
5ac5e328e2
30
src/new/tests/Plugins/System/PSC/XmlCalc/Api/DesignTest.php
Normal file
30
src/new/tests/Plugins/System/PSC/XmlCalc/Api/DesignTest.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\System\PSC\XmlCalc\Api;
|
||||
|
||||
use PSC\Shop\ContactBundle\Repository\ContactRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Tests\RefreshDatabaseTrait;
|
||||
|
||||
class DesignTest extends WebTestCase
|
||||
{
|
||||
use RefreshDatabaseTrait;
|
||||
|
||||
public function testDesignApi(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$client->jsonRequest(
|
||||
'POST',
|
||||
'/api/plugin/system/psc/xmlcalc/product/design',
|
||||
[
|
||||
'product' => '01938686-0e4d-7da9-bae3-b2e1b1681f9f',
|
||||
'jsonProduct' => '[{"uuid":"df2df718-b28e-482d-bf0c-67d246f05d32","name":"Test Artikel","options":[{"id":"auflage","name":"Auflage","default":"100","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_umschlag","name":"Seiten Umschlag","default":"2","dependencys":[],"placeHolder":"Placeholder","required":false,"type":2},{"id":"seiten_anzahl_inhalt","name":"Seiten Anzahl Inhalt","default":"10","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.12","price":0,"value":"1-10","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.24","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.23","price":0,"value":"3-","dependencys":[]}]}]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*0.11","price":0,"value":"11-","dependencys":[{"relation":"seiten_umschlag","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.21","price":0,"value":"1-2","dependencys":[]},{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vseiten_umschlag$V*0.20","price":0,"value":"3-","dependencys":[]}]}]}]}],"placeHolder":"Placeholder","required":true,"type":2},{"id":"farbigkeit","name":"Farbigkeit","default":"10","dependencys":[],"type":3,"options":[{"id":"10","name":"1\/0 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"1-101","dependencys":[]}]}]},{"id":"11","name":"1\/1 farbig","dependencys":[]},{"id":"20","name":"2\/0 farbig","dependencys":[]},{"id":"21","name":"2\/1 farbig","dependencys":[]},{"id":"22","name":"2\/2 farbig","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"","price":0,"value":"11-50","dependencys":[]}]}]}],"mode":"normal"},{"id":"calc","name":"calc","dependencys":[{"relation":"auflage","formula":"","borders":[{"calcValue":"","calcValue1":"","calcValue2":"","calcValue3":"","calcValue4":"","calcValue5":"","calcValue6":"","calcValue7":"","calcValue8":"","calcValue9":"","calcValue10":"","flatRate":"","formula":"$Vauflage$V*$Vseiten_anzahl_inhalt$V","price":0,"value":"1-","dependencys":[]}]}],"type":1}]}]',
|
||||
],
|
||||
[],
|
||||
);
|
||||
$this->assertResponseIsSuccessful();
|
||||
|
||||
self::assertJson($client->getResponse()->getContent());
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,8 @@
|
||||
"vue": "^3.5.13",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-draggable-plus": "^0.6.0",
|
||||
"vue-i18n": "^11.1.9",
|
||||
"xml-beautify": "^1.2.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.1",
|
||||
@ -176,6 +178,12 @@
|
||||
|
||||
"@internationalized/number": ["@internationalized/number@3.6.3", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-p+Zh1sb6EfrfVaS86jlHGQ9HA66fJhV9x5LiE5vCbZtXEHAuhcmUZUdZ4WrFpUBfNalr2OkAJI5AcKEQF+Lebw=="],
|
||||
|
||||
"@intlify/core-base": ["@intlify/core-base@11.1.9", "", { "dependencies": { "@intlify/message-compiler": "11.1.9", "@intlify/shared": "11.1.9" } }, "sha512-Lrdi4wp3XnGhWmB/mMD/XtfGUw1Jt+PGpZI/M63X1ZqhTDjNHRVCs/i8vv8U1cwaj1A9fb0bkCQHLSL0SK+pIQ=="],
|
||||
|
||||
"@intlify/message-compiler": ["@intlify/message-compiler@11.1.9", "", { "dependencies": { "@intlify/shared": "11.1.9", "source-map-js": "^1.0.2" } }, "sha512-84SNs3Ikjg0rD1bOuchzb3iK1vR2/8nxrkyccIl5DjFTeMzE/Fxv6X+A7RN5ZXjEWelc1p5D4kHA6HEOhlKL5Q=="],
|
||||
|
||||
"@intlify/shared": ["@intlify/shared@11.1.9", "", {}, "sha512-H/83xgU1l8ox+qG305p6ucmoy93qyjIPnvxGWRA7YdOoHe1tIiW9IlEu4lTdsOR7cfP1ecrwyflQSqXdXBacXA=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||
@ -610,12 +618,16 @@
|
||||
|
||||
"vue-draggable-plus": ["vue-draggable-plus@0.6.0", "", { "dependencies": { "@types/sortablejs": "^1.15.8" } }, "sha512-G5TSfHrt9tX9EjdG49InoFJbt2NYk0h3kgjgKxkFWr3ulIUays0oFObr5KZ8qzD4+QnhtALiRwIqY6qul4egqw=="],
|
||||
|
||||
"vue-i18n": ["vue-i18n@11.1.9", "", { "dependencies": { "@intlify/core-base": "11.1.9", "@intlify/shared": "11.1.9", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-N9ZTsXdRmX38AwS9F6Rh93RtPkvZTkSy/zNv63FTIwZCUbLwwrpqlKz9YQuzFLdlvRdZTnWAUE5jMxr8exdl7g=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@2.2.10", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.10" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-jWZ1xSaNbabEV3whpIDMbjVSVawjAyW+x1n3JeGQo7S0uv2n9F/JMgWW90tGWNFRKya4YwKMZgCtr0vRAM7DeQ=="],
|
||||
|
||||
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"xml-beautify": ["xml-beautify@1.2.3", "", {}, "sha512-VsYpkqoVawIP84pi00XukPsgQHqOhgrpwTHlXqqRMAgYZ1u+Yw3KHIUhO1Igf19d5CQ5h6ExJT1hFCJRLmzADg=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
|
||||
@ -642,6 +654,8 @@
|
||||
|
||||
"reka-ui/@vueuse/shared": ["@vueuse/shared@12.8.2", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w=="],
|
||||
|
||||
"vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"reka-ui/@vueuse/core/@vueuse/metadata": ["@vueuse/metadata@12.8.2", "", {}, "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A=="],
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,9 @@
|
||||
"uuid": "^11.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-draggable-plus": "^0.6.0"
|
||||
"vue-draggable-plus": "^0.6.0",
|
||||
"vue-i18n": "^11.1.9",
|
||||
"xml-beautify": "^1.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.1",
|
||||
|
||||
@ -8,7 +8,8 @@ onMounted(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const uuid = params.get('uuid');
|
||||
if (uuid) {
|
||||
store.loadFromApi(uuid);
|
||||
store.loadConfigFromProductApi(uuid);
|
||||
store.loadFormulaAnalyserDataFromApi(uuid);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -7,8 +7,7 @@ import {
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs'
|
||||
|
||||
import { Library } from '../components/app/library'
|
||||
import { Debug } from '../components/app/debug'
|
||||
import { ElementProperties } from '../components/app/elementproperties'
|
||||
import { ElementProperties, SpecialElementProperties } from '../components/app/elementproperties'
|
||||
import { ElementDependency } from '../components/app/elementdependency'
|
||||
import { Main } from '../components/app/main'
|
||||
import FormulaVisualizer from './app/FormulaVisualizer.vue'
|
||||
@ -26,7 +25,6 @@ import XmlView from './app/XmlView.vue'
|
||||
<ResizablePanel id="" :default-size="15">
|
||||
<div class="flex flex-col gap-2 h-full">
|
||||
<Library />
|
||||
<Debug />
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle id="" with-handle />
|
||||
@ -35,16 +33,16 @@ import XmlView from './app/XmlView.vue'
|
||||
<div class="flex justify-center">
|
||||
<TabsList>
|
||||
<TabsTrigger value="designer">
|
||||
Designer
|
||||
{{ $t('designer') }}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="preview">
|
||||
Kalkulations Analyse
|
||||
{{ $t('preview') }}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="xml">
|
||||
XML Ansicht
|
||||
{{ $t('xml_view') }}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="json">
|
||||
JSON Ansicht
|
||||
{{ $t('json_view') }}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
@ -66,6 +64,7 @@ import XmlView from './app/XmlView.vue'
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
<ElementProperties />
|
||||
<SpecialElementProperties />
|
||||
<ElementDependency />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,22 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, provide } from 'vue';
|
||||
import { ref, onMounted, provide, computed } from 'vue';
|
||||
import NodeRenderer from './NodeRenderer.vue';
|
||||
import { loadPriceFromApi } from '../../lib/api';
|
||||
import { useElementStore } from '../../stores/Items';
|
||||
|
||||
// Debounce function to limit the rate at which a function gets called.
|
||||
function debounce<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
return (...args: Parameters<T>) => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
timeoutId = setTimeout(() => {
|
||||
func(...args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
|
||||
interface Node {
|
||||
name: string;
|
||||
unParsed?: string;
|
||||
@ -25,50 +11,12 @@ interface Node {
|
||||
parts: Node[];
|
||||
}
|
||||
|
||||
const parsedData = ref<Node[] | null>(null);
|
||||
const expandedNodes = ref(new Set<string>());
|
||||
const error = ref('');
|
||||
const isLoading = ref(false);
|
||||
const store = useElementStore();
|
||||
|
||||
const loadFormulaData = async () => {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
parsedData.value = null;
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const uuid = urlParams.get('uuid');
|
||||
|
||||
if (!uuid) {
|
||||
error.value = 'Keine UUID in der URL gefunden.';
|
||||
isLoading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await loadPriceFromApi(uuid);
|
||||
if (response && response.debug && response.debug.graphJson) {
|
||||
const graphData = JSON.parse(response.debug.graphJson);
|
||||
parsedData.value = graphData;
|
||||
} else {
|
||||
throw new Error('Ungültiges oder leeres Antwortformat von der API.');
|
||||
}
|
||||
} catch (e: any) {
|
||||
error.value = `Fehler beim Laden der Formeldaten: ${e.message}`;
|
||||
console.error(e);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const debouncedLoadFormulaData = debounce(loadFormulaData, 500);
|
||||
|
||||
onMounted(() => {
|
||||
loadFormulaData();
|
||||
store.$subscribe(() => {
|
||||
debouncedLoadFormulaData();
|
||||
});
|
||||
});
|
||||
const parsedData = computed(() => store.getFormulaData);
|
||||
const error = computed(() => store.getFormulaError);
|
||||
const isLoading = computed(() => store.isFormulaLoading);
|
||||
|
||||
const toggleNode = (nodeId: string) => {
|
||||
const newExpanded = new Set(expandedNodes.value);
|
||||
|
||||
@ -10,11 +10,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
import { xml } from '@codemirror/lang-xml';
|
||||
import { useElementStore } from '../../stores/Items';
|
||||
import XmlBeautify from 'xml-beautify'
|
||||
|
||||
const xmlString = ref('<root>\n <!-- XML Data Source Not Yet Implemented -->\n</root>');
|
||||
const store = useElementStore();
|
||||
|
||||
const xmlString = computed(() => new XmlBeautify().beautify(store.xml,
|
||||
{
|
||||
indent: " ", //indent pattern like white spaces
|
||||
useSelfClosingElement: true //true:use self-closing element when empty element.
|
||||
}));
|
||||
|
||||
const extensions = [xml()];
|
||||
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { useElementStore } from '../../../stores/Items';
|
||||
import { Textarea } from '../../../components/ui/textarea'
|
||||
import { Button } from '../../../components/ui/button'
|
||||
const store = useElementStore()
|
||||
|
||||
function loadJson() {
|
||||
store.loadJSON()
|
||||
}
|
||||
|
||||
function restoreJson() {
|
||||
store.parseJSON()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-1">
|
||||
<Textarea v-model="store.json" class="h-50"/>
|
||||
<div class="flex flex-row mt-2 gap-1">
|
||||
<Button class="grow" v-on:click="loadJson()">Load Json</Button>
|
||||
<Button class="grow" v-on:click="restoreJson()">Restore Json</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1 +0,0 @@
|
||||
export { default as Debug } from './Debug.vue'
|
||||
@ -0,0 +1,20 @@
|
||||
<script lang="ts" setup>
|
||||
import { useElementStore } from '../../../stores/Items'
|
||||
import SelectSpecialProperties from '../properties/SelectSpecial.vue'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
|
||||
let emit = defineEmits(['update:modelValue']);
|
||||
const store = useElementStore()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="">
|
||||
<SelectSpecialProperties
|
||||
v-model="store.getActiveItem as SelectElement"
|
||||
>
|
||||
</SelectSpecialProperties>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@ -1 +1,2 @@
|
||||
export { default as ElementProperties } from './ElementProperties.vue'
|
||||
export { default as SpecialElementProperties } from './SpecialProperties.vue'
|
||||
|
||||
@ -19,7 +19,7 @@ const theModel = computed<InputElement>({
|
||||
|
||||
<template>
|
||||
<div class="flex gap-2 flex-row items-center">
|
||||
<label class="w-60 flex-inital">{{theModel.name}} {{theModel.default}}</label>
|
||||
<label class="w-60 flex-inital">{{theModel.name}}</label>
|
||||
<Input v-model:placeholder="theModel.placeHolder" :modelValue="theModel.default" v-model:name="theModel.name" v-model:id="theModel.id" v-model:required="theModel.required"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -4,7 +4,9 @@ import { Image, SquareParking, SquareDot, SquareMenu, SquarePen, SquareChevronDo
|
||||
import { Switch } from '../../../components/ui/switch'
|
||||
import { Label } from '../../../components/ui/label'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const store = useElementStore()
|
||||
|
||||
let previewMode = ref(false)
|
||||
@ -30,44 +32,50 @@ watch(previewMode, (newPreviewMode) => {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col p-3 gap-3 overflow-auto">
|
||||
<div class="flex items-center space-x-2">
|
||||
<select v-model="locale">
|
||||
<option value="de">DE</option>
|
||||
<option value="en">EN</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Switch id="preview-mode" v-model="previewMode" />
|
||||
<Label for="preview-mode">Preview Mode</Label>
|
||||
<Label for="preview-mode">{{ $t('preview_mode') }}</Label>
|
||||
</div>
|
||||
<div id="headline" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '6')" @dragenter.prevent @dragover.prevent>
|
||||
<SquareDot />
|
||||
<span>Headline</span>
|
||||
<span>{{ $t('headline') }}</span>
|
||||
</div>
|
||||
<div id="text" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '4')" @dragenter.prevent @dragover.prevent>
|
||||
<SquareParking />
|
||||
<span>Text</span>
|
||||
<span>{{ $t('text') }}</span>
|
||||
</div>
|
||||
<div id="media" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '9')" @dragenter.prevent @dragover.prevent>
|
||||
<Image />
|
||||
<span>Media</span>
|
||||
<span>{{ $t('media') }}</span>
|
||||
</div>
|
||||
<div id="textarea" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '5')" @dragenter.prevent @dragover.prevent>
|
||||
<SquareMenu />
|
||||
<span>Textarea</span>
|
||||
<span>{{ $t('textarea') }}</span>
|
||||
</div>
|
||||
<div id="input" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '2')" @dragenter.prevent @dragover.prevent>
|
||||
<SquarePen />
|
||||
<span>Input</span>
|
||||
<span>{{ $t('input') }}</span>
|
||||
</div>
|
||||
<div id="select" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '3')" @dragenter.prevent @dragover.prevent>
|
||||
<SquareChevronDown />
|
||||
<span>Select</span>
|
||||
<span>{{ $t('select') }}</span>
|
||||
</div>
|
||||
<div id="hidden" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '1')" @dragenter.prevent @dragover.prevent>
|
||||
<SquareDashed />
|
||||
<span>Hidden</span>
|
||||
<span>{{ $t('hidden') }}</span>
|
||||
</div>
|
||||
<div id="row" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '7')" @dragenter.prevent @dragover.prevent>
|
||||
<SquareDashed />
|
||||
<span>Row</span>
|
||||
<span>{{ $t('row') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
@ -25,13 +25,13 @@ const theModel = computed({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>Default</label>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Input v-model="theModel!.default"/>
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
<label>Variant</label>
|
||||
<label>{{ $t('variant') }}</label>
|
||||
<Select v-model="theModel!.variant">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@ -39,22 +39,22 @@ const theModel = computed({
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="1">
|
||||
Headline 1
|
||||
{{ $t('headline1') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="2">
|
||||
Headline 2
|
||||
{{ $t('headline2') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="3">
|
||||
Headline 3
|
||||
{{ $t('headline3') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="4">
|
||||
Headline 4
|
||||
{{ $t('headline4') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="5">
|
||||
Headline 5
|
||||
{{ $t('headline5') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="6">
|
||||
Headline 6
|
||||
{{ $t('headline6') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
|
||||
@ -17,10 +17,10 @@ const theModel = computed({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>Default</label>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Input v-model="theModel!.default"/>
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
</template>
|
||||
|
||||
@ -18,18 +18,22 @@ const theModel = computed<InputElement>({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>Placeholder</label>
|
||||
<Input v-model="theModel!.placeHolder"/>
|
||||
<label>Default</label>
|
||||
<Input v-model="theModel!.default"/>
|
||||
<label>Name</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
<Checkbox v-model="theModel!.required"/>
|
||||
<label class="form-check-label" for="flexSwitchCheckDefault">Required</label>
|
||||
<label>Min</label>
|
||||
<Input v-model="theModel!.minValue"/>
|
||||
<label>Max</label>
|
||||
<Input v-model="theModel!.maxValue"/>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>{{ $t('placeholder') }}</label>
|
||||
<Input v-model="theModel!.placeHolder"/>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Input v-model="theModel!.default"/>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
<Checkbox v-model="theModel!.required"/>
|
||||
<label class="form-check-label" for="flexSwitchCheckDefault">{{ $t('required') }}</label>
|
||||
<label>{{ $t('min') }}</label>
|
||||
<Input v-model="theModel!.minValue"/>
|
||||
<label>{{ $t('max') }}</label>
|
||||
<Input v-model="theModel!.maxValue"/>
|
||||
<label>{{ $t('min_calc') }}</label>
|
||||
<Input v-model="theModel!.minCalc"/>
|
||||
<label>{{ $t('max_calc') }}</label>
|
||||
<Input v-model="theModel!.maxCalc"/>
|
||||
</template>
|
||||
|
||||
@ -20,10 +20,10 @@ const theModel = computed({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>Default</label>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Input v-model="theModel!.default"/>
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
</template>
|
||||
|
||||
@ -26,11 +26,11 @@ const theModel = computed<Option>({
|
||||
|
||||
<template>
|
||||
<div class="flex flex-row gap-1">
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel.id" />
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel.name"/>
|
||||
<Button v-on:click="addDependency(theModel)">Add Dependency</Button>
|
||||
<Button v-on:click="addDependency(theModel)">{{ $t('add_dependency') }}</Button>
|
||||
</div>
|
||||
<Dependency :dependencys="theModel.dependencys" />
|
||||
</template>
|
||||
|
||||
@ -24,5 +24,5 @@ function addColumn(row: Row) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button v-on:click="addColumn(theModel!)">add Column</Button>
|
||||
<Button v-on:click="addColumn(theModel!)">{{ $t('add_column') }}</Button>
|
||||
</template>
|
||||
|
||||
@ -23,31 +23,29 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '../../../components/ui/dialog'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: SelectElement
|
||||
}>()
|
||||
|
||||
let emit = defineEmits(['update:modelValue']);
|
||||
let emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const theModel = computed<SelectElement>({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => emit('update:modelValue', value),
|
||||
});
|
||||
});
|
||||
|
||||
function addOption(obj: SelectElement) {
|
||||
obj.addOption(new Option(String(obj.options.length + 1)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>Default</label>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Input v-model="theModel!.default"/>
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
<label>Mode</label>
|
||||
<label>{{ $t('mode') }}</label>
|
||||
<Select v-model="theModel!.mode">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@ -55,42 +53,17 @@ function addOption(obj: SelectElement) {
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="normal">
|
||||
Normal
|
||||
{{ $t('normal') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="paperdb">
|
||||
PaperDB
|
||||
{{ $t('paperdb') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="colordb">
|
||||
ColorDB
|
||||
{{ $t('colordb') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<label>Container</label>
|
||||
<label>{{ $t('container') }}</label>
|
||||
<Input v-model="theModel!.container"/>
|
||||
<Dialog >
|
||||
<DialogTrigger>
|
||||
<Button class="mt-2">Edit Options</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="min-w-full grid-rows-[auto_minmax(0,1fr)_auto] p-4 max-h-[90dvh]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit Options</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Button v-on:click="addOption(theModel)">Add Option</Button>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="w-full grid overflow-y-auto px-6">
|
||||
<div class="d-flex flex-wrap p-2 relative" v-for="opt in theModel.options" :key="opt.uuid">
|
||||
<OptionElement :option="opt"/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose as-child>
|
||||
<Button type="button" variant="secondary">
|
||||
Close
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
<script lang="ts" setup>
|
||||
import { useElementStore } from '../../../stores/Items'
|
||||
import SelectElement from '../../../model/SelectElement';
|
||||
import Option from '../../../model/select/Option';
|
||||
import { computed } from 'vue';
|
||||
import { Input } from '../../../components/ui/input'
|
||||
import { Button } from '../../../components/ui/button'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '../../../components/ui/select'
|
||||
import OptionElement from './OptionElement.vue'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogClose,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '../../../components/ui/dialog'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: SelectElement
|
||||
}>()
|
||||
|
||||
let emit = defineEmits(['update:modelValue'])
|
||||
|
||||
let openModal = ref(false)
|
||||
|
||||
const theModel = computed<SelectElement>({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
function addOption(obj: SelectElement) {
|
||||
obj.addOption(new Option(String(obj.options.length + 1)));
|
||||
}
|
||||
const store = useElementStore()
|
||||
|
||||
store.$subscribe((mutation, state) => {
|
||||
if(state.showOptions) {
|
||||
openModal.value = true
|
||||
}
|
||||
}, true)
|
||||
|
||||
watch(openModal, (newOpenModal) => {
|
||||
if(newOpenModal === false) {
|
||||
store.setShowOptions(false)
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-if="store.getActiveItem.type === 3" v-model:open="openModal">
|
||||
<DialogTrigger>
|
||||
<Button class="mt-2">{{ $t('edit_options') }}</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="min-w-full grid-rows-[auto_minmax(0,1fr)_auto] p-4 max-h-[90dvh]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ $t('edit_options') }}</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Button v-on:click="addOption(theModel)">{{ $t('add_option') }}</Button>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="w-full grid overflow-y-auto px-6">
|
||||
<div class="d-flex flex-wrap p-2 relative" v-for="opt in theModel.options" :key="opt.uuid">
|
||||
<OptionElement :option="opt"/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose as-child>
|
||||
<Button type="button" variant="secondary">
|
||||
{{ $t('close') }}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
@ -18,10 +18,10 @@ const theModel = computed<TextElement>({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel!.id" />
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel!.name"/>
|
||||
<label>Default</label>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Textarea v-model="theModel!.default"/>
|
||||
</template>
|
||||
|
||||
@ -19,10 +19,10 @@ const theModel = computed<TextareaElement>({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label>ID</label>
|
||||
<label>{{ $t('id') }}</label>
|
||||
<Input v-model="theModel.id" />
|
||||
<label>Name</label>
|
||||
<label>{{ $t('name') }}</label>
|
||||
<Input v-model="theModel.name"/>
|
||||
<label>Default</label>
|
||||
<label>{{ $t('default') }}</label>
|
||||
<Textarea v-model="theModel.default"/>
|
||||
</template>
|
||||
|
||||
@ -18,7 +18,7 @@ import Row from '../../../model/Row'
|
||||
import SelectElement from '../../../model/SelectElement'
|
||||
import { useElementStore } from '../../../stores/Items'
|
||||
import Parser from '../../../lib/parser'
|
||||
import { Settings, Trash, CirclePlus, Waypoints } from 'lucide-vue-next';
|
||||
import { Settings, Trash, CirclePlus, List, Option } from 'lucide-vue-next';
|
||||
import { ref } from 'vue'
|
||||
|
||||
interface Props {
|
||||
@ -86,12 +86,16 @@ const deleteItem = (item: BaseElement) => {
|
||||
}
|
||||
|
||||
const editElementProperties = (item: BaseElement) => {
|
||||
store.setShowProperties(true)
|
||||
store.setActiveItem(item)
|
||||
store.setShowProperties(true)
|
||||
}
|
||||
const editOptions = (item: BaseElement) => {
|
||||
store.setActiveItem(item)
|
||||
store.setShowOptions(true)
|
||||
}
|
||||
const editElementDependency = (item: BaseElement) => {
|
||||
store.setShowDependency(true)
|
||||
store.setActiveItem(item)
|
||||
store.setShowDependency(true)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -106,7 +110,7 @@ const editElementDependency = (item: BaseElement) => {
|
||||
<span class="absolute px-3 font-medium text-gray-900 -translate-x-1/2 bg-white left-1/2 dark:text-white dark:bg-gray-900 pointer-events-none"><CirclePlus :class="{ 'text-orange-500': dragUuid == item.uuid }" class="transition duration-200 pointer-events-none" /></span>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="{ 'border-white' : item.dependencys.length == 0, 'border-blue-500': item.dependencys.length > 0 }" @dragstart="startDrag($event, item.uuid)" draggable="true" class="element w-full flex flex-row border-l-2 hover:border-orange-500 pl-2 transition duration-500 min-h-5" v-bind:class="{ ' bg-slate-50': item.isFocused === true }">
|
||||
<div :class="{ 'border-white' : !item.hasDependencys(), 'border-blue-500': item.hasDependencys() }" @dragstart="startDrag($event, item.uuid)" draggable="true" class="element w-full flex flex-row border-l-2 hover:border-orange-500 pl-2 transition duration-500 min-h-5" v-bind:class="{ ' bg-slate-50': item.isFocused === true }">
|
||||
<div class="grow content-center items-center">
|
||||
<InputElementForm
|
||||
v-if="item.type === 2"
|
||||
@ -142,13 +146,16 @@ const editElementDependency = (item: BaseElement) => {
|
||||
/>
|
||||
</div>
|
||||
<div class="buttons absolute rounded-sm invisible right-0 bg-slate-100/70 flex flex-row gap-2" v-if="!isPreview">
|
||||
<div v-on:click="editElementDependency(item)" class="m-2 cursor-pointer">
|
||||
<Waypoints />
|
||||
<div v-on:click="editElementDependency(item)" :title="$t('dependencies')" class="m-2 cursor-pointer">
|
||||
<Option />
|
||||
</div>
|
||||
<div v-on:click="editElementProperties(item)" class="m-2 cursor-pointer">
|
||||
<div v-if="item.type === 3" v-on:click="editOptions(item)" :title="$t('options')" class="m-2 cursor-pointer">
|
||||
<List />
|
||||
</div>
|
||||
<div v-on:click="editElementProperties(item)" :title="$t('settings')" class="m-2 cursor-pointer">
|
||||
<Settings />
|
||||
</div>
|
||||
<div v-on:click="deleteItem(item)" class="text-red-500 m-2 cursor-pointer">
|
||||
<div v-on:click="deleteItem(item)" class="text-red-500 m-2 cursor-pointer">
|
||||
<Trash />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
{
|
||||
"designer": "Designer",
|
||||
"preview": "Kalkulations Analyse",
|
||||
"xml_view": "XML Ansicht",
|
||||
"json_view": "JSON Ansicht",
|
||||
"preview_mode": "Vorschau-Modus",
|
||||
"headline": "Überschrift",
|
||||
"text": "Text",
|
||||
"media": "Medien",
|
||||
"textarea": "Textbereich",
|
||||
"input": "Eingabefeld",
|
||||
"select": "Auswahl",
|
||||
"hidden": "Versteckt",
|
||||
"row": "Zeile",
|
||||
"id": "ID",
|
||||
"default": "Standard",
|
||||
"name": "Name",
|
||||
"variant": "Variante",
|
||||
"headline1": "Überschrift 1",
|
||||
"headline2": "Überschrift 2",
|
||||
"headline3": "Überschrift 3",
|
||||
"headline4": "Überschrift 4",
|
||||
"headline5": "Überschrift 5",
|
||||
"headline6": "Überschrift 6",
|
||||
"placeholder": "Platzhalter",
|
||||
"required": "Erforderlich",
|
||||
"min": "Min",
|
||||
"max": "Max",
|
||||
"min_calc": "Min Calc",
|
||||
"max_calc": "Max Calc",
|
||||
"add_dependency": "Abhängigkeit hinzufügen",
|
||||
"add_column": "Spalte hinzufügen",
|
||||
"mode": "Modus",
|
||||
"normal": "Normal",
|
||||
"paperdb": "PapierDB",
|
||||
"colordb": "FarbDB",
|
||||
"container": "Container",
|
||||
"edit_options": "Optionen bearbeiten",
|
||||
"add_option": "Option hinzufügen",
|
||||
"close": "Schließen",
|
||||
"dependencies": "Abhängigkeiten",
|
||||
"options": "Optionen",
|
||||
"settings": "Einstellungen"
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
{
|
||||
"designer": "Designer",
|
||||
"preview": "Calculation Analysis",
|
||||
"xml_view": "XML View",
|
||||
"json_view": "JSON View",
|
||||
"preview_mode": "Preview Mode",
|
||||
"headline": "Headline",
|
||||
"text": "Text",
|
||||
"media": "Media",
|
||||
"textarea": "Textarea",
|
||||
"input": "Input",
|
||||
"select": "Select",
|
||||
"hidden": "Hidden",
|
||||
"row": "Row",
|
||||
"id": "ID",
|
||||
"default": "Default",
|
||||
"name": "Name",
|
||||
"variant": "Variant",
|
||||
"headline1": "Headline 1",
|
||||
"headline2": "Headline 2",
|
||||
"headline3": "Headline 3",
|
||||
"headline4": "Headline 4",
|
||||
"headline5": "Headline 5",
|
||||
"headline6": "Headline 6",
|
||||
"placeholder": "Placeholder",
|
||||
"required": "Required",
|
||||
"min": "Min",
|
||||
"max": "Max",
|
||||
"min_calc": "Min Calc",
|
||||
"max_calc": "Max Calc",
|
||||
"add_dependency": "Add Dependency",
|
||||
"add_column": "Add Column",
|
||||
"mode": "Mode",
|
||||
"normal": "Normal",
|
||||
"paperdb": "PaperDB",
|
||||
"colordb": "ColorDB",
|
||||
"container": "Container",
|
||||
"edit_options": "Edit Options",
|
||||
"add_option": "Add Option",
|
||||
"close": "Close",
|
||||
"dependencies": "Dependencies",
|
||||
"options": "Options",
|
||||
"settings": "Settings"
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import de from './de.json'
|
||||
import en from './en.json'
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'de',
|
||||
fallbackLocale: 'en',
|
||||
messages: {
|
||||
de,
|
||||
en
|
||||
}
|
||||
})
|
||||
|
||||
export default i18n
|
||||
@ -2,9 +2,11 @@ import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import i18n from './i18n'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(i18n)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
@ -20,6 +20,10 @@ export default class BaseElement {
|
||||
isFocused: boolean = false;
|
||||
dependencys: Dependency[] = [];
|
||||
|
||||
hasDependencys() {
|
||||
return this.dependencys.length > 0;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
'id': this.id,
|
||||
|
||||
@ -7,6 +7,8 @@ export default class InputElement extends BaseElement {
|
||||
name: string = ""
|
||||
xmlType: string = "input"
|
||||
minValue: number = 0
|
||||
minCalc: string = ""
|
||||
maxCalc: string = ""
|
||||
maxValue: number = 0
|
||||
|
||||
constructor() {
|
||||
@ -22,7 +24,9 @@ export default class InputElement extends BaseElement {
|
||||
'default': this.default,
|
||||
'name': this.name,
|
||||
'minValue': this.minValue,
|
||||
'minCalc': this.minCalc,
|
||||
'maxValue': this.maxValue,
|
||||
'maxCalc': this.maxCalc,
|
||||
'required': this.required
|
||||
})
|
||||
}
|
||||
@ -34,6 +38,8 @@ export default class InputElement extends BaseElement {
|
||||
this.required = obj.required
|
||||
this.placeHolder = obj.placeHolder
|
||||
this.minValue = obj.minValue
|
||||
this.minCalc = obj.minCalc
|
||||
this.maxValue = obj.maxValue
|
||||
this.maxCalc = obj.maxCalc
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,17 @@ export default class SelectElement extends BaseElement {
|
||||
this.options.push(option)
|
||||
}
|
||||
|
||||
hasDependencys() {
|
||||
let hasDep = this.options.reduce((result: bool, opt: Option) => {
|
||||
if(opt.dependencys.length > 0) {
|
||||
result = true
|
||||
}
|
||||
return result
|
||||
}, false)
|
||||
|
||||
return hasDep || super.hasDependencys()
|
||||
}
|
||||
|
||||
public toJSON() {
|
||||
return Object.assign(
|
||||
super.toJSON(),
|
||||
|
||||
@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
|
||||
import BaseElement from '../model/BaseElement'
|
||||
import Parser from '../lib/parser'
|
||||
import {v4 as uuidv4} from 'uuid'
|
||||
import { loadJsonFromApi } from '../lib/api'
|
||||
import { loadJsonFromApi, loadPriceFromApi } from '../lib/api'
|
||||
|
||||
|
||||
export const useElementStore = defineStore('items', {
|
||||
@ -10,12 +10,17 @@ export const useElementStore = defineStore('items', {
|
||||
uuid: uuidv4(),
|
||||
items: [] as BaseElement[],
|
||||
activeItem: {} as BaseElement | {},
|
||||
formulaData: [],
|
||||
formulaError: '',
|
||||
isFormulaLoading: false,
|
||||
showProperties: false,
|
||||
showDependency: false,
|
||||
showOptions: false,
|
||||
showPreview: false,
|
||||
sourceDragUuid: "",
|
||||
dragMode: "",
|
||||
json: "",
|
||||
xml: "",
|
||||
name: uuidv4(),
|
||||
}),
|
||||
getters: {
|
||||
@ -24,9 +29,11 @@ export const useElementStore = defineStore('items', {
|
||||
getActiveItem: (state) => state.activeItem as BaseElement,
|
||||
isShowPropierties: (state) => state.showProperties,
|
||||
isShowDependency: (state) => state.showDependency,
|
||||
isShowOptions: (state) => state.showOptions,
|
||||
isShowPreview: (state) => state.showPreview,
|
||||
getSourceDragUuid: (state) => state.sourceDragUuid,
|
||||
getDragMode: (state) => state.dragMode,
|
||||
getFormulaData: (state) => state.formulaData,
|
||||
},
|
||||
actions: {
|
||||
addElement(item: BaseElement) {
|
||||
@ -73,6 +80,9 @@ export const useElementStore = defineStore('items', {
|
||||
setShowDependency(value: boolean) {
|
||||
this.showDependency = value
|
||||
},
|
||||
setShowOptions(value: boolean) {
|
||||
this.showOptions = value
|
||||
},
|
||||
setShowProperties(value: boolean) {
|
||||
this.showProperties = value
|
||||
},
|
||||
@ -140,10 +150,31 @@ export const useElementStore = defineStore('items', {
|
||||
setDragMode(mode: string) {
|
||||
this.dragMode = mode
|
||||
},
|
||||
async loadFromApi(id: string) {
|
||||
const data = await loadJsonFromApi(id);
|
||||
this.json = data;
|
||||
async loadConfigFromProductApi(uuid: string) {
|
||||
const data = await loadJsonFromApi(uuid);
|
||||
this.json = data.json;
|
||||
this.xml = data.xml;
|
||||
this.parseJSON();
|
||||
},
|
||||
async loadFormulaAnalyserDataFromApi(uuid: string) {
|
||||
if (this.formulaData && this.formulaData.length > 0) {
|
||||
return;
|
||||
}
|
||||
this.isFormulaLoading = true;
|
||||
this.formulaError = '';
|
||||
try {
|
||||
const response = await loadPriceFromApi(uuid);
|
||||
if (response && response.debug && response.debug.graphJson) {
|
||||
this.formulaData = JSON.parse(response.debug.graphJson);
|
||||
} else {
|
||||
throw new Error('Invalid or empty response format from API.');
|
||||
}
|
||||
} catch (e: any) {
|
||||
this.formulaError = `Failed to load formula data: ${e.message}`;
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.isFormulaLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ export default defineConfig({
|
||||
changeOrigin: true,
|
||||
configure: (proxy, options) => {
|
||||
proxy.on('proxyReq', (proxyReq, req, res) => {
|
||||
proxyReq.setHeader('Authorization', 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTI1MTE3MTgsImV4cCI6MTc1MjUxNTMxOCwicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfU0hPUF9PUEVSQVRPUiIsIlJPTEVfVVNFUiIsIlJPTEVfVVNFUiIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9FZGl0IiwiUk9MRV9QU0NfQ29sbGVjdF9Db250YWN0X0FkZCIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9EZWxldGUiLCJST0xFX1BTQ19Db2xsZWN0X0NvbnRhY3RfTG9jayIsIlJPTEVfUFNDX1IyX1NlbmRjbG91ZF9TaG93Il0sInVpZCI6MX0.MlNFnqbWlCbaKejkcJgnri2d4pg569vfk6TrOe32rJbyyyb0X3svfhzvCsyO9i1-XwR0frm5s2fHdeGEumCjtel9VzLLIvbmr43NhUVPA03EG17pAX4QnM-GaL9vzIeZQlrIcwSprFKz9qo6Toc1Wq0mFEjvTwHj5UR5JBIgnV7TtScIVl83XJljMUbX-NrUSoOeGn6W2SRtH_bDP47ZC-P4wtDcXcrJWM9ka1Vknn-1DQgitVLtOEsxzU7bkxPpfC_ENuRqDE8HmpPZsizF4Pt9jzfAXcPy0CviBJxvg1-tu57h164VSsnz1-K6duBMTB18afi987-dXtBc7nKJhQ');
|
||||
proxyReq.setHeader('Authorization', 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTI1Nzc2NzIsImV4cCI6MTc1MjU4MTI3Miwicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfU0hPUF9PUEVSQVRPUiIsIlJPTEVfVVNFUiIsIlJPTEVfVVNFUiIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9FZGl0IiwiUk9MRV9QU0NfQ29sbGVjdF9Db250YWN0X0FkZCIsIlJPTEVfUFNDX0NvbGxlY3RfQ29udGFjdF9EZWxldGUiLCJST0xFX1BTQ19Db2xsZWN0X0NvbnRhY3RfTG9jayIsIlJPTEVfUFNDX1IyX1NlbmRjbG91ZF9TaG93Il0sInVpZCI6MX0.ViKfV_6cSsP6UvqibTJ5zXE8F5JZWmOEhNquw5_3bpB5N7rOtTIM8ZaD5i9VfoRf2a1CaSIKAzhte_8K49bNIpMd4B8mh3ufqUIHn33L34TsiTNblKv4PlQB_FZbCgujzfP2UenrDi3SAsHd5bynZUOJNbkGzMtv2sUot-mrKJmUvchl-yvcSFw4bYfy-88hnfXJ6sCDlIU-Vd9OSChoBqD12z3Nr6fEqY-ngq7Xv315yFY9Fhg3gxu5NqyAMzN-F6QJHjUsHlo2b9oLeAo2nFZ_Cj2nAMVa6VbxAXMrj6Ogf2POr1TWtvBBaJZj4c1D5rWktkFkPLTUAStNOwMRvQ');
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@ -89,6 +89,6 @@ class Config extends AbstractController
|
||||
$engine->setActiveArticle($data->xmlProduct);
|
||||
}
|
||||
|
||||
return $this->json($engine->generateJson());
|
||||
return $this->json(['json' => $engine->generateJson(), 'xml' => $engine->generateXML(true)]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Plugin\System\PSC\XmlCalc\Api\Product;
|
||||
|
||||
use Doctrine\ODM\MongoDB\DocumentManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Nelmio\ApiDocBundle\Annotation\Security;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Plugin\System\PSC\XmlCalc\Dto\Input\DesignInput;
|
||||
use Plugin\System\PSC\XmlCalc\Model\Product as PluginProduct;
|
||||
use PSC\Component\ApiBundle\Dto\Error\NotFound;
|
||||
use PSC\Library\Calc\Engine;
|
||||
use PSC\Library\Calc\PaperContainer;
|
||||
use PSC\Shop\ContactBundle\Model\Contact;
|
||||
use PSC\Shop\ContactBundle\Transformer\Model\Contact as ContactTransformer;
|
||||
use PSC\Shop\EntityBundle\Entity\Product;
|
||||
use PSC\System\SettingsBundle\Service\PaperDB;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
class Design extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private \PSC\System\SettingsBundle\Service\Shop $shopService,
|
||||
private DocumentManager $documentManager,
|
||||
private PaperDB $paperDB,
|
||||
private ContactTransformer $contactTransformer,
|
||||
private TokenStorageInterface $tokenStorage,
|
||||
private EntityManagerInterface $entityManager,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="get config for product",
|
||||
* @OA\JsonContent(ref=@Model(type=\Plugin\System\PSC\XmlCalc\Model\Product::class))
|
||||
* )
|
||||
* @OA\RequestBody(
|
||||
*
|
||||
* @Model(type=\Plugin\System\PSC\XmlCalc\Dto\Input\DesignInput::class))
|
||||
* )
|
||||
* @OA\Tag(name="Plugin/System/psc/Xmlcalc/Product")
|
||||
* */
|
||||
#[Route(path: '/product/design', methods: ['POST'])]
|
||||
#[ParamConverter(
|
||||
'data',
|
||||
class: '\Plugin\System\PSC\XmlCalc\Dto\Input\DesignInput',
|
||||
converter: 'psc_rest.request_body',
|
||||
)]
|
||||
public function config(DesignInput $data)
|
||||
{
|
||||
$product = $this->entityManager
|
||||
->getRepository('PSC\Shop\EntityBundle\Entity\Product')
|
||||
->findOneBy(['uuid' => $data->product]);
|
||||
|
||||
$paperContainer = new PaperContainer();
|
||||
$paperContainer->parse(simplexml_load_string($product->getShop()->getInstall()->getPaperContainer()));
|
||||
$engine = new Engine();
|
||||
$engine->setPaperRepository($this->paperDB);
|
||||
$engine->setPaperContainer($paperContainer);
|
||||
if ($product->getShop()->getInstall()->getCalcTemplates() && !$data->test) {
|
||||
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplates() . '</root>');
|
||||
}
|
||||
if ($product->getShop()->getInstall()->getCalcTemplatesTest() && $data->test) {
|
||||
$engine->setTemplates('<root>' . $product->getShop()->getInstall()->getCalcTemplatesTest() . '</root>');
|
||||
}
|
||||
$engine->loadJson($data->jsonProduct);
|
||||
if (!$data->test) {
|
||||
$engine->setFormulas($product->getShop()->getFormel());
|
||||
$engine->setParameters($product->getShop()->getParameter());
|
||||
}
|
||||
if ($data->test) {
|
||||
$engine->setFormulas($product->getShop()->getTestFormel());
|
||||
$engine->setParameters($product->getShop()->getTestParameter());
|
||||
}
|
||||
$engine->setVariables($data->values);
|
||||
$engine->setTax($product->getMwert());
|
||||
if ($this->tokenStorage->getToken()) {
|
||||
$contact = new Contact();
|
||||
$this->contactTransformer->fromDb($contact, $this->tokenStorage->getToken()->getUser());
|
||||
$engine->setVariable('contact.accountType', $contact->getAccountType()->value);
|
||||
$engine->setVariable('contact.account', $contact->getAccount()->getUid());
|
||||
}
|
||||
|
||||
return $this->json([
|
||||
'json' => $engine->generateJson(),
|
||||
'xml' => $engine->generateXML(true),
|
||||
'jsonGraph' => $engine->getCalcGraph()->generateJsonGraph(),
|
||||
'price' => $engine->getPrice() * 100,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Plugin\System\PSC\XmlCalc\Dto\Input;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
final class DesignInput
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @OA\Property(type="string")
|
||||
*/
|
||||
public string $product;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @OA\Property(type="string")
|
||||
*/
|
||||
public string $jsonProduct = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*
|
||||
* @OA\Property(type="boolean")
|
||||
*/
|
||||
public bool $test = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @OA\Property(type="array", @OA\Items(type="string"))
|
||||
*/
|
||||
public array $values = ['auflage' => 100];
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user