feat(fe smartblock): started working on smart blocks editor
This commit is contained in:
parent
8ba2731c31
commit
08c50d6a97
7 changed files with 516 additions and 3 deletions
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Table from "@/components/content/partials/Table.vue";
|
import Table from "@/components/content/partials/Table.vue";
|
||||||
import PlaylistEditor from "@/components/content/partials/PlaylistEditor.vue";
|
|
||||||
import ConfirmDelete from "@/components/content/partials/dialogs/ConfirmDelete.vue";
|
import ConfirmDelete from "@/components/content/partials/dialogs/ConfirmDelete.vue";
|
||||||
import {onBeforeMount, reactive, ref, watch} from "vue";
|
import {onBeforeMount, reactive, ref, watch} from "vue";
|
||||||
import {blocks_page} from "@/composables/content/blocks_page.ts";
|
import {blocks_page} from "@/composables/content/blocks_page.ts";
|
||||||
|
import SmartBlockEditor from "@partials/SmartBlockEditor.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
hideColumns: {
|
hideColumns: {
|
||||||
|
@ -101,7 +101,7 @@ watch(search, (newValue, oldValue) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PlaylistEditor
|
<SmartBlockEditor
|
||||||
v-if="itemEdited.id !== null && !dialog.open"
|
v-if="itemEdited.id !== null && !dialog.open"
|
||||||
:item="itemEdited"
|
:item="itemEdited"
|
||||||
@go-back="resetItemEdited"
|
@go-back="resetItemEdited"
|
||||||
|
@ -125,7 +125,7 @@ watch(search, (newValue, oldValue) => {
|
||||||
>
|
>
|
||||||
<template v-slot:header-buttons>
|
<template v-slot:header-buttons>
|
||||||
<v-btn color="primary" @click="edit(0)">
|
<v-btn color="primary" @click="edit(0)">
|
||||||
Crea una nuova Playlist
|
Crea un nuovo blocco dinamico
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:dialog>
|
<template v-slot:dialog>
|
||||||
|
|
132
resources/js/components/content/partials/SmartBlockEditor.vue
Normal file
132
resources/js/components/content/partials/SmartBlockEditor.vue
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Sources from "@/components/content/partials/Sources.vue";
|
||||||
|
import TrackList from "@/components/content/partials/TrackList.vue";
|
||||||
|
import {useAuthStore} from "@/stores/auth.store.ts";
|
||||||
|
import {reactive, ref} from "vue";
|
||||||
|
import {smartblock} from "@models/smartblock/smartblock.ts";
|
||||||
|
|
||||||
|
const auth = useAuthStore();
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'saveItem'
|
||||||
|
])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
item: Object,
|
||||||
|
})
|
||||||
|
|
||||||
|
const item = props.item.id > 0 ? props.item : reactive({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
creator_id: auth.userData.user.id,
|
||||||
|
description: '',
|
||||||
|
tracks: [],
|
||||||
|
criteria: [],
|
||||||
|
limit: {
|
||||||
|
type: null,
|
||||||
|
quantity: null
|
||||||
|
},
|
||||||
|
repeated_tracks: false,
|
||||||
|
overflow_tracks: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const smartblockFields = smartblock(item)
|
||||||
|
|
||||||
|
//Is true if there is a required field empty or while saving
|
||||||
|
const disabledSaveButton = ref(true)
|
||||||
|
|
||||||
|
|
||||||
|
const update = (list) => {
|
||||||
|
item.tracks = list
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
// const errors
|
||||||
|
emit('saveItem', item)
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkError = (field, model) => {
|
||||||
|
if (field.required) {
|
||||||
|
const error = field.required && (model === '' || model === null)
|
||||||
|
disabledSaveButton.value = error
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateProperty = (criteria, prop) => {
|
||||||
|
console.log(criteria, prop)
|
||||||
|
item[prop] = criteria
|
||||||
|
console.log(item)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-row no-gutters>
|
||||||
|
<v-col>
|
||||||
|
<Component
|
||||||
|
v-for="(field, key) in smartblockFields()"
|
||||||
|
:is="field.component"
|
||||||
|
:label="field.label"
|
||||||
|
:radioButtons="field.radioButtons"
|
||||||
|
:value="field.value"
|
||||||
|
:disabled="field.disabled"
|
||||||
|
:density="'compact'"
|
||||||
|
@update:modelValue="checkError(field, item[key])"
|
||||||
|
@update-property="updateProperty"
|
||||||
|
:error="checkError(field, item[key])"
|
||||||
|
:limit="item.limit"
|
||||||
|
rows="2"
|
||||||
|
:items="field.items"
|
||||||
|
v-model="item[key]"
|
||||||
|
item-title="title"
|
||||||
|
item-value="value"
|
||||||
|
density="compact"
|
||||||
|
hide-details="auto"
|
||||||
|
class="mb-2"
|
||||||
|
clearable
|
||||||
|
:active="true"
|
||||||
|
/>
|
||||||
|
<v-btn
|
||||||
|
color="accent"
|
||||||
|
@click="$emit('goBack')"
|
||||||
|
>Torna indietro</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="secondary"
|
||||||
|
@click="preview"
|
||||||
|
>Anteprima</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="save"
|
||||||
|
:disabled="disabledSaveButton"
|
||||||
|
>Salva</v-btn>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<TrackList
|
||||||
|
:tracks="item.tracks"
|
||||||
|
@update-tracks="update"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
{{item}}
|
||||||
|
<!-- <v-row class="tables" no-gutters>-->
|
||||||
|
<!-- <v-col>-->
|
||||||
|
<!-- <TrackList-->
|
||||||
|
<!-- :tracks="item.tracks"-->
|
||||||
|
<!-- @update-tracks="update"-->
|
||||||
|
<!-- />-->
|
||||||
|
<!-- </v-col>-->
|
||||||
|
<!-- <v-col>-->
|
||||||
|
<!-- <Sources />-->
|
||||||
|
<!-- </v-col>-->
|
||||||
|
<!-- </v-row>-->
|
||||||
|
<!-- <v-row no-gutters>-->
|
||||||
|
<!-- </v-row>-->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tables > .v-col {
|
||||||
|
width: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps({
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
radioButtons: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-radio-group :label="label">
|
||||||
|
<v-radio
|
||||||
|
v-for="radioButton in radioButtons"
|
||||||
|
:label="radioButton.label"
|
||||||
|
:value="radioButton.value"
|
||||||
|
></v-radio>
|
||||||
|
</v-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,94 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {smartblockCriteria} from "@models/smartblock/smartblockCriteria.ts";
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
import {trackType} from "@/composables/content/track_type.ts";
|
||||||
|
|
||||||
|
const emit = defineEmits(['updateProperty'])
|
||||||
|
|
||||||
|
const { criteria, modifiers } = smartblockCriteria()
|
||||||
|
const trackTypes = trackType(false)
|
||||||
|
console.log(trackTypes)
|
||||||
|
|
||||||
|
const activeCriteria = ref([])
|
||||||
|
const firstCriteria = activeCriteria.value.push({
|
||||||
|
criteria: '',
|
||||||
|
modifier: '',
|
||||||
|
value: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(activeCriteria.value, (newVal, oldVal) => {
|
||||||
|
console.log(newVal)
|
||||||
|
emit('updateProperty', newVal, 'criteria')
|
||||||
|
})
|
||||||
|
|
||||||
|
const addCriteria = () => {
|
||||||
|
activeCriteria.value.push({
|
||||||
|
criteria: '',
|
||||||
|
modifier: '',
|
||||||
|
value: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<label for="criteria" class="v-label">Criteri di popolamento</label>
|
||||||
|
<fieldset id="criteria" class="smartblock-criteria">
|
||||||
|
<v-row v-for="(current, index) in activeCriteria">
|
||||||
|
<v-col
|
||||||
|
v-if="index > 0"
|
||||||
|
cols="12"
|
||||||
|
class="text-center"
|
||||||
|
>E</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-select
|
||||||
|
v-model="activeCriteria[index].criteria"
|
||||||
|
label="Seleziona il criterio"
|
||||||
|
:items="criteria"
|
||||||
|
item-title="title"
|
||||||
|
item-value="value"
|
||||||
|
></v-select>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-select
|
||||||
|
v-model="activeCriteria[index].modifier"
|
||||||
|
label="Seleziona il modificatore"
|
||||||
|
:items="modifiers
|
||||||
|
.filter(mod => mod.type === criteria.find(cri => cri.value === activeCriteria[index].criteria)?.type || mod.type === 'all')"
|
||||||
|
item-title="title"
|
||||||
|
item-value="value"
|
||||||
|
></v-select>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
v-if="activeCriteria[index].criteria != 'track_type_id'"
|
||||||
|
label="Valore scelto"
|
||||||
|
v-model="activeCriteria[index].value"
|
||||||
|
:type="criteria.find(cri => cri.value === activeCriteria[index].criteria)?.type === 'number' ? 'number' : 'text'"
|
||||||
|
></v-text-field>
|
||||||
|
<v-select
|
||||||
|
v-else
|
||||||
|
:items="trackTypes.trackTypes.value"
|
||||||
|
v-model="activeCriteria[index].value"
|
||||||
|
item-title="type_name"
|
||||||
|
item-value="id"
|
||||||
|
></v-select>
|
||||||
|
</v-col>
|
||||||
|
<v-col
|
||||||
|
v-if="index > 0"
|
||||||
|
cols="1"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
@click="activeCriteria.splice(index,1)"
|
||||||
|
>mdi-close</v-icon>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</fieldset>
|
||||||
|
<v-btn
|
||||||
|
color="secundary"
|
||||||
|
@click="addCriteria"
|
||||||
|
>Aggiungi un nuovo criterio</v-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {reactive} from "vue";
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'updateProperty'
|
||||||
|
])
|
||||||
|
|
||||||
|
const limit = reactive({
|
||||||
|
type: null,
|
||||||
|
quantity: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const limitItems = [
|
||||||
|
{
|
||||||
|
title: 'Ore',
|
||||||
|
value: 'hours',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Minuti',
|
||||||
|
value: 'minutes',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tracce',
|
||||||
|
value: 'items',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tempo rimanente della trasmissione',
|
||||||
|
value: 'remaining',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const update = (e) => {
|
||||||
|
emit('updateProperty', limit, 'limit')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<span>Limite a</span>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
v-if="limit.type !== 'remaining'"
|
||||||
|
label="Quanto"
|
||||||
|
v-model="limit.quantity"
|
||||||
|
@update:modelValue="update"
|
||||||
|
type="number"></v-text-field>
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<v-select
|
||||||
|
label="Cosa"
|
||||||
|
v-model="limit.type"
|
||||||
|
:items="limitItems"
|
||||||
|
item-title="title"
|
||||||
|
item-value="value"
|
||||||
|
@update:modelValue="update"
|
||||||
|
></v-select>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
113
resources/js/composables/content/models/smartblock/smartblock.ts
Normal file
113
resources/js/composables/content/models/smartblock/smartblock.ts
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import {VCheckbox, VSelect, VTextarea, VTextField} from "vuetify/components";
|
||||||
|
import RadioGroup from "@partials/fields/smartblock/RadioGroup.vue";
|
||||||
|
import SmartBlockCriteria from "@partials/fields/smartblock/SmartBlockCriteria.vue";
|
||||||
|
import SmartBlockLimit from "@partials/fields/smartblock/SmartBlockLimit.vue";
|
||||||
|
|
||||||
|
export function smartblock(item) {
|
||||||
|
const visibleFields = {
|
||||||
|
name: {
|
||||||
|
title: 'Nome',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
title: 'Descrizione',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
title: 'Tipologia blocco',
|
||||||
|
required: true,
|
||||||
|
radioButtons: [
|
||||||
|
{
|
||||||
|
label: 'Dinamico',
|
||||||
|
value: 'dynamic'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Statico',
|
||||||
|
value: 'static'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
criteria: {
|
||||||
|
title: 'Seleziona i criteri',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
title: 'Limite a',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
repeated_tracks: {
|
||||||
|
title: 'Permetti al ripetizione delle tracce',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
overflow_tracks: {
|
||||||
|
title: 'Permetti all\'ultima traccia di andare oltre il limite',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
title: 'Ordina per',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const fields = {}
|
||||||
|
Object.keys(visibleFields).forEach((key) => {
|
||||||
|
fields[key] = {
|
||||||
|
label: visibleFields[key].title,
|
||||||
|
value: item !== null ? item[key] : '',
|
||||||
|
required: visibleFields[key].required,
|
||||||
|
component: VTextField
|
||||||
|
}
|
||||||
|
// console.log(fields)
|
||||||
|
switch (key) {
|
||||||
|
case 'name':
|
||||||
|
fields[key].component = VTextField
|
||||||
|
break
|
||||||
|
case 'description':
|
||||||
|
fields[key].component = VTextarea
|
||||||
|
break
|
||||||
|
case 'type':
|
||||||
|
fields[key].component = RadioGroup
|
||||||
|
fields[key].radioButtons = visibleFields[key].radioButtons
|
||||||
|
break
|
||||||
|
case 'criteria':
|
||||||
|
fields[key].component = SmartBlockCriteria
|
||||||
|
break
|
||||||
|
case 'limit':
|
||||||
|
fields[key].component = SmartBlockLimit
|
||||||
|
break
|
||||||
|
case 'repeated_tracks':
|
||||||
|
case 'overflow_tracks':
|
||||||
|
fields[key].component = VCheckbox
|
||||||
|
break
|
||||||
|
case 'sort':
|
||||||
|
fields[key].component = VSelect
|
||||||
|
fields[key].items = [
|
||||||
|
{
|
||||||
|
title: 'Random',
|
||||||
|
value: 'random'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Dal più recente',
|
||||||
|
value: 'newest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Dal meno recente',
|
||||||
|
value: 'oldest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Più recentemente andate in onda',
|
||||||
|
value: 'mostrecentplay'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Meno recentemente andate in onda',
|
||||||
|
value: 'leastrecentplay'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// console.log(fields)
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
export function smartblockCriteria() {
|
||||||
|
const criteria = [ {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Nome dell\'Album',
|
||||||
|
value: 'album_title'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
title: 'Nome dell\'Artista',
|
||||||
|
value: 'artist_name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
title: 'Bit Rate (kbps)',
|
||||||
|
value: 'bit_rate'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
title: 'BPM',
|
||||||
|
value: 'bpm'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
title: 'Genere',
|
||||||
|
value: 'genre'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'TrackType',
|
||||||
|
title: 'Tipo di traccia',
|
||||||
|
value: 'track_type_id'
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
const modifiers = [
|
||||||
|
{
|
||||||
|
value: 'contains',
|
||||||
|
title: 'contiene',
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'does not contains',
|
||||||
|
title: 'non contiene',
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'starts with',
|
||||||
|
title: 'comincia con',
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'ends with',
|
||||||
|
title: 'finisce con',
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is greater than',
|
||||||
|
title: 'è maggiore di',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is less than',
|
||||||
|
title: 'è minore di',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is in the range',
|
||||||
|
title: 'è tra',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is',
|
||||||
|
title: 'è uguale a',
|
||||||
|
type: 'all'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is not',
|
||||||
|
title: 'è diverso da',
|
||||||
|
type: 'all'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return { criteria, modifiers }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue