| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- <template>
- <div class="timeline">
- <div class="timelime-control">
- <h1>Planning global de l'événement</h1>
- <div class="actions">
- <button
- class="btn small secondary"
- @click="createCreneau"
- :disabled="creneauGroupList.length == 0"
- >
- <i class="material-icons">create</i>Creneau
- </button>
- <button class="btn small secondary" @click="createRessource">
- <i class="material-icons">create</i>Ligne
- </button>
- <button class="btn icon small primary tooltiped" aria-tooltip="Zoomer" @click="zoom(1)">
- <i class="material-icons">zoom_in</i>
- </button>
- <button class="btn icon small primary tooltiped" aria-tooltip="Dezoomer" @click="zoom(-1)">
- <i class="material-icons">zoom_out</i>
- </button>
- </div>
- </div>
- <jc-timeline
- ref="timeline"
- :slotduration="slotduration"
- :legendspan="legendspan"
- :slotwidth="slotwidth"
- :start="start.toDate().toISOString()"
- :end="end.toDate().toISOString()"
- @event-change="eventChangeHandler"
- @item-selected="selectionChangeHandler"
- @reorder-ressource="ressourceChangeHandler"
- ></jc-timeline>
- </div>
- <editeur-creneau
- class="planning"
- v-if="currentCreneau"
- :creneau="currentCreneau"
- @create="createCreneau"
- @delete="deleteCreneau"
- @duplicate="duplicateCreneau"
- @edit="updateCreneau"
- ></editeur-creneau>
- <editeur-ligne
- class="planning"
- v-else
- :creneauGroupId="currentCreneauGroupId"
- @create="createRessource"
- @delete="deleteRessource"
- @edit="updateCreneauGroup"
- ></editeur-ligne>
- </template>
- <script lang="ts">
- import { v4 as uuidv4 } from "uuid";
- import { defineComponent } from "vue";
- import Timeline from "jc-timeline/lib/Timeline";
- import { Event as jcEvent } from "jc-timeline/lib/Event";
- import EditeurCreneau from "@/components/EditeurCreneau.vue";
- import EditeurLigne from "@/components/EditeurCreneauGroup.vue";
- import { Ressource } from "jc-timeline";
- import Creneau from "@/models/Creneau";
- import { MutationTypes } from "@/store/Mutations";
- import Selectable from "node_modules/jc-timeline/lib/utils/selectable";
- import toast from "@/utils/Toast";
- import * as dayjs from "dayjs";
- import "dayjs/locale/fr";
- dayjs.locale("fr");
- type changePayload = {
- items: Array<jcEvent>;
- };
- export default defineComponent({
- name: "Planning",
- components: {
- EditeurCreneau,
- EditeurLigne,
- },
- data() {
- return {
- currentCreneau: undefined as Creneau | undefined,
- currentCreneauGroup: undefined as Ressource | undefined,
- zoomLevel: 14,
- slotduration: 30,
- legendspan: 2,
- slotwidth: 30,
- };
- },
- methods: {
- createCreneau(): void {
- // take the current crenau as reference if any
- const groupId = this.currentCreneau
- ? this.currentCreneau.ressourceId
- : // else the current row as reference if any
- this.currentCreneauGroup
- ? this.currentCreneauGroup.id
- : // else the first row as reference if any
- this.creneauList.length > 0
- ? this.creneauList[0].id
- : false;
- if (groupId) {
- const start = new Date(this.timeline.start);
- const e = this.timeline.addEvent(
- new jcEvent({
- id: uuidv4(),
- start: start,
- end: new Date(start.getTime() + 1000 * 60 * 60),
- ressourceId: groupId,
- title: "Nouveau creneau",
- })
- );
- if (e) {
- this.timeline.clearSelectedItems();
- e.selected = true;
- const creneau = new Creneau({
- event: e,
- penibility: 12,
- minAttendee: 1,
- maxAttendee: 1,
- benevoleIdList: [],
- competencesIdList: [],
- description: "",
- isMeal: false,
- fixedAttendee: false,
- });
- this.$store.commit(MutationTypes.addCreneau, creneau);
- this.currentCreneau = this.$store.getters.getCreneauById(creneau.id);
- this.currentCreneauGroup = undefined;
- }
- } else {
- toast({
- html:
- "Erreur: Pas de ligne auquel associer un nouveau creneau.<br>" +
- " Veuillez selectioné un créneau existant ou une ligne.",
- });
- }
- },
- createRessource(): void {
- const ressource = new Ressource({
- id: uuidv4(),
- title: "Nouvelle ligne",
- });
- this.$store.commit(MutationTypes.addCreneauGroupAt, { pos: 0, r: ressource });
- this.timeline.clearSelectedItems();
- this.timeline.addRessource(ressource).selected = true;
- this.currentCreneauGroup = ressource;
- },
- duplicateCreneau(payload: Creneau) {
- const newCreneau = new Creneau({
- ...payload.toJSON(),
- event: new jcEvent({ ...payload.event, id: uuidv4() }),
- });
- newCreneau.title = "Copy de " + newCreneau.title;
- this.timeline.addEvent(newCreneau.event);
- this.$store.commit(MutationTypes.addCreneau, newCreneau);
- this.currentCreneau = newCreneau;
- },
- deleteRessource(): void {
- if (this.currentCreneauGroup) {
- const contentRemoved = this.timeline.removeRessourceById(this.currentCreneauGroup.id);
- contentRemoved.ressources.map((r) =>
- this.$store.commit(MutationTypes.removeCreneauGroup, r)
- );
- contentRemoved.items.map((e) => {
- const crenenau = this.$store.getters.getCreneauById(e.id);
- if (crenenau) this.$store.commit(MutationTypes.removeCreneau, crenenau);
- });
- }
- },
- deleteCreneau(): void {
- if (this.currentCreneau) {
- this.timeline.removeEventById(this.currentCreneau.id);
- this.$store.commit(MutationTypes.removeCreneau, this.currentCreneau);
- }
- },
- selectionChangeHandler(ev: CustomEvent) {
- const elts = ev.detail.items as Array<Selectable>;
- if (elts.length == 1) {
- const item = elts[0];
- if (item instanceof Ressource) {
- this.currentCreneauGroup = item;
- this.currentCreneau = undefined;
- }
- if (item instanceof jcEvent) {
- this.currentCreneau = this.$store.getters.getCreneauById(item.id);
- this.currentCreneauGroup = undefined;
- }
- }
- if (elts.length == 0) {
- this.currentCreneau = undefined;
- this.currentCreneauGroup = undefined;
- }
- },
- eventChangeHandler(ev: CustomEvent<changePayload>) {
- this.currentCreneauGroup = undefined;
- const jcEvents = ev.detail.items;
- for (let index = 0; index < jcEvents.length; index++) {
- const element = jcEvents[index];
- this.$store.commit(MutationTypes.editCreneau, {
- id: element.id,
- field: "start",
- value: element.start,
- });
- this.$store.commit(MutationTypes.editCreneau, {
- id: element.id,
- field: "end",
- value: element.end,
- });
- this.$store.commit(MutationTypes.editCreneau, {
- id: element.id,
- field: "ressourceId",
- value: element.ressourceId,
- });
- this.currentCreneau = this.$store.getters.getCreneauById(element.id);
- }
- },
- ressourceChangeHandler(ev: CustomEvent<{ ressources: Array<Ressource> }>) {
- this.$store.commit(MutationTypes.reorderCreneauGroup, ev.detail.ressources);
- },
- updateCreneauGroup<K extends keyof Ressource>(payload: {
- id: string;
- field: K;
- value: Ressource[K];
- }) {
- const prevState = this.$store.getters.getCreneauGroupById(payload.id);
- if (prevState && prevState[payload.field] !== payload.value) {
- const r = this.timeline.updateRessource(payload.id, payload.field, payload.value);
- if (r) {
- payload.value = r[payload.field];
- }
- this.$store.commit(MutationTypes.editCreneauGroup, payload);
- }
- },
- updateCreneau<K extends keyof Creneau>(payload: { id: string; field: K; value: Creneau[K] }) {
- this.$store.commit(MutationTypes.editCreneau, payload);
- const creneau = this.$store.getters.getCreneauById(payload.id);
- if (creneau) {
- this.timeline.removeEventById(payload.id);
- this.timeline.addEvent(creneau.event);
- }
- },
- zoom(lvl: number) {
- const durations = [
- 10080,
- 10080,
- 10080,
- 10080,
- 10080,
- 1440,
- 1440,
- 720,
- 720,
- 360,
- 120,
- 60,
- 60,
- 60,
- 30,
- 30,
- 15,
- 5,
- ];
- const slotWidths = [40, 60, 80, 120, 160, 30, 40, 30, 50, 40, 25, 20, 30, 40, 30, 40, 35, 20];
- const legendSpans = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 4];
- this.zoomLevel += lvl;
- this.zoomLevel = Math.min(Math.max(0, this.zoomLevel), durations.length - 1);
- this.slotduration = durations[this.zoomLevel];
- this.slotwidth = slotWidths[this.zoomLevel];
- this.legendspan = legendSpans[this.zoomLevel];
- },
- },
- computed: {
- timeline(): Timeline {
- const output = this.$refs["timeline"];
- return output as Timeline;
- },
- currentCreneauGroupId(): string {
- return this.currentCreneauGroup ? this.currentCreneauGroup.id : "";
- },
- creneauList(): Array<Creneau> {
- return this.$store.state.creneauList;
- },
- eventList(): Array<jcEvent> {
- return this.creneauList.map((o) => o.event);
- },
- creneauGroupList(): Array<Ressource> {
- return this.$store.state.creneauGroupList;
- },
- start(): dayjs.Dayjs {
- return this.$store.state.evenement.startingDate;
- },
- end(): dayjs.Dayjs {
- return this.$store.state.evenement.endingDate;
- },
- },
- watch: {},
- mounted() {
- this.timeline.setAttribute("start", this.start.toISOString());
- this.timeline.setAttribute("end", this.end.toISOString());
- this.timeline.addRessources(this.creneauGroupList);
- this.timeline.addEvents(this.eventList);
- this.timeline.setLegendUnitFormat("d", "dddd D MMMM");
- this.timeline.customStyle = `.bubble{
- padding: 2px 4px;
- display: flex;
- justify-content: center;
- align-items: center;
- position: absolute;
- right: -5px;
- bottom: -5px;
- border-radius: 4px;
- font-size: 12px;
- font-weight: bold;
- z-index:1;
- background: #08875b;
- transform: translateX(50%);
- white-space: nowrap;
- }
- .bubble.red{
- background: #e4002b;
- }
- .bubble.orange{
- background: #fbca32;
- }`;
- this.timeline.clearSelectedItems();
- },
- });
- </script>
- <style lang="scss" scoped>
- .planning-container {
- display: flex;
- justify-content: center;
- }
- .timeline {
- margin: 0px 16px;
- width: 100%;
- }
- jc-timeline {
- margin-top: 8px;
- display: flex;
- flex-direction: column;
- height: calc(100vh - 13rem);
- }
- .actions {
- display: inline-flex;
- justify-content: left;
- margin-bottom: 12px;
- }
- .actions > .btn {
- margin-right: 4px;
- }
- </style>
|