You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xshop/resources/js/components/MetaInput.vue

369 lines
14 KiB
Vue

<template>
<div id="meta-input">
<div id="img-modal" @click.self="modal = false" v-if="modal" class="d-flex align-items-center justify-content-center">
<div class="container">
<div class="row">
<div :class="`col-md-4 `+(j == quantities[qOnEdit].image?'selected-img':'')" v-for="(img,j) in imgz" >
<img :src="img.original_url" @click="changeImgIndex(j)" alt="{{img.id}}" class="img-index">
</div>
</div>
</div>
</div>
<div class="row">
<div v-for="prop in properties" :class="prop.width">
<label for="prop.name" v-if="prop.type != 'checkbox'">
{{ prop.label }}
<!-- [{{prop.type}}]-->
</label>
<div v-else class="mt-2">
<br>
</div>
<div v-if="meta[prop.name] != undefined" class="position-relative">
<template v-if="prop.type == 'text'">
<input type="text" :id="prop.name" v-model="meta[prop.name]" class="form-control">
</template>
<template v-if="prop.type == 'number'">
<input type="number" :id="prop.name" v-model="meta[prop.name]" class="form-control">
</template>
<template v-if="prop.type == 'checkbox'">
<div class="form-check form-switch">
<input class="form-check-input" v-model="meta[prop.name]" type="checkbox" role="switch"
:id="prop.name">
<label class="form-check-label" :for="prop.name">{{ prop.label }}</label>
</div>
</template>
<template v-if="prop.type == 'color'">
<select :id="prop.name" class="form-control color" v-model="meta[prop.name]">
<option v-for="op in prop.optionList" :style="`background: ${op.value} ;`"
:value="op.value"> {{ op.title }}
</option>
</select>
<div class="sq" :style="`background: ${meta[prop.name]} ;`"></div>
</template>
<template v-if="prop.type == 'select' || prop.type == 'singemulti'">
<select :id="prop.name" class="form-control color" v-model="meta[prop.name]">
<option v-for="op in prop.optionList" :value="op.value"> {{ op.title }}</option>
</select>
</template>
<template v-if="prop.type == 'multi'">
<searchable-multi-select :items="prop.optionList" value-field="value"
v-model="meta[prop.name]"></searchable-multi-select>
</template>
<template v-if="prop.type == 'date'">
<vue-date-time-picker v-model="meta[prop.name]"></vue-date-time-picker>
</template>
<template v-if="prop.type == 'time'">
<vue-time-picker v-model="meta[prop.name]" :am-pm="false"></vue-time-picker>
</template>
</div>
</div>
</div>
<div v-if="hasPriceable && productId != null" class="mt-4">
<h4>
Quantities:
<!-- WIP: transalte-->
</h4>
<button type="button" class="btn btn-light w-100 mb-2" @click="addQ">
<i class="ri-add-line"></i>
</button>
<!-- qz: {{ quantitiez }}, qs: {{ quantities }}-->
<div class="row mt-1" v-for="(q,n) in quantities">
<template v-for="prop in properties">
<div v-if="prop.priceable" class="col-md">
<label for="prop.name" v-if="prop.type != 'checkbox'">
{{ prop.label }}
<!-- [{{prop.type}}]-->
</label>
<div v-if="meta[prop.name] != undefined" class="position-relative">
<template v-if="prop.type == 'text'">
<input type="text" :id="prop.name" v-model="q.data[prop.name]" class="form-control">
</template>
<template v-if="prop.type == 'number'">
<input type="number" :id="prop.name" v-model="q.data[prop.name]" class="form-control">
</template>
<template v-if="prop.type == 'checkbox'">
<br>
<div class="form-check form-switch mt-2">
<input class="form-check-input" v-model="q.data[prop.name]" type="checkbox"
role="switch"
:id="prop.name">
<label class="form-check-label" for="flexSwitchCheckDefault">{{
prop.label
}}</label>
</div>
</template>
<template v-if="prop.type == 'color'">
<select :id="prop.name" class="form-control color" v-model="q.data[prop.name]">
<option v-for="op in prop.optionList" :style="`background: ${op.value} ;`"
:value="op.value"> {{ op.title }}
</option>
</select>
<div class="sq" :style="`background: ${q.data[prop.name]} ;`"></div>
</template>
<template v-if="prop.type == 'select' || prop.type == 'singemulti'">
<select :id="prop.name" class="form-control color" v-model="q.data[prop.name]">
<option v-for="op in prop.optionList" :value="op.value"> {{ op.title }}</option>
</select>
</template>
<template v-if="prop.type == 'multi'">
<searchable-multi-select xname="" :items="prop.optionList" value-field="value"
v-model="q.data[prop.name]"></searchable-multi-select>
</template>
<template v-if="prop.type == 'date'">
<vue-date-time-picker v-model="q.data[prop.name]"></vue-date-time-picker>
</template>
<template v-if="prop.type == 'time'">
<vue-time-picker v-model="q.data[prop.name]" :am-pm="false"></vue-time-picker>
</template>
</div>
</div>
</template>
<div class="col-md">
<label :for="`qid-${n}`">
Count: <!-- WIP: transalte-->
</label>
<input type="number" placeholder="Count" :id="`qid-${n}`" min="0" v-model="q.count" class="form-control">
</div>
<div class="col-md">
<label :for="`prc-${n}`">
Price: <!-- WIP: transalte-->
</label>
<currency-input :xid="`qid-${n}`" xtitle="Price" v-model="q.price"></currency-input>
</div>
<div class="col-md" v-if="imgz.length > 0">
<label :for="`img-${n}`">
image: <!-- WIP: transalte-->
</label>
<button type="button" class="btn btn-outline-info d-block w-100" @click="showModal(n)">
<i class="ri-image-2-line"></i>
</button>
</div>
<div class="col-md-1">
<br>
<button type="button" class="btn btn-outline-danger d-block w-100" @click="remQ(n)">
<i class="ri-close-line"></i>
</button>
</div>
</div>
</div>
<!-- {{quantities}}-->
<input type="hidden" name="meta" :value="JSON.stringify(meta)">
<input type="hidden" name="q" :value="JSON.stringify(quantities)">
</div>
</template>
<script>
import {mapState} from "vuex";
import searchableMultiSelect from "./SearchableMultiSelect.vue";
import CurrencyInput from "./CurrencyInput.vue";
import VueDateTimePicker from "./vueDateTimePicker.vue";
import vueTimePicker from "./vueTimePicker.vue";
function arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
const sortedArr1 = arr1.slice().sort();
const sortedArr2 = arr2.slice().sort();
return sortedArr1.every((value, index) => value === sortedArr2[index]);
}
export default {
name: "meta-input",
components: {
searchableMultiSelect,
CurrencyInput,
VueDateTimePicker,
vueTimePicker,
},
data: () => {
return {
properties: [],
meta: {},
hasPriceable: false,
quantities: [],
qOnEdit: 0,
modal: false,
lastCat: null,
}
},
props: {
imgz:{
default: []
},
propsApiLink: {
required: true,
},
metaz: {
default: [],
},
quantitiez: {
default: [],
},
productId: {
default: null,
}
},
mounted() {
// this.quantities = this.quantitiez;
for( const q of this.quantitiez) {
q.data = JSON.parse(q.data);
this.quantities.push(q);
}
},
computed: {
category_id: {
get() {
return this.$store.state.category;
},
set(value) {
this.$store.commit('UPDATE_CATEGORY', value)
}
},
qsid: {
get() {
return this.$store.state.quantities;
},
set(value) {
// this.$store.commit('UPDATE_CATEGORY', value)
}
},
qid(){
let r = [];
for( const q of this.quantities) {
r.push(q.id);
}
return r;
}
},
methods: {
showModal(i){
// console.log('ii',i);
this.qOnEdit = i;
this.modal = true;
},
changeImgIndex(i){
// console.log('jjj',i);
this.quantities[this.qOnEdit].image = i;
},
remQ(i){
this.quantities.splice(i,1);
},
addQ() {
let data = {
id: null,
product_id: this.productId,
image: null,
price: 0,
count: 0,
data: {},
};
for (const prop of this.properties) {
// check priceable
if (prop.priceable) {
data.data[prop.name] = '';
}
}
this.quantities.push(data);
},
async updateProps() {
try {
const url = this.propsApiLink + this.category_id;
let resp = await axios.get(url);
this.properties = resp.data.data;
// added don't have
for (const prop of this.properties) {
// check priceable
if (prop.priceable) {
this.hasPriceable = true;
}
if (this.meta[prop.name] == undefined) {
if (prop.type == 'multi') {
this.meta[prop.name] = [];
} else {
this.meta[prop.name] = '';
}
}
}
// update by old meta data
for (const meta in this.metaz) {
this.meta[meta] = this.metaz[meta];
}
} catch (e) {
window.$toast.error(e.message);
}
},
},
watch: {
category_id: function (old,n) {
// console.log(old,n,'x');
// if (this.lastCat != this.category_id){
// this.lastCat = this.category_id;
this.updateProps();
// }
},
qsid: function () {
if (!arraysEqual(this.qid,this.qsid)){
window.location.href = window.redirect;
}
}
}
}
</script>
<style scoped>
#meta-input {
}
.color option {
}
.sq {
width: 37px;
height: 37px;
background: transparent;
border: 1px solid black;
position: absolute;
inset-inline-end: 0;
top: 0;
border-radius: 4px;
}
#img-modal{
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: #00000033;
backdrop-filter: blur(5px);
z-index: 10;
//display: none;
}
.img-index{
width: 100%;
height: 25vh;
min-height: 200px;
object-fit: cover;
}
.selected-img{
background: darkred;
}
</style>