feat(fe smartblock): started working on smart blocks editor

This commit is contained in:
Marco Cavalli 2025-03-25 10:57:19 +01:00
parent 8ba2731c31
commit 08c50d6a97
7 changed files with 516 additions and 3 deletions

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
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 {onBeforeMount, reactive, ref, watch} from "vue";
import {blocks_page} from "@/composables/content/blocks_page.ts";
import SmartBlockEditor from "@partials/SmartBlockEditor.vue";
const props = defineProps({
hideColumns: {
@ -101,7 +101,7 @@ watch(search, (newValue, oldValue) => {
</script>
<template>
<PlaylistEditor
<SmartBlockEditor
v-if="itemEdited.id !== null && !dialog.open"
:item="itemEdited"
@go-back="resetItemEdited"
@ -125,7 +125,7 @@ watch(search, (newValue, oldValue) => {
>
<template v-slot:header-buttons>
<v-btn color="primary" @click="edit(0)">
Crea una nuova Playlist
Crea un nuovo blocco dinamico
</v-btn>
</template>
<template v-slot:dialog>

View 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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View 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
}
}

View file

@ -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 }
}