feat: spots

This commit is contained in:
Michael 2025-07-11 15:03:59 +02:00
parent 08010fbb61
commit a4e1a3328f
20 changed files with 172 additions and 97 deletions

View file

@ -3,6 +3,7 @@
namespace App\Filters;
use App\Filters\FiltersType\AllFilter;
use App\Filters\FiltersType\IsFilter;
use App\Filters\FiltersType\LikeFilter;
class FileFilters

View file

@ -27,11 +27,17 @@ class FileController extends Controller
$pagination = $request->per_page;
}
return File::searchFilter($request)
->where('import_status', '=', 0)
->with('track_type')
->with('owner')
->orderBy('artist_name')
$files = File::searchFilter($request)
->where('import_status', '=', 0)
->with('track_type')
->with('owner');
if($request->track_type == 'spot'){
$trackTypes = TrackType::where('code', '=', 'SPOT')->orWhere('parent_id', '=', '3')->pluck('id');
$files = $files->whereIn('track_type_id', $trackTypes->toArray());
}
return $files->orderBy('artist_name')
->paginate($pagination)
->toJson();
}

View file

@ -31,17 +31,25 @@ class PlaylistController extends Controller
$pagination = $request->per_page;
}
return Playlist::searchFilter($request)
->with(
[
'creator',
'tracks.file',
'tracks.block',
'tracks.block.criteria',
'tracks.block.creator'
]
)
->orderBy('name')
$playlists = Playlist::searchFilter($request)
->with(
[
'creator',
'tracks.file',
'tracks.block',
'tracks.block.criteria',
'tracks.block.creator'
]
);
if($request->has('playlistType')) {
$playlistType = $request->get('playlistType');
$playlists = ($playlistType == 'show')
? $playlists->doesntHave('spotPlaylist')
: $playlists->has('spotPlaylist');
}
return $playlists->orderBy('name')
->paginate($pagination)
->toJson();
} catch (\Exception $e) {

View file

@ -30,11 +30,19 @@ class SmartBlockController extends Controller
} else {
$pagination = $request->per_page;
}
$smartblocks = SmartBlock::searchFilter($request)
->with(['creator', 'tracks', 'tracks.file', 'criteria']);
return SmartBlock::searchFilter($request)
->with(['creator', 'tracks', 'tracks.file', 'criteria'])
if($request->has('smartblockType')) {
$smartblockType = $request->get('smartblockType');
$smartblocks = ($smartblockType == 'show')
? $smartblocks->doesntHave('spotSmartblock')
: $smartblocks->has('spotSmartblock');
}
return $smartblocks
->paginate($pagination)
->toJson();show
->toJson();
}
/**

View file

@ -7,25 +7,16 @@ import {onBeforeMount, onMounted, type PropType, reactive, ref, watch} from "vue
import {usePlaylistStore} from "@/stores/playlist.store.ts";
import {baseSmartBlock} from "@models/smartblock/smartblock.ts";
import {basePlaylist} from "@models/playlist/playlist.ts";
import {useShowTypeStore} from "@stores/showType.store.ts";
const playlistStore = usePlaylistStore();
const { items, listData, headers, selected, loading, search, getItems, editItem, deleteItem } = playlist_page();
// Props and data
const props = defineProps({
showType: {
type: String as PropType<'spot' | null>,
required: false,
validator: (value: string) => ['spot'].includes(value),
default: null,
},
});
// Props, data, stores
const itemEdited = ref({
id: null
});
const bulk = ref(false)
const dialog = reactive({
open: false,
@ -33,7 +24,9 @@ const dialog = reactive({
title: '',
text: ''
})
const showTypeStore = useShowTypeStore();
// Funcs
const openDialog = (type, title = '', text = '', bulk = false) => {
dialog.open = true
dialog.type = type
@ -47,7 +40,7 @@ const edit = (item) => {
item = basePlaylist();
}
playlistStore.loadPlaylist(item);
playlistStore.currentPlaylist.playlist_type = props.showType;
playlistStore.currentPlaylist.playlist_type = showTypeStore.currentType;
itemEdited.value = item;
}

View file

@ -5,20 +5,11 @@ import ConfirmDelete from "@partials/dialogs/ConfirmDelete.vue";
import {show_page} from "@/composables/content/show/show_page.ts";
import ShowForm from "@partials/show/ShowForm.vue";
import {baseShow, type Show} from "@models/show/show";
import {useShowTypeStore} from "@stores/showType.store.ts";
const {items, listData, headers, selected, loading, search, showType, getItems, editItem, deleteItem} = show_page()
// Props and data
const props = defineProps({
showType: {
type: String as PropType<'show' | 'spot' | null>,
required: true,
validator: (value: string) => ['show', 'spot'].includes(value),
default: null,
},
});
const {items, listData, headers, selected, loading, search, getItems, editItem, deleteItem} = show_page()
const showTypeStore = useShowTypeStore();
const showCreateEditMode = ref(false);
let showSelected = ref<Number | null>(null);
@ -58,8 +49,8 @@ const saveItem = (item) => {
}
const cancel = (item) => {
let deleteMessage = `Vuoi cancellare lo ${props.showType} selezionato?`
if (bulk.value.state) deleteMessage = `Vuoi cancellare gli ${props.showType} selezionati?`
let deleteMessage = `Vuoi cancellare lo ${showTypeStore.currentType} selezionato?`
if (bulk.value.state) deleteMessage = `Vuoi cancellare gli ${showTypeStore.currentType} selezionati?`
bulk.value.items = item
showSelected.value = item?.id
openDialog(
@ -95,10 +86,6 @@ const goBack = () => {
showSelected.value = null
}
onBeforeMount(() => {
showType.value = props.showType
})
watch(search, (newValue, oldValue) => {
const options = {...listData};
getItems(options)
@ -106,7 +93,7 @@ watch(search, (newValue, oldValue) => {
</script>
<template>
<ShowForm v-if="showCreateEditMode" :showId="showSelected" :showType="props.showType" @go-back="goBack"/>
<ShowForm v-if="showCreateEditMode" :showId="showSelected" :showType="showTypeStore.currentType" @go-back="goBack"/>
<Table
v-else
:headers="headers"
@ -125,7 +112,7 @@ watch(search, (newValue, oldValue) => {
>
<template v-slot:header-buttons>
<v-btn color="primary" @click="create">
<span>Crea un nuovo {{ props.showType }} </span>
<span>Crea un nuovo {{ showTypeStore.currentType }} </span>
</v-btn>
</template>
<template v-slot:dialog>

View file

@ -6,7 +6,11 @@ import {smartblock_page} from "@/composables/content/smartblock_page.ts";
import SmartBlockEditor from "@partials/SmartBlockEditor.vue";
import {useSmartBlockStore} from "@/stores/smartblock.store.ts";
import {baseSmartBlock} from "@models/smartblock/smartblock.ts";
import {useShowTypeStore} from "@stores/showType.store.ts";
const { items, listData, headers, selected, loading, search, getItems, editItem, deleteItem } = smartblock_page()
// Props, data and stores
const props = defineProps({
hideColumns: {
type: Array,
@ -16,18 +20,8 @@ const props = defineProps({
type: Boolean,
required: false
},
showType: {
type: String as PropType<'spot' | null>,
required: false,
validator: (value: string) => ['spot'].includes(value),
},
});
const smartBlockStore = useSmartBlockStore()
const { items, listData, headers, selected, loading, search, getItems, editItem, deleteItem } = smartblock_page()
const itemEdited = ref({
id: null
})
@ -42,6 +36,11 @@ const dialog = reactive({
const visibleHeaders = ref(headers)
const showTypeStore = useShowTypeStore();
const smartBlockStore = useSmartBlockStore()
// Funcs
const openDialog = (type, title = '', text = '') => {
dialog.open = true
dialog.type = type
@ -54,7 +53,7 @@ const edit = (item) => {
item = baseSmartBlock();
}
smartBlockStore.loadSmartBlock(item);
smartBlockStore.currentSmartBlock.smart_block_type = props.showType;
smartBlockStore.currentSmartBlock.smart_block_type = showTypeStore.currentType;
itemEdited.value = item;
console.log(smartBlockStore)
}
@ -78,7 +77,7 @@ const cancel = (item) => {
const confirmDelete = (confirm) => {
if (confirm) {
if (!bulk) {
if (!bulk.value) {
deleteItem(itemEdited.value.id)
} else {
itemEdited.value.forEach(el => {

View file

@ -6,26 +6,24 @@ import {smartblock} from "@models/smartblock/smartblock.ts";
import {smartblock_page} from "@/composables/content/smartblock_page.ts";
import {formatFromSeconds} from "@/helpers/TimeFormatter.ts";
import {useSmartBlockStore} from "@/stores/smartblock.store.ts";
const auth = useAuthStore();
import {baseSmartBlockCriteria} from "@models/smartblock/smartblockCriteria.ts";
const { loading, getTracklist } = smartblock_page()
const emit = defineEmits([
'saveItem'
])
//
const auth = useAuthStore();
const smartBlockStore = useSmartBlockStore();
const item = smartBlockStore.currentSmartBlock;
console.log(smartBlockStore.currentSmartBlock)
const length = ref([]);
const smartblockFields = smartblock(item)
const length = ref([]);
//Is true if there is a required field empty or while saving
const disabledSaveButton = ref(true)
// Funcs
const update = (list) => {
item.tracks = list
}
@ -61,8 +59,25 @@ const showPreview = async () => {
})
}
function hiddenSmartBlockCriteria(){
if(!smartBlockStore.currentSmartBlock.smart_block_type) return
let showSmartBlockCriteria = baseSmartBlockCriteria()
showSmartBlockCriteria.criteria = 'track_type_id'
showSmartBlockCriteria.modifier = 'is not'
showSmartBlockCriteria.value = '3'
if (smartBlockStore.currentSmartBlock.smart_block_type == 'spot') {
showSmartBlockCriteria.modifier = 'is'
}
smartBlockStore.currentSmartBlock.criteria.push(showSmartBlockCriteria)
}
// Hook and watch
onMounted(() => {
smartBlockStore.updateField({key: 'creator_id', value: auth.userData.user.id})
hiddenSmartBlockCriteria()
})
watch(loading.value, (newVal, oldVal) => {

View file

@ -1,8 +1,9 @@
<script setup lang="ts">
import {ref} from "vue";
import {onBeforeMount, ref} from "vue";
import Archive from "@/components/content/Archive.vue";
import Blocks from "@components/content/SmartBlock.vue";
import Webstream from "@components/content/Webstream.vue";
import {useShowTypeStore} from "@stores/showType.store.ts";
const tab = ref(null)
const tabs = [
@ -19,6 +20,15 @@ const tabs = [
title: 'Webstream',
},
]
onBeforeMount(() => {
const showTypeStore = useShowTypeStore()
if(showTypeStore.currentType == 'spot') {
const webstreamIndex = tabs.findIndex(tab => tab.id == 'webstream')
tabs.splice(webstreamIndex, 1)
}
})
</script>
<template>

View file

@ -50,11 +50,11 @@ onMounted(async () => {
}
// fill store
let playlistOptions = {playlistType: 'spot'};
let playlistOptions: { playlistType: 'show' | 'spot' } = { playlistType: 'spot' };
if (props.showType === 'show') {
usersDJs.value = await getUser({role: 'dj'});
playlistOptions.playlistType = null;
playlistOptions.playlistType = 'show';
}
playlists.value = await getPlaylist(playlistOptions);

View file

@ -1,5 +1,6 @@
import axios from "axios";
import {ref, reactive, computed} from "vue";
import {useShowTypeStore} from "@stores/showType.store.ts";
export function archive_page() {
const items = ref([])
@ -13,6 +14,7 @@ export function archive_page() {
'total_items': 0,
'page': 1,
})
const showTypeStore = useShowTypeStore();
const headers = [
// {title: '', key: 'artwork'},
@ -30,12 +32,14 @@ export function archive_page() {
*/
const getItems = async (page_info) => {
loading.value = true;
let options = {
page: page_info.page,
per_page: page_info.itemsPerPage,
all: search.value
}
options['track_type_id'] = showTypeStore.currentType
return await axios.get(`/file`, {
params: {
page: page_info.page,
per_page: page_info.itemsPerPage,
all: search.value
}
params: options
}).then((response) => {
//console.log(response)
listData.itemsPerPage = response.data.per_page;

View file

@ -49,6 +49,7 @@ export const getPlaylist = async (options: {
page?: Number | null;
per_page?: Number | null;
all?: string | null;
playlistType?: 'show' | 'spot' | null;
}): Promise<any> => {
const filteredParams = cleanOptions(options);
return await axios.get(`/playlist`, {params: filteredParams})

View file

@ -11,7 +11,7 @@ export interface Playlist {
description?: string; // Opzionale
length: number; // Durata della playlist
contents: PlaylistContent[];
playlist_type: 'spot' | null
playlist_type: 'show' | 'spot' | null
}
export const basePlaylist = (): Playlist => {

View file

@ -17,7 +17,7 @@ export interface SmartBlock {
contents?: SmartBlockContent[]; // Contenuti associati (opzionale)
criteria?: SmartBlockCriteria[]; // Criteri associati (opzionale)
tracks?: SmartBlockContent[];
smart_block_type: 'spot' | null;
smart_block_type: 'show' | 'spot' | null;
}
export const baseSmartBlock = (): SmartBlock => {
@ -48,6 +48,7 @@ export const getSmartBlock = async (options: {
page?: Number | null;
per_page?: Number | null;
all?: string | null;
smartblockType?: 'show' | 'spot' | null;
}): Promise<SmartBlock[]> => {
const filteredParams = cleanOptions(options);
return await axios.get(`/smartblock`, {params: filteredParams})

View file

@ -1,6 +1,7 @@
import {reactive, ref} from "vue";
import axios from "axios";
import {timeFormatter} from "@/helpers/TimeFormatter.ts";
import {useShowTypeStore} from "@stores/showType.store.ts";
export function playlist_page() {
const items = ref([])
@ -14,6 +15,7 @@ export function playlist_page() {
'total_items': 0,
'page': 1,
})
const showTypeStore = useShowTypeStore();
const headers = [
// {title: '', key: 'artwork'},
@ -31,6 +33,7 @@ export function playlist_page() {
page: page_info.page,
per_page: page_info.itemsPerPage,
all: search.value,
playlistType: showTypeStore.currentType,
}
}).then((response) => {
console.log(response)

View file

@ -1,6 +1,7 @@
import {reactive, ref} from "vue";
import axios, {type AxiosResponse} from "axios";
import {deleteShow, getShows, type Show, showTableHeader} from "@models/show/show.ts";
import {useShowTypeStore} from "@stores/showType.store.ts";
export function show_page() {
const items = ref([])
@ -14,16 +15,17 @@ export function show_page() {
'total_items': 0,
'page': 1,
})
const showType = ref(null);
const showTypeStore = useShowTypeStore();
const headers = showTableHeader
const getItems = async (options) => {
const showSearchOptions = {
page: options.page,
per_page: options.itemsPerPage,
page: options?.page,
per_page: options?.itemsPerPage,
all: search.value,
showType: showType.value,
showType: showTypeStore.currentType,
}
return getShows(showSearchOptions).then(showList => {
listData.itemsPerPage = showList.per_page;
@ -55,5 +57,5 @@ export function show_page() {
})
};
return {items, listData, headers, selected, loading, search, showType, getItems, editItem, deleteItem}
return {items, listData, headers, selected, loading, search, getItems, editItem, deleteItem}
}

View file

@ -4,6 +4,7 @@ import {timeFormatter} from "@/helpers/TimeFormatter.ts";
import {deleteSmartBlock, getSmartBlock, SmartBlockTableHeader} from "@models/smartblock/smartblock.ts";
import {showTableHeader} from "@models/show/show.ts";
import {useAuthStore} from "@/stores/auth.store.ts";
import {useShowTypeStore} from "@stores/showType.store.ts";
export function smartblock_page() {
const items = ref([])
@ -17,6 +18,7 @@ export function smartblock_page() {
'total_items': 0,
'page': 1,
})
const showTypeStore = useShowTypeStore();
const auth = useAuthStore();
const timezone = auth.userData.timezone;
@ -28,7 +30,8 @@ export function smartblock_page() {
return getSmartBlock({
page: options.page,
per_page: options.itemsPerPage,
all: search.value
all: search.value,
smartblockType: showTypeStore.currentType,
}).then((smartblockList) => {
console.log(smartblockList)
listData.itemsPerPage = smartblockList.per_page;

View file

@ -1,5 +1,6 @@
<script setup lang="ts">
import {computed, defineAsyncComponent, ref, watch} from 'vue';
import { useShowTypeStore } from '@/stores/showType.store';
// Props and data
const props = defineProps({
@ -8,8 +9,7 @@ const props = defineProps({
const currentPage = computed(() => props.page.id)
const showType = ref<'show' | 'spot' | null>(null)
const showTypeStore = useShowTypeStore();
/**
* ToDo:
*/
@ -27,13 +27,17 @@ const tabs = {
}
watch(currentPage, (newVal) => {
showType.value = null
const showTypes = ['show', 'playlist', 'blocks']
const spotTypes = ['spot', 'spot-playlist', 'spot-blocks']
switch (true) {
case newVal === 'show':
showType.value = 'show'
case showTypes.includes(newVal):
showTypeStore.setAsShows()
break
case ['spot', 'spot-playlist', 'spot-block'].some(item => newVal.includes(item)):
showType.value = 'spot'
case spotTypes.includes(newVal):
showTypeStore.setAsSpots()
break
default:
showTypeStore.clearType()
break
}
}, {immediate: true})
@ -42,9 +46,7 @@ watch(currentPage, (newVal) => {
<template>
<v-col>
<!-- <keep-alive>-->
<Component :is="tabs[currentPage]"
v-bind="showType ? { showType: showType } : {}"
/>
<Component :is="tabs[currentPage]" />
<!-- </keep-alive>-->
</v-col>
</template>

View file

@ -18,7 +18,7 @@ export const usePlaylistStore = defineStore('playlist', {
updateField(payload: { key: string; value: any }) {
this.currentPlaylist[payload.key] = payload.value
},
updatePlaylistContentsField(payload: { key: string; value: any }) {
updatePlaylistContentsField(pEayload: { key: string; value: any }) {
this.currentPlaylist.currentPlaylistContents[payload.key] = payload.value;
},
}

View file

@ -0,0 +1,32 @@
import {defineStore} from "pinia";
export type ShowType = 'show' | 'spot' | null;
export const useShowTypeStore = defineStore('showType', {
state: () => ({
type: null as ShowType,
}),
getters: {
// Returns the current type, useful for direct access
currentType: (state): ShowType => state.type,
// Returns a boolean, useful for v-if directives
isShowingShow: (state): boolean => state.type === 'show',
isShowingSpot: (state): boolean => state.type === 'spot',
hasActiveType: (state): boolean => state.type !== null,
},
actions: {
setShowType(newType: ShowType) {
this.type = newType;
},
setAsShows() {
this.type = 'show';
},
setAsSpots() {
this.type = 'spot';
},
clearType() {
this.type = null;
}
}
})