|
|
@@ -2,7 +2,7 @@
|
|
|
<div class="timeline">
|
|
|
<div class="timelime-control">
|
|
|
<h1>Planning global de l'événement</h1>
|
|
|
- <div class="actions" @click="(e) => e.stopPropagation()">
|
|
|
+ <div class="actions" jc-timeline-keep-select>
|
|
|
<button
|
|
|
class="btn small secondary"
|
|
|
@click="createCreneau"
|
|
|
@@ -39,20 +39,22 @@
|
|
|
v-if="currentCreneau"
|
|
|
:creneau="currentCreneau"
|
|
|
@create="createCreneau"
|
|
|
- @delete="deleteCreneau"
|
|
|
+ @delete="deleteCurrentCreneau"
|
|
|
@duplicate="duplicateCreneau"
|
|
|
@edit="updateCreneau"
|
|
|
- @click="(e) => e.stopPropagation()"
|
|
|
+ jc-timeline-keep-select
|
|
|
></editeur-creneau>
|
|
|
<editeur-ligne
|
|
|
class="planning"
|
|
|
v-else
|
|
|
:creneauGroupId="currentCreneauGroupId"
|
|
|
@create="createRessource"
|
|
|
- @delete="deleteRessource"
|
|
|
+ @delete="deleteCurrentRessource"
|
|
|
+ @duplicate="duplicateCurrentRessource"
|
|
|
@edit="updateCreneauGroup"
|
|
|
- @click="(e) => e.stopPropagation()"
|
|
|
+ jc-timeline-keep-select
|
|
|
></editeur-ligne>
|
|
|
+ <context-menu :x="menuX" :y="menuY" :actions="contextActions" ref="menu" />
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts">
|
|
|
@@ -69,8 +71,9 @@ 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 from "dayjs";
|
|
|
import "dayjs/locale/fr";
|
|
|
+import ContextMenu, { MenuAction } from "@/components/ContextMenu.vue";
|
|
|
dayjs.locale("fr");
|
|
|
|
|
|
type changePayload = {
|
|
|
@@ -82,9 +85,14 @@ export default defineComponent({
|
|
|
components: {
|
|
|
EditeurCreneau,
|
|
|
EditeurLigne,
|
|
|
+ ContextMenu,
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
+ contextActions: [] as Array<MenuAction>,
|
|
|
+ menuX: 0,
|
|
|
+ menuY: 0,
|
|
|
+
|
|
|
currentCreneau: undefined as Creneau | undefined,
|
|
|
currentCreneauGroup: undefined as Ressource | undefined,
|
|
|
zoomLevel: 14,
|
|
|
@@ -107,34 +115,8 @@ export default defineComponent({
|
|
|
: 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;
|
|
|
- }
|
|
|
+ const end = new Date(start.getTime() + 1000 * 60 * 60);
|
|
|
+ this.registerCreneau(start, end, groupId);
|
|
|
} else {
|
|
|
toast({
|
|
|
html:
|
|
|
@@ -143,14 +125,47 @@ export default defineComponent({
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
+ registerCreneau(start: Date, end: Date, groupId: string): void {
|
|
|
+ const e = this.timeline.addEvent(
|
|
|
+ new jcEvent({
|
|
|
+ id: uuidv4(),
|
|
|
+ start: start,
|
|
|
+ end: end,
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ },
|
|
|
createRessource(): void {
|
|
|
const ressource = new Ressource({
|
|
|
id: uuidv4(),
|
|
|
title: "Nouvelle ligne",
|
|
|
});
|
|
|
- this.$store.commit(MutationTypes.addCreneauGroupAt, { pos: 0, r: ressource });
|
|
|
+ this.registerRessource(ressource);
|
|
|
+ },
|
|
|
+ registerRessource(ressource: Ressource, pos = 0) {
|
|
|
+ this.$store.commit(MutationTypes.addCreneauGroupAt, { pos, r: ressource });
|
|
|
this.timeline.clearSelectedItems();
|
|
|
- this.timeline.addRessource(ressource).selected = true;
|
|
|
+ this.timeline.addRessource(ressource, pos).selected = true;
|
|
|
this.currentCreneauGroup = ressource;
|
|
|
},
|
|
|
duplicateCreneau(payload: Creneau) {
|
|
|
@@ -158,28 +173,40 @@ export default defineComponent({
|
|
|
...payload.toJSON(),
|
|
|
event: new jcEvent({ ...payload.event, id: uuidv4() }),
|
|
|
});
|
|
|
- newCreneau.title = "Copy de " + newCreneau.title;
|
|
|
+ newCreneau.title = "Copie 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);
|
|
|
- });
|
|
|
- }
|
|
|
+ duplicateCurrentRessource() {
|
|
|
+ if (this.currentCreneauGroup) this.duplicateRessource(this.currentCreneauGroup);
|
|
|
},
|
|
|
- deleteCreneau(): void {
|
|
|
- if (this.currentCreneau) {
|
|
|
- this.timeline.removeEventById(this.currentCreneau.id);
|
|
|
- this.$store.commit(MutationTypes.removeCreneau, this.currentCreneau);
|
|
|
+ duplicateRessource(ressource: Ressource): void {
|
|
|
+ let newRessource = new Ressource({ ...ressource.toJSON(), id: uuidv4() });
|
|
|
+ if (ressource.parent) {
|
|
|
+ newRessource.parent = ressource.parent;
|
|
|
}
|
|
|
+ this.registerRessource(newRessource, this.creneauGroupList.indexOf(ressource) + 1);
|
|
|
+
|
|
|
+ this.timeline.updateRessource(newRessource.id, "title", "Copie de " + newRessource.title);
|
|
|
+ },
|
|
|
+ deleteRessource(ressource: Ressource): void {
|
|
|
+ const contentRemoved = this.timeline.removeRessourceById(ressource.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);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deleteCurrentRessource(): void {
|
|
|
+ if (this.currentCreneauGroup) this.deleteRessource(this.currentCreneauGroup);
|
|
|
+ },
|
|
|
+ deleteCreneau(creneau: Creneau) {
|
|
|
+ this.timeline.removeEventById(creneau.id);
|
|
|
+ this.$store.commit(MutationTypes.removeCreneau, creneau);
|
|
|
+ },
|
|
|
+ deleteCurrentCreneau(): void {
|
|
|
+ if (this.currentCreneau) this.deleteCreneau(this.currentCreneau);
|
|
|
},
|
|
|
selectionChangeHandler(ev: CustomEvent) {
|
|
|
const elts = ev.detail.items as Array<Selectable>;
|
|
|
@@ -278,6 +305,72 @@ export default defineComponent({
|
|
|
this.slotwidth = slotWidths[this.zoomLevel];
|
|
|
this.legendspan = legendSpans[this.zoomLevel];
|
|
|
},
|
|
|
+ openContextMenu(e: MouseEvent) {
|
|
|
+ e.preventDefault();
|
|
|
+ this.menuX = e.clientX;
|
|
|
+ this.menuY = e.clientY;
|
|
|
+ (this.$refs.menu as typeof ContextMenu).open();
|
|
|
+ },
|
|
|
+ rightclick(e: MouseEvent) {
|
|
|
+ if (this.timeline) {
|
|
|
+ const node = this.timeline.shadowRoot?.elementFromPoint(e.clientX, e.clientY);
|
|
|
+ if (node) {
|
|
|
+ if (node.className == "jc-timeslots" || node.className.includes("jc-slot")) {
|
|
|
+ const arr = this.timeline.shadowRoot
|
|
|
+ ?.elementsFromPoint(e.clientX, e.clientY)
|
|
|
+ .filter((o) => o.tagName == "TD");
|
|
|
+ if (arr) {
|
|
|
+ const slot = arr[0];
|
|
|
+ const startTime = dayjs(slot.getAttribute("start") as string);
|
|
|
+ const ressourceId = slot.parentElement?.getAttribute("ressourceid");
|
|
|
+ const endTime = startTime.add(this.slotduration, "m");
|
|
|
+ if (startTime.isValid() && ressourceId) {
|
|
|
+ const onClick = () => {
|
|
|
+ this.registerCreneau(startTime.toDate(), endTime.toDate(), ressourceId);
|
|
|
+ };
|
|
|
+ this.contextActions = [{ id: "1", onClick: onClick, name: "Inserer un créneau" }];
|
|
|
+ this.openContextMenu(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (
|
|
|
+ node.className.startsWith("jc-timeslot-") ||
|
|
|
+ node.classList.contains("jc-timeslot")
|
|
|
+ ) {
|
|
|
+ const timeslot = node.classList.contains("jc-timeslot") ? node : node.parentElement;
|
|
|
+ const creneau = this.$store.getters.getCreneauById(
|
|
|
+ timeslot?.getAttribute("eventid") ?? ""
|
|
|
+ );
|
|
|
+ if (creneau) {
|
|
|
+ this.contextActions = [
|
|
|
+ { id: "1", onClick: () => this.duplicateCreneau(creneau), name: "Dupliquer" },
|
|
|
+ { id: "2", onClick: () => this.deleteCreneau(creneau), name: "Supprimer" },
|
|
|
+ ];
|
|
|
+ this.openContextMenu(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (node.className.startsWith("jc-ressource")) {
|
|
|
+ const ressourceId = node.parentElement?.getAttribute("ressourceid");
|
|
|
+ const ressource = this.$store.getters.getCreneauGroupById(ressourceId ?? "");
|
|
|
+
|
|
|
+ if (ressource) {
|
|
|
+ const pos = this.creneauGroupList.indexOf(ressource);
|
|
|
+ const newRessource = (pos: number) => {
|
|
|
+ const r = new Ressource({ id: uuidv4(), title: "Nouvelle ligne" });
|
|
|
+ if (ressource.parent) r.parent = ressource.parent;
|
|
|
+ this.registerRessource(r, pos);
|
|
|
+ };
|
|
|
+ this.contextActions = [
|
|
|
+ { id: "1", onClick: () => this.duplicateRessource(ressource), name: "Dupliquer" },
|
|
|
+ { id: "2", onClick: () => newRessource(pos), name: "Inserer au dessus" },
|
|
|
+ { id: "3", onClick: () => newRessource(pos + 1), name: "Inserer dessous" },
|
|
|
+ { id: "4", onClick: () => this.deleteRessource(ressource), name: "Supprimer" },
|
|
|
+ ];
|
|
|
+ this.openContextMenu(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
},
|
|
|
computed: {
|
|
|
timeline(): Timeline {
|
|
|
@@ -333,6 +426,7 @@ export default defineComponent({
|
|
|
background: #fbca32;
|
|
|
}`;
|
|
|
this.timeline.clearSelectedItems();
|
|
|
+ this.timeline.addEventListener("contextmenu", this.rightclick);
|
|
|
},
|
|
|
});
|
|
|
</script>
|