fix(git): manual merging commit
This commit is contained in:
commit
a5785dcbe8
22 changed files with 844 additions and 40 deletions
|
@ -1,9 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import CalendarShowEvent from "@/components/content/partials/CalendarShowEvent.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {ref} from "vue";
|
||||
import {useAuthStore} from "@/stores/auth.store.ts";
|
||||
|
||||
const auth = useAuthStore();
|
||||
const userRole = auth.userData.user.role;
|
||||
|
||||
const editMode = ref(false);
|
||||
|
||||
const toggleEditMode = () => {
|
||||
editMode.value = !editMode.value;
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const navigateToCreateShow = () => {
|
||||
// TODO Change route to correct one
|
||||
router.push({name: 'CreateShow'});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>dashboard</div>
|
||||
<v-row class="ma-4 justify-space-around">
|
||||
<!-- TODO show only if user is Editor or admin-->
|
||||
<template v-if="userRole && (userRole == 'admin' || userRole == 'editor')">
|
||||
<v-btn color="primary" @click="navigateToCreateShow">Crea show</v-btn>
|
||||
<v-btn color="secondary" @click="toggleEditMode">{{ editMode ? 'Disabilita modifica calendario' : 'Abilita modifica calendario' }}</v-btn>
|
||||
</template>
|
||||
</v-row>
|
||||
<CalendarShowEvent :edit-mode="editMode"/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
139
resources/js/components/content/partials/CalendarShowEvent.vue
Normal file
139
resources/js/components/content/partials/CalendarShowEvent.vue
Normal file
|
@ -0,0 +1,139 @@
|
|||
<script setup lang="ts">
|
||||
import type {Ref} from 'vue';
|
||||
import type {ShowInstances} from "@models/show/showInstances";
|
||||
import type {ContextMenuType} from "@models/misc/contextMenu"
|
||||
import {type calendarShowEvent, calendarShowEventMenu} from "@models/misc/calendarShowEvent";
|
||||
|
||||
import {ref, computed, onMounted} from 'vue';
|
||||
import {getShowInstances} from "@models/show/showInstances";
|
||||
import ContextMenu from '@partials/ContextMenu.vue';
|
||||
|
||||
// Data
|
||||
const showInstances = ref<ShowInstances[]>([]);
|
||||
onMounted(async () => {
|
||||
showInstances.value = await getShowInstances({
|
||||
withShow: true,
|
||||
starts: `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}`,
|
||||
});
|
||||
});
|
||||
const shows: Ref<calendarShowEvent[]> = computed(() => {
|
||||
return showInstances.value.flatMap(showInstance => {
|
||||
return {
|
||||
showInstanceId: showInstance.id,
|
||||
title: showInstance.show.name,
|
||||
color: showInstance.show.color,
|
||||
start: new Date(showInstance.starts),
|
||||
end: new Date(showInstance.ends),
|
||||
timed: true
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const calendar = ref(null);
|
||||
const currentCalendarDate = ref(null);
|
||||
const selectedShowInstance = ref(null);
|
||||
const contextMenu = ref<ContextMenuType>({
|
||||
visible: false,
|
||||
position: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
},
|
||||
menu: calendarShowEventMenu
|
||||
});
|
||||
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Funcs
|
||||
const openContextMenu = (showInstance: Record<string, unknown>, browserEvent: MouseEvent) => {
|
||||
if (!props.editMode) return;
|
||||
|
||||
selectedShowInstance.value = showInstance;
|
||||
contextMenu.value.visible = true;
|
||||
contextMenu.value.position.top = browserEvent.y;
|
||||
contextMenu.value.position.left = browserEvent.x + 5;
|
||||
};
|
||||
|
||||
const hideContextMenu = () => {
|
||||
contextMenu.value.visible = false;
|
||||
};
|
||||
|
||||
|
||||
const contextMenuAction = (action: string) => {
|
||||
if (!selectedShowInstance.value) return;
|
||||
|
||||
switch (action) {
|
||||
case 'contextMenuEditInstance':
|
||||
console.log('Edit instance', selectedShowInstance.value);
|
||||
// Add logic to edit the instance here
|
||||
break;
|
||||
case 'contextMenuEditShow':
|
||||
console.log('Edit show', selectedShowInstance.value);
|
||||
// Add logic to edit the show here
|
||||
break;
|
||||
case 'contextMenuDeleteInstance':
|
||||
console.log('Delete instance', selectedShowInstance.value);
|
||||
// Add logic to delete the instance here
|
||||
break;
|
||||
case 'contextMenuDeleteShow':
|
||||
console.log('Delete show', selectedShowInstance.value);
|
||||
// Add logic to delete the show here
|
||||
break;
|
||||
default:
|
||||
console.log('Unknown action:', action);
|
||||
break;
|
||||
}
|
||||
|
||||
contextMenu.value.visible = false;
|
||||
};
|
||||
|
||||
const formatTime = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-calendar
|
||||
ref="calendar"
|
||||
v-model="currentCalendarDate"
|
||||
:events="shows"
|
||||
:event-margin-bottom="3"
|
||||
@contextmenu:event="openContextMenu"
|
||||
>
|
||||
<template v-slot:event="{ event }">
|
||||
<div
|
||||
class="v-event mx-1 event-content"
|
||||
:style="{ backgroundColor: event.color as string }"
|
||||
@click="(e) => openContextMenu(event, e)"
|
||||
@click.self="hideContextMenu"
|
||||
>
|
||||
<span>{{ event.title }}</span>
|
||||
<br/>
|
||||
<span>{{ formatTime(event.start as string) }} - {{ formatTime(event.end as string) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</v-calendar>
|
||||
|
||||
<ContextMenu v-if="contextMenu.visible" @contextMenuAction="contextMenuAction" :event="selectedShowInstance"
|
||||
:menu="contextMenu.menu" :top="contextMenu.position.top" :left="contextMenu.position.left"/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.event-content {
|
||||
position: relative;
|
||||
white-space: normal;
|
||||
line-height: 1.2;
|
||||
padding: 4px 8px;
|
||||
background-color: #7492b9;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
68
resources/js/components/content/partials/ContextMenu.vue
Normal file
68
resources/js/components/content/partials/ContextMenu.vue
Normal file
|
@ -0,0 +1,68 @@
|
|||
<script setup lang="ts">
|
||||
import type {ContextMenu} from "@models/misc/contextMenu.ts";
|
||||
import {menuEntryWithAction, menuEntryWithChildren} from "@models/misc/contextMenu.ts";
|
||||
|
||||
import {type PropType} from 'vue';
|
||||
|
||||
const emit = defineEmits(['click']);
|
||||
|
||||
const props = defineProps({
|
||||
top: {
|
||||
type: Number,
|
||||
},
|
||||
left: {
|
||||
type: Number,
|
||||
},
|
||||
menu: {
|
||||
type: Object as PropType<ContextMenu>,
|
||||
}
|
||||
});
|
||||
|
||||
function triggerAction(item: string) {
|
||||
console.log(item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
class="mx-auto context-menu"
|
||||
width="200"
|
||||
ref="menuRef"
|
||||
:style="{ top: `${props.top}px`, left: `${props.left}px` }"
|
||||
>
|
||||
<v-list>
|
||||
<template v-for="(entry, i) in menu.entries">
|
||||
<v-list-group
|
||||
v-if="menuEntryWithChildren(entry) && entry.children"
|
||||
:value="i"
|
||||
>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-list-item v-bind="props" :title=entry.menuText></v-list-item>
|
||||
</template>
|
||||
<v-list-item
|
||||
v-for="(child, j) in entry.children"
|
||||
:key="j"
|
||||
@click="triggerAction(child.actionTrigger)"
|
||||
:title="child.menuText"
|
||||
></v-list-item>
|
||||
</v-list-group>
|
||||
|
||||
<!-- Render children if any -->
|
||||
<v-list-item
|
||||
v-else-if="menuEntryWithAction(entry)"
|
||||
link
|
||||
@click="triggerAction(entry.actionTrigger)"
|
||||
>
|
||||
<v-list-item-title>{{ entry.menuText }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.context-menu {
|
||||
position: absolute;
|
||||
width: 200px
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,7 @@
|
|||
import {computed, ref} from "vue";
|
||||
import draggable from "vuedraggable";
|
||||
draggable.compatConfig = { MODE: 3 };
|
||||
import DataTableRowHandler from "@/components/content/partials/table/DataTableRowHandler.vue";
|
||||
//import DataTableRowHandler from "@/components/content/partials/table/DataTableRowHandler.vue";
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:search',
|
||||
|
|
|
@ -16,13 +16,13 @@ export function archive_page() {
|
|||
|
||||
const headers = [
|
||||
// {title: '', key: 'artwork'},
|
||||
{title: 'Track title', value: 'track_title'},
|
||||
{title: 'Artist', value: 'artist_name'},
|
||||
{title: 'Genre', value: 'genre'},
|
||||
{title: 'Track Type', value: 'track_type'},
|
||||
{title: 'Length', value: 'length'},
|
||||
{title: 'Uploaded', value: 'mtime'},
|
||||
{title: 'Actions', key: 'actions'}
|
||||
{title: 'Titolo', value: 'track_title'},
|
||||
{title: 'Artista', value: 'artist_name'},
|
||||
{title: 'Genere', value: 'genre'},
|
||||
{title: 'Tipologia', value: 'track_type'},
|
||||
{title: 'Durata', value: 'length'},
|
||||
{title: 'Caricato il', value: 'mtime'},
|
||||
{title: 'Azioni', value: 'actions'}
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ export function archive_page() {
|
|||
all: search.value
|
||||
}
|
||||
}).then((response) => {
|
||||
console.log(response)
|
||||
//console.log(response)
|
||||
listData.itemsPerPage = response.data.per_page;
|
||||
listData.first_page = response.data.from;
|
||||
listData.last_page = response.data.last_page;
|
||||
|
|
17
resources/js/composables/content/dashboard_page.ts
Normal file
17
resources/js/composables/content/dashboard_page.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import {ref, reactive} from "vue";
|
||||
|
||||
export function archive_page() {
|
||||
const items = ref([])
|
||||
const selected = ref([])
|
||||
const loading = ref(false)
|
||||
const search = ref('')
|
||||
const listData = reactive({
|
||||
'itemsPerPage': 5,
|
||||
'first_page': null,
|
||||
'last_page': null,
|
||||
'total_items': 0,
|
||||
'page': 1,
|
||||
})
|
||||
|
||||
return { items, listData, selected, loading, search }
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import type {ContextMenu} from "@models/misc/contextMenu"
|
||||
|
||||
export interface calendarShowEvent {
|
||||
showInstanceId: Number,
|
||||
title: string,
|
||||
color: string,
|
||||
start: Date,
|
||||
end: Date
|
||||
timed: boolean,
|
||||
}
|
||||
|
||||
export const calendarShowEventMenu: ContextMenu = {
|
||||
entries: [
|
||||
{
|
||||
expanded: false,
|
||||
menuText: 'Edit',
|
||||
children: [
|
||||
{
|
||||
menuText: 'Edit instance',
|
||||
actionTrigger: 'contextMenuEditInstance'
|
||||
},
|
||||
{
|
||||
menuText: 'Edit show',
|
||||
actionTrigger: 'contextMenuEditShow'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
expanded: false,
|
||||
menuText: 'Delete',
|
||||
children: [
|
||||
{
|
||||
menuText: 'Delete instance',
|
||||
actionTrigger: 'contextMenuDeleteInstance'
|
||||
},
|
||||
{
|
||||
menuText: 'Delete show',
|
||||
actionTrigger: 'contextMenuDeleteShow'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
34
resources/js/composables/content/models/misc/contextMenu.ts
Normal file
34
resources/js/composables/content/models/misc/contextMenu.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
export interface ContextMenuType {
|
||||
visible: boolean;
|
||||
position: {
|
||||
top: number;
|
||||
left: number;
|
||||
};
|
||||
menu: ContextMenu
|
||||
}
|
||||
|
||||
export interface ContextMenu {
|
||||
entries: ContextMenuEntry[];
|
||||
}
|
||||
|
||||
interface ContextMenuEntryWithAction {
|
||||
menuText: string;
|
||||
actionTrigger: string;
|
||||
}
|
||||
|
||||
interface ContextMenuEntryWithChildren {
|
||||
expanded: boolean;
|
||||
menuText: string;
|
||||
children: ContextMenuEntry[];
|
||||
}
|
||||
|
||||
type ContextMenuEntry = ContextMenuEntryWithAction | ContextMenuEntryWithChildren;
|
||||
|
||||
export function menuEntryWithAction(entry: ContextMenuEntry): entry is ContextMenuEntryWithAction {
|
||||
return 'actionTrigger' in entry;
|
||||
}
|
||||
|
||||
export function menuEntryWithChildren(entry: ContextMenuEntry): entry is ContextMenuEntryWithChildren {
|
||||
return 'children' in entry;
|
||||
}
|
||||
|
82
resources/js/composables/content/models/show/schedule.ts
Normal file
82
resources/js/composables/content/models/show/schedule.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { VSelect, VTextField } from "vuetify/components";
|
||||
|
||||
interface Schedule {
|
||||
id?: number;
|
||||
starts: string; // ISO datetime string
|
||||
ends: string; // ISO datetime string
|
||||
clipLength: number; // Length in seconds or appropriate unit
|
||||
fadeIn: number; // Fade-in duration in seconds
|
||||
fadeOut: number; // Fade-out duration in seconds
|
||||
cueIn: string; // Cue-in point (HH:MM:SS or similar format)
|
||||
cueOut: string; // Cue-out point (HH:MM:SS or similar format)
|
||||
mediaItemPlayed: boolean; // Indicates if media item has been played
|
||||
playoutStatus: string; // Status of the playout (e.g., 'pending', 'completed')
|
||||
broadcasted: boolean; // Indicates if it has been broadcasted
|
||||
position: number; // Position in the schedule
|
||||
fileId: number; // Reference to File ID
|
||||
instanceId: number; // Reference to ShowInstances ID
|
||||
|
||||
// Relationships
|
||||
file?: File; // Reference to File interface
|
||||
showInstance?: ShowInstances; // Reference to ShowInstances interface
|
||||
}
|
||||
|
||||
export function scheduleForm(item: Schedule) {
|
||||
const visibleFields = {
|
||||
starts: 'Inizio',
|
||||
ends: 'Fine',
|
||||
clipLength: 'Lunghezza clip (s)',
|
||||
fadeIn: 'Fade-in (s)',
|
||||
fadeOut: 'Fade-out (s)',
|
||||
cueIn: 'Cue in',
|
||||
cueOut: 'Cue out',
|
||||
mediaItemPlayed: 'Media riprodotto',
|
||||
playoutStatus: 'Stato playout',
|
||||
broadcasted: 'Trasmissione completata',
|
||||
position: 'Posizione',
|
||||
fileId: 'File',
|
||||
instanceId: 'Istanza programma'
|
||||
};
|
||||
|
||||
return () => {
|
||||
const fields = {};
|
||||
Object.keys(visibleFields).forEach((key) => {
|
||||
fields[key] = {
|
||||
label: visibleFields[key],
|
||||
value: item[key as keyof Schedule],
|
||||
component: VTextField,
|
||||
disabled: false
|
||||
};
|
||||
|
||||
switch (key) {
|
||||
case 'starts':
|
||||
case 'ends':
|
||||
fields[key].props = {
|
||||
type: 'datetime-local',
|
||||
step: 300 // 5-minute increments for practical scheduling
|
||||
};
|
||||
break;
|
||||
case 'mediaItemPlayed':
|
||||
case 'broadcasted':
|
||||
fields[key].component = VSelect;
|
||||
fields[key].props = {
|
||||
items: [
|
||||
{ text: 'Sì', value: true },
|
||||
{ text: 'No', value: false }
|
||||
]
|
||||
};
|
||||
break;
|
||||
case 'fileId':
|
||||
fields[key].value = item.file?.name || '';
|
||||
fields[key].disabled = true;
|
||||
break;
|
||||
case 'instanceId':
|
||||
fields[key].value = item.showInstance?.id || ''; // Assuming you want to show instance ID or name
|
||||
fields[key].disabled = true;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
};
|
||||
}
|
117
resources/js/composables/content/models/show/show.ts
Normal file
117
resources/js/composables/content/models/show/show.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
import { VSelect, VTextarea, VTextField } from "vuetify/components";
|
||||
import type {ShowInstances} from "@models/show/showInstances";
|
||||
import type {ShowDays} from "@models/show/showDays.ts";
|
||||
import type {ShowDjs} from "@models/show/showDjs.ts";
|
||||
import axios, {type AxiosResponse} from "axios";
|
||||
|
||||
|
||||
export interface Show {
|
||||
id?: number;
|
||||
name: string;
|
||||
url: string;
|
||||
genre: string;
|
||||
description: string;
|
||||
color: string;
|
||||
backgroundColor: string;
|
||||
liveStreamUsingAirtimeAuth: boolean;
|
||||
liveStreamUsingCustomAuth: boolean;
|
||||
liveStreamUser?: string;
|
||||
liveStreamPass?: string;
|
||||
imagePath?: string;
|
||||
hasAutoplaylist: boolean;
|
||||
autoplaylistId?: number;
|
||||
autoplaylistRepeat: boolean;
|
||||
|
||||
// Relationships
|
||||
block?: any;
|
||||
showDays?: ShowDays[];
|
||||
showDjs?: ShowDjs[];
|
||||
showInstances?: ShowInstances[];
|
||||
playlist?: any;
|
||||
}
|
||||
|
||||
export function showForm(item: Show) {
|
||||
const visibleFields = {
|
||||
name: 'Nome',
|
||||
url: 'URL',
|
||||
genre: 'Genere',
|
||||
description: 'Descrizione',
|
||||
color: 'Colore',
|
||||
backgroundColor: 'Colore di sfondo',
|
||||
liveStreamUsingAirtimeAuth: 'Autenticazione Airtime',
|
||||
liveStreamUsingCustomAuth: 'Autenticazione personalizzata',
|
||||
liveStreamUser: 'Utente di streaming',
|
||||
liveStreamPass: 'Password di streaming',
|
||||
linked: 'Collegato',
|
||||
isLinkable: 'Collegabile',
|
||||
imagePath: 'Percorso immagine',
|
||||
hasAutoplaylist: 'Ha playlist automatica',
|
||||
autoplaylistId: 'ID Playlist automatica',
|
||||
autoplaylistRepeat: 'Ripeti playlist automatica'
|
||||
};
|
||||
|
||||
return () => {
|
||||
const fields = {};
|
||||
Object.keys(visibleFields).forEach((key) => {
|
||||
fields[key] = {
|
||||
label: visibleFields[key],
|
||||
value: item[key as keyof Show],
|
||||
component: VTextField,
|
||||
disabled: false
|
||||
};
|
||||
|
||||
switch (key) {
|
||||
case 'liveStreamUsingAirtimeAuth':
|
||||
case 'liveStreamUsingCustomAuth':
|
||||
case 'linked':
|
||||
case 'isLinkable':
|
||||
case 'hasAutoplaylist':
|
||||
fields[key].component = VSelect;
|
||||
fields[key].props = {
|
||||
items: [
|
||||
{ text: 'Sì', value: true },
|
||||
{ text: 'No', value: false }
|
||||
]
|
||||
};
|
||||
break;
|
||||
|
||||
case 'description':
|
||||
fields[key].component = VTextarea;
|
||||
break;
|
||||
|
||||
case 'autoplaylistId':
|
||||
// Optional handling if you have a way to fetch or display playlist names
|
||||
fields[key].props = {
|
||||
items: [], // Populate this with actual playlist options if available
|
||||
labelKey: 'name', // Assuming playlists have a name property
|
||||
valueKey: 'id'
|
||||
};
|
||||
break;
|
||||
|
||||
case 'imagePath':
|
||||
fields[key].props = { type: 'file' }; // If you want to upload an image file
|
||||
break;
|
||||
|
||||
default:
|
||||
// For other fields, keep as text field by default
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
};
|
||||
}
|
||||
|
||||
export async function getShows(scheduled = null , dateRangeScheduledStart = "", dateRangeScheduledEnd = "") {
|
||||
return await axios.get(`/show`, {
|
||||
params: {
|
||||
scheduled: scheduled,
|
||||
dateRangeScheduledStart: dateRangeScheduledStart,
|
||||
dateRangeScheduledEnd: dateRangeScheduledEnd,
|
||||
}
|
||||
}).then((response: AxiosResponse) => {
|
||||
return response.data
|
||||
}).catch((error: Error) => {
|
||||
console.log("Error: "+ error);
|
||||
})
|
||||
}
|
68
resources/js/composables/content/models/show/showDays.ts
Normal file
68
resources/js/composables/content/models/show/showDays.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { VSelect, VTextField } from "vuetify/components";
|
||||
import type {Show} from "@models/show/show";
|
||||
|
||||
export interface ShowDays {
|
||||
id?: number;
|
||||
firstShow: string; // Date string (ISO format)
|
||||
lastShow: string; // Date string (ISO format)
|
||||
startTime: string; // DateTime string (ISO format)
|
||||
timezone: string;
|
||||
duration: string; // Stored as string but could represent time
|
||||
day: number; // Assuming 0-6 for days of week
|
||||
repeatType: number; // Numerical representation of repeat type
|
||||
nextPopDate: string; // Date string (ISO format)
|
||||
showId: number;
|
||||
record: number; // 0 or 1 for boolean-like values
|
||||
|
||||
// Relationships
|
||||
show?: Show; // Reference to parent Show
|
||||
}
|
||||
|
||||
export function showDaysForm(item: ShowDays) {
|
||||
const visibleFields = {
|
||||
firstShow: 'Prima data',
|
||||
lastShow: 'Ultima data',
|
||||
startTime: 'Ora inizio',
|
||||
timezone: 'Fuso orario',
|
||||
duration: 'Durata',
|
||||
day: 'Giorno',
|
||||
repeatType: 'Tipo ripetizione',
|
||||
nextPopDate: 'Prossima data',
|
||||
record: 'Registrazione'
|
||||
};
|
||||
|
||||
return () => {
|
||||
const fields = {};
|
||||
Object.keys(visibleFields).forEach((key) => {
|
||||
fields[key] = {
|
||||
label: visibleFields[key],
|
||||
value: item[key as keyof ShowDays],
|
||||
component: VTextField,
|
||||
disabled: false
|
||||
};
|
||||
|
||||
switch (key) {
|
||||
case 'day':
|
||||
case 'repeatType':
|
||||
case 'record':
|
||||
fields[key].component = VSelect;
|
||||
// Add options if you have predefined values
|
||||
// fields[key].props = { items: daysOfWeekOptions };
|
||||
break;
|
||||
case 'startTime':
|
||||
// Optional: Add time picker props
|
||||
fields[key].props = { type: 'time' };
|
||||
break;
|
||||
case 'firstShow':
|
||||
case 'lastShow':
|
||||
case 'nextPopDate':
|
||||
// Optional: Add date picker props
|
||||
fields[key].props = { type: 'date' };
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
};
|
||||
}
|
||||
|
44
resources/js/composables/content/models/show/showDjs.ts
Normal file
44
resources/js/composables/content/models/show/showDjs.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { VTextField } from "vuetify/components";
|
||||
|
||||
export interface ShowDjs {
|
||||
id?: number;
|
||||
subjsId: number;
|
||||
showId: number;
|
||||
|
||||
dj?: User;
|
||||
}
|
||||
|
||||
// Assuming User interface exists
|
||||
export interface User {
|
||||
id: number;
|
||||
login: string;
|
||||
}
|
||||
|
||||
export function showDjsForm(item: ShowDjs) {
|
||||
const visibleFields = {
|
||||
subjsId: 'Presentatore',
|
||||
showId: 'Programma'
|
||||
};
|
||||
|
||||
return () => {
|
||||
const fields = {};
|
||||
Object.keys(visibleFields).forEach((key) => {
|
||||
fields[key] = {
|
||||
label: visibleFields[key],
|
||||
value: item[key as keyof ShowDjs],
|
||||
component: VTextField,
|
||||
disabled: false
|
||||
};
|
||||
|
||||
switch (key) {
|
||||
case 'subjsId':
|
||||
fields[key].disabled = true;
|
||||
break;
|
||||
case 'showId':
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
};
|
||||
}
|
101
resources/js/composables/content/models/show/showInstances.ts
Normal file
101
resources/js/composables/content/models/show/showInstances.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
import {VSelect, VTextField} from "vuetify/components";
|
||||
import type {Show} from "@models/show/show";
|
||||
import axios, {type AxiosResponse} from "axios";
|
||||
|
||||
export interface ShowInstances {
|
||||
id?: number;
|
||||
starts: string; // ISO datetime string
|
||||
ends: string; // ISO datetime string
|
||||
showId: number;
|
||||
record: number; // 0|1 or similar
|
||||
rebroadcast: number; // 0|1 or similar
|
||||
timeFilled: string; // Duration format (HH:MM:SS)
|
||||
created?: string; // ISO datetime string (optional)
|
||||
modifiedInstance: boolean;
|
||||
autoplaylistBuilt: boolean;
|
||||
|
||||
// Relationships
|
||||
Playlist?: any; // Assuming File interface exists
|
||||
show?: Show; // Reference to Show interface
|
||||
}
|
||||
|
||||
export function showInstancesForm(item: ShowInstances) {
|
||||
const visibleFields = {
|
||||
starts: 'Inizio',
|
||||
ends: 'Fine',
|
||||
showId: 'Programma',
|
||||
record: 'Registrazione',
|
||||
rebroadcast: 'Ritrasmissione',
|
||||
timeFilled: 'Durata riempita',
|
||||
modifiedInstance: 'Istanza modificata',
|
||||
autoplaylistBuilt: 'Autoplaylist generata'
|
||||
};
|
||||
|
||||
return () => {
|
||||
const fields = {};
|
||||
Object.keys(visibleFields).forEach((key) => {
|
||||
fields[key] = {
|
||||
label: visibleFields[key],
|
||||
value: item[key as keyof ShowInstances],
|
||||
component: VTextField,
|
||||
disabled: false
|
||||
};
|
||||
|
||||
switch (key) {
|
||||
case 'starts':
|
||||
case 'ends':
|
||||
fields[key].props = {
|
||||
type: 'datetime-local',
|
||||
step: 300 // 5-minute increments
|
||||
};
|
||||
break;
|
||||
case 'modifiedInstance':
|
||||
case 'autoplaylistBuilt':
|
||||
fields[key].component = VSelect;
|
||||
fields[key].props = {
|
||||
items: [
|
||||
{text: 'Sì', value: true},
|
||||
{text: 'No', value: false}
|
||||
]
|
||||
};
|
||||
break;
|
||||
case 'record':
|
||||
case 'rebroadcast':
|
||||
fields[key].component = VSelect;
|
||||
fields[key].props = {
|
||||
items: [
|
||||
{text: 'Sì', value: 1},
|
||||
{text: 'No', value: 0}
|
||||
]
|
||||
};
|
||||
break;
|
||||
case 'showId':
|
||||
fields[key].value = item.show?.name || '';
|
||||
fields[key].disabled = true;
|
||||
break;
|
||||
case 'timeFilled':
|
||||
fields[key].props = {type: 'time'};
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
};
|
||||
}
|
||||
|
||||
export async function getShowInstances(options: {
|
||||
showId?: number | null;
|
||||
starts?: string | null;
|
||||
ends?: string | null;
|
||||
withShow?: boolean | null;
|
||||
}): Promise<ShowInstances[]> {
|
||||
const filteredParams = Object.fromEntries(
|
||||
Object.entries(options).filter(([_, value]) => value !== undefined && value !== null)
|
||||
);
|
||||
|
||||
return await axios.get(`/showInstances`, { params: filteredParams }).then((response: AxiosResponse) => {
|
||||
return response.data
|
||||
}).catch((error: Error) => {
|
||||
console.log("Error: " + error);
|
||||
});
|
||||
}
|
|
@ -2,8 +2,9 @@
|
|||
import "vuetify/styles";
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import {createVuetify, type ThemeDefinition} from "vuetify";
|
||||
import * as components from "vuetify/components";
|
||||
import * as baseComponents from "vuetify/components";
|
||||
import * as directives from "vuetify/directives";
|
||||
import { VCalendar } from 'vuetify/labs/VCalendar'
|
||||
|
||||
/**
|
||||
* Example of custom Theme
|
||||
|
@ -38,7 +39,10 @@ const customTheme: ThemeDefinition = {
|
|||
};
|
||||
|
||||
const vuetify = createVuetify({
|
||||
components,
|
||||
components: {
|
||||
...baseComponents,
|
||||
VCalendar,
|
||||
},
|
||||
directives,
|
||||
theme: {
|
||||
defaultTheme: 'customTheme',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue