Rev 8392 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
declare(strict_types=1);
/**
* Template für die Verwaltung der Produktvarianten innerhalb des Produktes
* @author: Daniel Schmitzer (daschmi@daschmi.de)
* @date: 20.04.23
* @time: 11:30
*/
namespace wpsg;
?>
<?php if (!wpsg_isSizedInt($this->view['data']['id'])) { ?>
<p><?php echo __('Bitte speichern Sie das Produkt zuerst.', 'wpsg'); ?></p>
<?php } else {
/** @var \wpsg_product $oProduct */
$oProduct = \wpsg_product::getInstance(intval($this->view['data']['id']));
?>
<?php echo wpsg_drawForm_AdminboxStart(__('Produktvarianten', 'wpsg')); ?>
<?php echo $this->view['wpsg_mod_productvariants']['html']; ?>
<a href="<?php echo WPSG_URL_WP; ?>wp-admin/admin.php?page=wpsg-Admin&action=module&modul=wpsg_mod_productvariants"><span class="wpsg-glyphicon glyphicon glyphicon-wrench"></span><?php echo __('Zur Konfiguration der Produktvarianten', 'wpsg'); ?></a>
<?php echo wpsg_drawForm_AdminboxEnd(); ?>
<div id="wpsg_mod_productvars_combination">
<div v-if="loading" class="loading_layer">
<img class="loading" src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" />
</div>
<div class="inner">
<div class="top_filter">
<div v-for="(variant, i) of arVariationen">
<select v-model="arFilter[i]">
<option :value="0">{{getVariantLabel(i)}} [ Alle ]</option>
<option :value="parseInt(variation)" v-for="(variation, j) of variant">{{getVariantLabel(i)}} [{{getVariationLabel(variation)}}]</option>
</select>
</div>
</div>
<div v-for="(combination, i) of arPossibleKeysFiltered" class="relative">
<div class="panel panel-default">
<div class="panel-heading clearfix">
<h3 class="panel-title">
{{combination.label}}
<div class="right">
<a :href="combination.url" target="_blank" class="url" title="<?php echo __('Produktvariante im Frontend ansehen', 'wpsg'); ?>">
<span class="glyphicon glyphicon-new-window"></span>
</a>
<span v-if="combination.id > 0" class="glyphicon glyphicon-pencil" @click.prevent="edit(combination)"></span>
<span v-else class="glyphicon glyphicon-plus" @click.prevent="add(combination)"></span>
</div>
</h3>
</div>
<div class="panel-body" v-if="combination.loaded">
<div v-if="combination.loading" class="loading_layer">
<img class="loading" src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" />
</div>
<div class="form-group form-group-sm ">
<label class="col-sm-6 control-label" for="name">Produktname</label>
<div class="col-sm-6">
<div class="wpsg_field_wrap">
<input type="text"
@keydown.enter.prevent
class="form-control input-sm " autocomplete="off" placeholder="" v-model="combination.name" />
</div>
</div>
<div class="clearfix wpsg_clear"></div>
</div>
<div class="form-group form-group-sm ">
<label class="col-sm-6 control-label" for="detailname">Produktname (Detail)</label>
<div class="col-sm-6">
<div class="wpsg_field_wrap">
<input type="text"
@keydown.enter.prevent
class="form-control input-sm " autocomplete="off" placeholder="" v-model="combination.detailname" />
</div>
</div>
<div class="clearfix wpsg_clear"></div>
</div>
<div class="form-group form-group-sm ">
<label class="col-sm-6 control-label" for="anr">Artikelnummer</label>
<div class="col-sm-6">
<div class="wpsg_field_wrap">
<input type="text"
@keydown.enter.prevent
class="form-control input-sm" autocomplete="off" placeholder="" v-model="combination.anr" />
</div>
</div>
<div class="clearfix wpsg_clear"></div>
</div>
<!-- Productcodes -->
<template v-if="codeKeyNotSet(combination).length > 0">
<div class="form-group form-group-sm has-feedback">
<label class="col-sm-6 control-label" for="metaean">Code hinzufügen</label>
<div class="col-sm-6">
<div class="wpsg_field_wrap">
<select class="form-control input-sm" v-model="combination.add_code_key">
<option v-for="(code_key, i) of codeKeyNotSet(combination)" :value="code_key">{{combination.arProductCodes[code_key].label}}</option>
</select>
<a @click.stop.prevent="codeKeyAdd(combination)" href="#" class="glyphicon glyphicon glyphicon-plus form-control-feedback" aria-hidden="true" style="pointer-events: auto;"></a>
</div>
</div>
<div class="clearfix wpsg_clear"></div>
</div>
<hr />
</template>
<div class="code_wrap">
<template v-for="(code, i) of combination.arProductCodes">
<div class="form-group form-group-sm has-feedback" v-if="code.set === true">
<label class="col-sm-6 control-label" for="metaean">{{code.label}}</label>
<div class="col-sm-6">
<div class="wpsg_field_wrap">
<input type="text" class="form-control input-sm" v-model="code.code"
@keydown.enter.prevent
/>
<a @click.stop.prevent="codeKeyRemove(combination, code.code_key)" href="#" class="glyphicon glyphicon glyphicon-trash form-control-feedback" aria-hidden="true" style="pointer-events: auto;"></a>
</div>
</div>
<div class="clearfix wpsg_clear"></div>
</div>
</template>
</div>
<!--<pre>{{combination}}</pre>-->
<div class="mt-8 flex w-full justify-end">
<input type="submit" @click.prevent="save(combination)" class="button button-primary" value="speichern" />
</div>
</div>
</div>
</div>
</div>
</div>
<script type="module">
import { ref, createApp, onMounted, computed } from '<?php echo plugin_dir_url(__FILE__); ?>/../../../js/vue.esm-browser.js';
document.addEventListener('DOMContentLoaded', () => {
const app = createApp({
setup() {
const product_id = ref(<?php echo $oProduct->getId(); ?>);
const loading = ref(true);
const arFilter = ref(undefined);
const arPossibleKeys = ref(undefined);
const arVariant = ref(undefined);
const arVariantLabel = ref(undefined);
const arVariationen = ref(undefined);
const arVariationLabel = ref(undefined);
const arPossibleKeysFiltered = computed(() => {
let r = [];
if (!arPossibleKeys.value) return r;
for (let var_key of arPossibleKeys.value) {
const arKey = var_key.var_key.split('|');
const typedKey = {};
for (let i of arKey) {
const [var_id, vari_id] = i.split(':');
typedKey[var_id] = parseInt(vari_id);
}
let set = true;
for (let f in arFilter.value) {
if (arFilter.value[f] !== 0 && typedKey[f] !== arFilter.value[f]) {
set = false;
break;
}
}
if (set) r.push(var_key);
}
return r;
});
const getVariantLabel = (var_id) => {
if (arVariantLabel.value[var_id.toString()] !== undefined) return arVariantLabel.value[var_id.toString()];
else '';
};
const getVariationLabel = (var_id) => {
if (arVariationLabel.value[var_id.toString()] !== undefined) return arVariationLabel.value[var_id.toString()];
else '';
};
const xhr = (action_do, data, cb_success) => {
const request = new XMLHttpRequest();
data.action_do = action_do;
request.open('POST', '<?php echo WPSG_URL_WP; ?>wp-admin/?page=wpsg-Admin&action=module&modul=wpsg_mod_productvariants&subaction=combination&noheader=1', true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.onload = () => {
if (request.status >= 200 && request.status < 400) {
const response = JSON.parse(request.responseText);
cb_success(response);
} else {
console.error('Error: ' + request.statusText);
}
};
request.onerror = function () {
console.error('Error: ' + request.statusText);
};
request.send(JSON.stringify(data));
};
const save = (combination) => {
xhr('save', {
var_key: combination.var_key,
product_id: combination.product_id,
combination: combination
}, (response) => {
for (let i = 0; i < arPossibleKeys.value.length; i++) {
const var_key = arPossibleKeys.value[i];
if (var_key.var_key === response.combination.var_key) {
arPossibleKeys.value[i] = response.combination;
}
}
});
combination.loading = true;
}
const updateCombinationData = () => {
xhr('getCombination', {
product_id: product_id.value
}, (response) => {
arFilter.value = response.arFilter;
arPossibleKeys.value = response.arPossibleKeys;
arVariant.value = response.arVariant;
arVariantLabel.value = response.arVariantLabel;
arVariationen.value = response.arVariationen;
arVariationLabel.value = response.arVariationLabel;
loading.value = false;
});
};
const add = (combination) => {
combination.loaded = true;
combination.loading = true;
xhr('add', {
var_key: combination.var_key,
product_id: product_id.value
}, (response) => {
for (let i = 0; i < arPossibleKeys.value.length; i++) {
const var_key = arPossibleKeys.value[i];
if (var_key.var_key === response.combination.var_key) {
arPossibleKeys.value[i] = response.combination;
}
}
});
};
const edit = (combination) => {
combination.loaded = true;
combination.loading = true;
xhr('edit', {
var_key: combination.var_key,
product_id: product_id.value
}, (response) => {
for (let i = 0; i < arPossibleKeys.value.length; i++) {
const var_key = arPossibleKeys.value[i];
if (var_key.var_key === response.combination.var_key) {
arPossibleKeys.value[i] = response.combination;
}
}
});
};
const codeKeyNotSet = (combination) => {
let r = [];
for (let code_key in combination.arProductCodes) {
if (combination.arProductCodes[code_key].set !== true) r.push(code_key);
}
return r;
};
const codeKeyAdd = (combination) => {
const add_code_key = combination.add_code_key;
if (add_code_key !== undefined && codeKeyNotSet(combination).includes(add_code_key)) {
combination.arProductCodes[add_code_key].set = true;
combination.add_code_key = undefined;
}
};
const codeKeyRemove = (combination, code_key_remove) => {
combination.arProductCodes[code_key_remove].set = false;
}
onMounted(() => {
// updateCombinationData();
});
return {
arFilter,
arPossibleKeys,
arVariant,
arVariantLabel,
arVariationen,
arVariationLabel,
product_id,
loading,
getVariantLabel,
getVariationLabel,
codeKeyNotSet, codeKeyAdd, codeKeyRemove,
arPossibleKeysFiltered,
add,
edit,
save,
updateCombinationData
};
}
}).mount('#wpsg_mod_productvars_combination');
window.wpsg_mod_productvariants = app;
jQuery(document).ready(function () {
wpsg_mod_productvariants_show(<?php echo $this->view['data']['id']; ?>);
});
});
</script>
<style>
#wpsg_mod_productvars_combination { width:100%; position:relative; }
#wpsg_mod_productvars_combination .top_filter { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); row-gap:1rem; column-gap:1rem; margin-bottom:2rem; }
#wpsg_mod_productvars_combination .top_filter select { width:100%; }
#wpsg_mod_productvars_combination .panel-title { display:flex; justify-content:space-between; align-items:center; }
#wpsg_mod_productvars_combination .panel-title a.url { color:inherit; margin-right:1rem; display:inline-block; }
#wpsg_mod_productvars_combination .panel-title .glyphicon { cursor:pointer; }
#wpsg_mod_productvars_combination .panel { margin-bottom:10px; }
#wpsg_mod_productvars_combination .loading_layer { z-index:10; position:absolute; left:0; top:0; width:100%; height:100%; background-color:rgba(255, 255, 255, 0.5); display:flex; justify-content:center; align-items:center; }
#wpsg_mod_productvars_combination > .inner { min-height:50px; width:100%; }
#wpsg_mod_productvars_combination .flex { display:flex; }
#wpsg_mod_productvars_combination .w-full { width:100%; }
#wpsg_mod_productvars_combination .justify-end { justify-content:flex-end; }
#wpsg_mod_productvars_combination .mt-4 { margin-top:1rem; }
#wpsg_mod_productvars_combination .relative { position:relative; }
#wpsg_mod_productvars_combination .mt-8 { margin-top:2rem; }
</style>
<?php }