1067 lines
30 KiB
Vue
1067 lines
30 KiB
Vue
<template>
|
|
<div class="plannings">
|
|
<div class="row justify-content-center">
|
|
<div class="col-1 text-center actions_col">
|
|
<a
|
|
class="sticky-top btn btn-primary mt-5"
|
|
@click.prevent="goToPlanning(false)"
|
|
>
|
|
<FontAwesomeIcon icon="text-white fa-solid fa-arrow-left-long" />
|
|
</a>
|
|
</div>
|
|
|
|
<div class="col-11">
|
|
<table class="table table-bordered align-middle text-center schedules_table">
|
|
<thead>
|
|
<tr>
|
|
<th rowspan="2" />
|
|
<th
|
|
:colspan="showWeekends ? 7 : 5"
|
|
v-for="item in weeksCells"
|
|
class="Mon Fri"
|
|
:key="item.num"
|
|
>
|
|
S {{ item.num }} - {{ item.month }} {{ item.year }}
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
<th
|
|
v-for="day in days"
|
|
:class="`day${day.eday}`"
|
|
:key="day.num"
|
|
>
|
|
{{ day.day }} {{ day.num }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<template v-for="(user, index) in schedules">
|
|
<tr
|
|
v-for="(slot, key) in user"
|
|
:key="`${String(index)} ${String(key)}`"
|
|
>
|
|
<td
|
|
:rowspan="daySlots"
|
|
class="resource_ident"
|
|
v-if="key == 1"
|
|
>
|
|
{{ String(users[index].name) }}
|
|
</td>
|
|
<td
|
|
v-for="day in days"
|
|
:class="'dynCell day bg-transparent ' + String(user[key][day.key as any].type.name) + ' ' + day.eday"
|
|
:key="day.key"
|
|
>
|
|
<div
|
|
:class="
|
|
'cellsizer ' +
|
|
(user[key][day.key as any].type.name
|
|
? String(user[key][day.key as any].type.name)
|
|
: 'empty')
|
|
|
|
"
|
|
>
|
|
<a
|
|
target="_blank"
|
|
class="text-decoration-none"
|
|
:href="String(getCellObjectInfo(user[key][day.key as any])?.url)"
|
|
>
|
|
<button
|
|
v-if="user[key][day.key as any]['model_lie']['value']"
|
|
class="btn-text position-relative top-0 start-0 btn bg-dark w-fit mw-100 h-auto overflow-hidden text-capitalize text-white opacity-100 p-0 px-1"
|
|
>
|
|
{{
|
|
String(user[key][day.key as any]["id_lie"]["label"])
|
|
}}
|
|
</button>
|
|
</a>
|
|
<br>
|
|
{{ String(user[key][day.key as any]["text"]) }}
|
|
<button
|
|
class="btn btn-edit text-white"
|
|
type="button"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#editModal"
|
|
@click.prevent="
|
|
setModalData(
|
|
index,
|
|
key,
|
|
day.key,
|
|
user[key][day.key as any]['id']
|
|
)
|
|
"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-pen" />
|
|
</button>
|
|
<button
|
|
:class="'btn btn-paste text-white ' + (!clipBoard.set ? 'hide' : '')"
|
|
type="button"
|
|
@click.prevent="
|
|
pasteCell(
|
|
index,
|
|
key,
|
|
day.key,
|
|
user[key][day.key as any]['id']
|
|
)
|
|
"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-clipboard" />
|
|
</button>
|
|
<button
|
|
class="btn btn-copy text-white"
|
|
type="button"
|
|
@click.prevent="
|
|
copyCell(
|
|
index,
|
|
key,
|
|
day.key,
|
|
user[key][day.key as any]['id']
|
|
)
|
|
"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-copy" />
|
|
</button>
|
|
<button
|
|
:class="
|
|
'btn btn-clear text-white ' + (!user[key][day.key as any]['id'] ? 'hide' : '')
|
|
"
|
|
@click.prevent="
|
|
eraseCell(
|
|
index,
|
|
key,
|
|
day.key,
|
|
user[key][day.key as any]['id']
|
|
)
|
|
"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-eraser" />
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="col-1 text-center actions_col">
|
|
<a
|
|
class="sticky-top btn btn-primary mt-5"
|
|
@click="goToPlanning(true)"
|
|
>
|
|
<FontAwesomeIcon icon="text-white fa-solid fa-arrow-right-long" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<!-- Modal -->
|
|
<div
|
|
class="modal fade"
|
|
id="editModal"
|
|
tabindex="-1"
|
|
aria-labelledby="modalLabel"
|
|
aria-hidden="true"
|
|
>
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5
|
|
class="modal-title"
|
|
id="modalLabel"
|
|
ref="modalLabel"
|
|
>
|
|
{{ (String(modale.id) === "Nouveau") ? __('Création d\'une tâche') : __('Édition d\'une tâche') }}
|
|
</h5>
|
|
<button
|
|
ref="close"
|
|
type="button"
|
|
class="btn btn-sm btn-primary bg-primary"
|
|
data-bs-dismiss="modal"
|
|
aria-label="Close"
|
|
>
|
|
<FontAwesomeIcon icon="text-white fa-solid fa-xmark" />
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="container">
|
|
<div class="row justify-content-center">
|
|
<div
|
|
v-if="error"
|
|
class="alert alert-danger"
|
|
role="alert"
|
|
>
|
|
{{ error }}
|
|
</div>
|
|
<div class="col-8">
|
|
<div class="form-group mb-3">
|
|
<label
|
|
for="categorie"
|
|
class="col-form-label text-md-right ms-5"
|
|
>
|
|
{{ __('Categorie') }}
|
|
</label>
|
|
<select
|
|
id="categorie"
|
|
ref="type"
|
|
class="form-select"
|
|
aria-label="Sélectionnez une catégorie"
|
|
>
|
|
<option value="">
|
|
{{ __('Sélectionnez une catégorie') }}
|
|
</option>
|
|
<option
|
|
v-for="(activity, index) of activities"
|
|
:key="index"
|
|
:value="activity.value"
|
|
:selected="modale.activity.name == activity.name"
|
|
:class="activity.value"
|
|
>
|
|
{{ String(activity.label) }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mb-3">
|
|
<label
|
|
for="morph"
|
|
class="col-form-label text-md-right ms-5"
|
|
>
|
|
{{ __('Type d\'élément lié') }}
|
|
</label>
|
|
<select
|
|
id="morph"
|
|
ref="morph"
|
|
class="form-select"
|
|
@change="selectChange"
|
|
aria-label="Sélectionnez un élément à lier"
|
|
>
|
|
<option value="">
|
|
{{ __('Sélectionnez un type d\'objet à lier') }}
|
|
</option>
|
|
<option
|
|
v-for="(model, index) of models"
|
|
:key="index"
|
|
:value="model.value"
|
|
:selected="modale.model_lie.value == model.value"
|
|
>
|
|
{{ String(model.label) }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div
|
|
class="form-group mb-3"
|
|
v-if="modale.dDisplay"
|
|
>
|
|
<label
|
|
for="select_id_lie"
|
|
class="col-form-label text-md-right ms-5"
|
|
>
|
|
{{ __('Élément lié') }}
|
|
</label>
|
|
<SearchBelongsToDropdownComponent
|
|
:label="__('crud.minicrud.select', {entity: (($refs.morph as HTMLSelectElement).value).slice(0, (($refs.morph as HTMLSelectElement).value).length-1 )})"
|
|
:targetmodel="
|
|
'App\\Models\\' + formatToModelName(($refs.morph as HTMLSelectElement).value)
|
|
"
|
|
:routename="
|
|
($refs.morph as HTMLSelectElement).value + '.json-paginate'
|
|
"
|
|
name="scheduleSiteId"
|
|
:modelrelated="data"
|
|
:modelselected="value"
|
|
:readonly="false"
|
|
:placeholder="__('crud.minicrud.select', {entity: (($refs.morph as HTMLSelectElement).value).slice(0, (($refs.morph as HTMLSelectElement).value).length-1 )})"
|
|
:helper="__('crud.minicrud.select', {entity: (($refs.morph as HTMLSelectElement).value).slice(0, (($refs.morph as HTMLSelectElement).value).length-1 )})"
|
|
:required="true"
|
|
/>
|
|
</div>
|
|
<div class="form-group mb-3">
|
|
<label
|
|
for="text"
|
|
class="col-form-label text-md-right ms-5"
|
|
>
|
|
{{ __('Description courte') }}
|
|
</label>
|
|
<textarea
|
|
ref="comment"
|
|
class="form-control"
|
|
name="text"
|
|
id="text"
|
|
rows="2"
|
|
placeholder=""
|
|
@keydown="limitLines($event)"
|
|
v-model="modale.text"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row justify-content-center">
|
|
<div class="col-8 text-center">
|
|
<button
|
|
class="btn btn-primary me-3"
|
|
@click.prevent="saveCell()"
|
|
>
|
|
{{ __('Valider') }}
|
|
</button>
|
|
<button
|
|
class="btn btn-danger"
|
|
@click.prevent="($refs.close as HTMLButtonElement).click()"
|
|
>
|
|
{{ __('Fermer') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
|
import axios from "axios";
|
|
import momentJs from "moment";
|
|
import { defineComponent } from "vue";
|
|
import route from "../../modules/route";
|
|
import toast from "../../modules/toast";
|
|
import trans from "../../modules/trans";
|
|
import SearchBelongsToDropdownComponent from "./SearchBelongsToDropdownComponent.vue";
|
|
|
|
type Lie = {
|
|
label: string | null;
|
|
name: string | null;
|
|
value: number | string | null;
|
|
};
|
|
|
|
type Day = {
|
|
day: string;
|
|
num: string;
|
|
eday: string;
|
|
key: string;
|
|
};
|
|
|
|
type DaySlot = {
|
|
id: number;
|
|
type: Lie;
|
|
text: string;
|
|
id_lie: Lie;
|
|
model_lie: Lie;
|
|
};
|
|
|
|
type SchedDay = {
|
|
id: number | null;
|
|
type: Lie;
|
|
text: string;
|
|
id_lie: Lie;
|
|
model_lie: Lie;
|
|
};
|
|
type Modale = {
|
|
id: number;
|
|
userid: number;
|
|
slot: number;
|
|
day: string;
|
|
title: string;
|
|
dDisplay: boolean;
|
|
text: string;
|
|
activity: Lie;
|
|
model_lie: Lie;
|
|
id_lie: Lie;
|
|
};
|
|
|
|
type ServerData = {
|
|
id: number;
|
|
user_id: number;
|
|
date: string;
|
|
activity: Lie;
|
|
slot: number;
|
|
model_lie: Lie;
|
|
id_lie: Lie;
|
|
description: string;
|
|
};
|
|
|
|
type ClipBoardType = {
|
|
set: boolean;
|
|
type: Lie;
|
|
text: string;
|
|
id_lie: Lie | null;
|
|
model_lie: Lie | null;
|
|
user_id: number | null;
|
|
slot: number | null;
|
|
activity: Lie | null;
|
|
id: number | null;
|
|
description: string;
|
|
date: string;
|
|
};
|
|
|
|
export default defineComponent({
|
|
mixins: [trans, route, toast, { methods: { momentJs } }],
|
|
components: {
|
|
FontAwesomeIcon,
|
|
SearchBelongsToDropdownComponent,
|
|
},
|
|
data(): {
|
|
showWeekends: boolean;
|
|
daySlots: number;
|
|
numweeks: number;
|
|
currentDate: null;
|
|
weeksCells: {
|
|
num: number;
|
|
month: number;
|
|
year: number;
|
|
}[];
|
|
days: Day[];
|
|
users: LaravelModelList;
|
|
schedules: Record<number, Record<number, DaySlot[]>>;
|
|
activities: LaravelModelList;
|
|
models: {
|
|
label: string;
|
|
name: string;
|
|
table: string;
|
|
value: string;
|
|
}[];
|
|
error: string;
|
|
modale: Modale;
|
|
dDisabled: boolean;
|
|
dReadonly: boolean;
|
|
loading: boolean;
|
|
value: Lie;
|
|
searchText: string;
|
|
data: [];
|
|
emptyCell: SchedDay;
|
|
clipBoard: ClipBoardType;
|
|
} {
|
|
return {
|
|
showWeekends: false,
|
|
daySlots: 4,
|
|
numweeks: 0,
|
|
currentDate: null,
|
|
weeksCells: [],
|
|
days: [],
|
|
users: [],
|
|
schedules: [],
|
|
activities: [],
|
|
models: [],
|
|
error: "",
|
|
modale: {
|
|
id: 0,
|
|
userid: 0,
|
|
slot: 0,
|
|
day: "01/01/1900",
|
|
title: "",
|
|
dDisplay: false,
|
|
text: "",
|
|
activity: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
model_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
id_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: null,
|
|
},
|
|
},
|
|
dDisabled: false,
|
|
dReadonly: false,
|
|
loading: false,
|
|
value: {
|
|
label: null,
|
|
name: null,
|
|
value: null,
|
|
},
|
|
searchText: "",
|
|
data: [],
|
|
emptyCell: {
|
|
type: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
text: "",
|
|
id_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: null,
|
|
},
|
|
model_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
id: null,
|
|
},
|
|
clipBoard: {
|
|
set: false,
|
|
type: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
text: "",
|
|
id_lie: null,
|
|
model_lie: null,
|
|
id: null,
|
|
user_id: null,
|
|
slot: null,
|
|
description: "",
|
|
date: "",
|
|
activity: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
},
|
|
};
|
|
},
|
|
mounted() {
|
|
const json = String(this.$attrs.json ?? "{}"),
|
|
data = JSON.parse(json);
|
|
|
|
this.daySlots = !Number.isNaN(Number.parseInt(data.daySlots))
|
|
? Number.parseInt(data.daySlots)
|
|
: 4;
|
|
this.showWeekends = data.daySlots == "true" ? true : false;
|
|
this.currentDate = data.browseDate ?? new Date();
|
|
this.weeksCells = data.weeks;
|
|
this.numweeks = this.weeksCells.length;
|
|
this.days = this.prepareDays();
|
|
this.users = data.users;
|
|
this.schedules = this.prepareSched(data.schedules);
|
|
this.activities = data.activities;
|
|
this.models = Object.values(data.models);
|
|
},
|
|
methods: {
|
|
goToPlanning(forward: boolean): void {
|
|
const route = this.route("schedule.index");
|
|
if (!route) {
|
|
throw new Error("undefined route schedule.index");
|
|
}
|
|
const thisWeekMonday = this.momentJs(this.currentDate).startOf("week");
|
|
const url = new URL(route);
|
|
(window as Window).location =
|
|
`${url.origin}${url.pathname}?p=` +
|
|
(forward
|
|
? thisWeekMonday.add(8, "day")
|
|
: thisWeekMonday.subtract(6, "day")
|
|
).format("DD/MM/YYYY");
|
|
},
|
|
prepareDays(): Day[] {
|
|
let mydays = [];
|
|
for (let i = 0; i < this.numweeks * 7; i++) {
|
|
const date = this.momentJs(this.currentDate).add(i, "day"),
|
|
obj = {
|
|
day: date.format("ddd"),
|
|
num: date.format("DD"),
|
|
eday: date.locale("en").format("ddd"),
|
|
key: date.format("DD/MM/YYYY"),
|
|
};
|
|
mydays.push(obj);
|
|
if (!this.showWeekends) {
|
|
if (date.day() == 5) {
|
|
i += 2;
|
|
}
|
|
}
|
|
}
|
|
return mydays;
|
|
},
|
|
prepareSched(
|
|
dbscheds: Record<number, Record<number, DaySlot[]>>
|
|
): Record<number, Record<number, DaySlot[]>> {
|
|
const templateObj: SchedDay = {
|
|
type: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
text: "",
|
|
id_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: null,
|
|
},
|
|
model_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
id: null,
|
|
};
|
|
//we need to make missing users
|
|
Object.keys(this.users).forEach((id) => {
|
|
if (dbscheds[Number.parseInt(id)] === undefined) {
|
|
dbscheds[Number.parseInt(id)] = {};
|
|
}
|
|
});
|
|
Object.keys(dbscheds).forEach((userid) => {
|
|
//what if we missing a slot for the whole period ?
|
|
//we need to make missing slots too
|
|
for (let i = 1; i < this.daySlots + 1; i++) {
|
|
if (dbscheds[Number.parseInt(userid)][i] === undefined) {
|
|
dbscheds[Number.parseInt(userid)][i] = [];
|
|
}
|
|
}
|
|
Object.keys(dbscheds[Number.parseInt(userid)]).forEach((slotkey) => {
|
|
this.days.forEach((day) => {
|
|
const schedSlot = dbscheds[Number.parseInt(userid)][
|
|
Number.parseInt(slotkey)
|
|
] as SchedDay[];
|
|
if (schedSlot[day.key as any] === undefined) {
|
|
schedSlot[day.key as any] = templateObj;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
return dbscheds;
|
|
},
|
|
getCellObjectInfo(cellData: DaySlot) {
|
|
for (let model of this.models) {
|
|
if (cellData["model_lie"].value === model.value && model.value === "tickets") {
|
|
return {
|
|
url: this.route("ticket.show", {
|
|
TICKET: String(cellData["id_lie"].value),
|
|
}),
|
|
text: cellData["model_lie"],
|
|
};
|
|
}
|
|
if (cellData["model_lie"].value === model.value && model.value === "sites") {
|
|
return {
|
|
url: this.route("sites.show", {
|
|
SITE: String(cellData["id_lie"].value),
|
|
}),
|
|
text: cellData["model_lie"],
|
|
};
|
|
}
|
|
if (cellData["model_lie"].value === model.value && model.value === "projects") {
|
|
return {
|
|
url: this.route("projects.show", {
|
|
PROJECT: String(cellData["id_lie"].value),
|
|
}),
|
|
text: cellData["model_lie"],
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
resetModalFields() {
|
|
this.value = {
|
|
label: null,
|
|
name: null,
|
|
value: null,
|
|
};
|
|
(this.$refs.type as HTMLSelectElement).value = "";
|
|
(this.$refs.morph as HTMLSelectElement).value = "";
|
|
},
|
|
setModalData(userid: number, slotkey: number, day: string, id: number) {
|
|
let text = this.schedules[userid][slotkey][day as any]["text"],
|
|
activity = this.schedules[userid][slotkey][day as any]["type"],
|
|
model = this.schedules[userid][slotkey][day as any]["model_lie"],
|
|
currentModale: Modale = {
|
|
id: this.schedules[userid][slotkey][day as any]["id"] ?? this.__("Nouveau"),
|
|
userid: userid,
|
|
slot: slotkey,
|
|
day: day,
|
|
title: String(id),
|
|
dDisplay: false,
|
|
text: text,
|
|
activity: activity,
|
|
model_lie: model ?? "",
|
|
id_lie: this.schedules[userid][slotkey][day as any]["id_lie"],
|
|
};
|
|
this.modale = currentModale;
|
|
this.$nextTick(() => {
|
|
this.modale.dDisplay = true;
|
|
this.selectChange();
|
|
this.value = this.schedules[userid][slotkey][day as any]["id_lie"];
|
|
});
|
|
},
|
|
pasteCell(userid: number, slotkey: number, day: string, id: number) {
|
|
if (this.clipBoard.activity === null) {
|
|
throw new Error("clipBoard activity is null");
|
|
}
|
|
if (this.clipBoard.model_lie === null) {
|
|
throw new Error("clipBoard model_lie is null");
|
|
}
|
|
if (this.clipBoard.id_lie === null) {
|
|
throw new Error("clipBoard id_lie is null");
|
|
}
|
|
const data: ServerData = {
|
|
id: id,
|
|
user_id: userid,
|
|
date: day,
|
|
activity: this.clipBoard.activity,
|
|
slot: slotkey,
|
|
model_lie: this.clipBoard.model_lie,
|
|
id_lie: this.clipBoard.id_lie,
|
|
description: this.clipBoard.description,
|
|
};
|
|
this.saveCellOnServer(data);
|
|
this.notify(
|
|
"Cellule collée",
|
|
3000,
|
|
{
|
|
background: "linear-gradient(to right, #00317d, #0058ca)",
|
|
}
|
|
);
|
|
},
|
|
clearClipBoard() {
|
|
this.clipBoard = {
|
|
set: false,
|
|
type: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
text: "",
|
|
activity: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
id_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
model_lie: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
id: null,
|
|
user_id: null,
|
|
slot: null,
|
|
description: "",
|
|
date: "",
|
|
};
|
|
},
|
|
copyCell(userid: number, slotkey: number, day: string, id: number) {
|
|
this.clipBoard = {
|
|
set: true,
|
|
id: id,
|
|
user_id: userid,
|
|
date: day,
|
|
activity: this.schedules[userid][slotkey][day as any].type,
|
|
slot: slotkey,
|
|
model_lie: this.schedules[userid][slotkey][day as any].model_lie,
|
|
id_lie: this.schedules[userid][slotkey][day as any].id_lie,
|
|
description: this.schedules[userid][slotkey][day as any].text,
|
|
text: "",
|
|
type: {
|
|
label: "",
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
};
|
|
|
|
this.notify(
|
|
"Cellule copiée",
|
|
3000,
|
|
{
|
|
background: "linear-gradient(to right, #00317d, #0058ca)",
|
|
}
|
|
);
|
|
},
|
|
saveCell() {
|
|
this.error = "";
|
|
const data: ServerData = {
|
|
id: this.modale.id,
|
|
user_id: this.modale.userid,
|
|
date: this.modale.day,
|
|
activity: {
|
|
label: String((this.$refs.type as HTMLSelectElement).value),
|
|
name: String((this.$refs.type as HTMLSelectElement).value),
|
|
value: (this.$refs.type as HTMLSelectElement).value,
|
|
},
|
|
slot: this.modale.slot,
|
|
model_lie: {
|
|
label: String((this.$refs.morph as HTMLSelectElement).value),
|
|
name: String((this.$refs.type as HTMLSelectElement).value),
|
|
value: (this.$refs.morph as HTMLSelectElement).value,
|
|
},
|
|
id_lie: {
|
|
label: null,
|
|
name: null,
|
|
value: (document.getElementsByName("scheduleSiteId")[0] as HTMLInputElement).value,
|
|
},
|
|
description: (this.$refs.comment as HTMLTextAreaElement).value,
|
|
};
|
|
this.saveCellOnServer(data);
|
|
},
|
|
saveCellOnServer(data: ServerData) {
|
|
this.error = "";
|
|
const self = this,
|
|
routeUri = self.route("schedule.setCellContent");
|
|
if (self.error.length) {
|
|
return;
|
|
}
|
|
|
|
if (!routeUri) {
|
|
throw new Error("schedule.setCellContent is undefined");
|
|
}
|
|
axios
|
|
.post(routeUri, {
|
|
id: data.id,
|
|
user_id: data.user_id,
|
|
date: data.date,
|
|
activity: data.activity.value ?? data.activity,
|
|
slot: data.slot,
|
|
model_lie: data.model_lie.value,
|
|
id_lie: data.id_lie.value,
|
|
description: data.description,
|
|
})
|
|
.then((response) => {
|
|
if (response.data.status) {
|
|
const sched = Object.assign({}, response.data.sched);
|
|
let cellData = {
|
|
type: sched.activity,
|
|
text: sched.description,
|
|
id_lie: sched.id_lie,
|
|
model_lie: sched.model_lie,
|
|
id: sched.id,
|
|
};
|
|
this.schedules[sched.user_id][sched.slot][sched.date] = cellData;
|
|
(this.$refs.close as HTMLButtonElement).click();
|
|
} else {
|
|
this.error = "Réponse inconnue";
|
|
}
|
|
})
|
|
.catch((error: any) => {
|
|
console.log(error);
|
|
if (error.response.status === 429) {
|
|
location.reload();
|
|
}
|
|
if (error.response.status === 422) {
|
|
if (error.response.data.errors) {
|
|
this.error = "";
|
|
for (let id in error.response.data.errors) {
|
|
let field = error.response.data.errors[id];
|
|
this.error += field.join("\n") + "\n";
|
|
}
|
|
return;
|
|
} else if (error.response.data.message) {
|
|
this.error = error.response.data.message;
|
|
return;
|
|
}
|
|
}
|
|
this.error = error;
|
|
});
|
|
},
|
|
eraseCell(userid: number, slotkey: number, day: string, id: number) {
|
|
const route = this.route("schedule.eraseCellContent"),
|
|
data = {
|
|
id: id,
|
|
};
|
|
if (!route) {
|
|
throw new Error("undefined route schedule.eraseCellContent");
|
|
}
|
|
axios
|
|
.post(route, data)
|
|
.then((response) => {
|
|
if (response.data.status) {
|
|
this.schedules[userid][slotkey][day as any] = this.emptyCell as DaySlot;
|
|
} else {
|
|
console.error("Unknown response");
|
|
}
|
|
})
|
|
.catch((error: any) => {
|
|
if (error.response.status === 429) {
|
|
location.reload();
|
|
}
|
|
console.error(error);
|
|
});
|
|
},
|
|
selectChange() {
|
|
this.value = {
|
|
label: null,
|
|
name: null,
|
|
value: null,
|
|
};
|
|
this.modale.dDisplay = false;
|
|
this.$nextTick(() => {
|
|
if ((this.$refs.morph as HTMLSelectElement).value) {
|
|
this.modale.dDisplay = true;
|
|
}
|
|
});
|
|
},
|
|
limitLines(e: KeyboardEvent) {
|
|
const comment = this.$refs.comment as HTMLTextAreaElement;
|
|
let keynum,
|
|
lines = comment.value.split("\n").length;
|
|
if (e.key !== undefined) {
|
|
keynum = e.key;
|
|
} else if (e.keyCode !== undefined) {
|
|
// IE
|
|
if (window.event) {
|
|
keynum = e.keyCode;
|
|
// Netscape/Firefox/Opera
|
|
} else if (e.which) {
|
|
keynum = e.which;
|
|
}
|
|
}
|
|
|
|
if (keynum === undefined) {
|
|
throw new Error("undefined pressed key");
|
|
}
|
|
keynum = Number.parseInt(String(keynum));
|
|
|
|
if (keynum !== 8 && comment.value.length >= this.textLimit) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
if (keynum === 13 && lines == comment.rows) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
},
|
|
formatToModelName(s: string) {
|
|
return s.charAt(0).toUpperCase() + s.slice(1, s.length-1);
|
|
}
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "vue-select/dist/vue-select.css";
|
|
|
|
.actions_col {
|
|
width: 45px;
|
|
padding: 0;
|
|
}
|
|
|
|
.plannings {
|
|
.sticky-top {
|
|
top: 20rem !important;
|
|
}
|
|
}
|
|
|
|
table {
|
|
.Mon {
|
|
border-left: 4px solid;
|
|
}
|
|
}
|
|
|
|
table.schedules_table {
|
|
table-layout: fixed;
|
|
|
|
.resource_ident {
|
|
font-weight: bold;
|
|
width: 150px;
|
|
}
|
|
|
|
.cellsizer {
|
|
height: 50px;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
.btn-text {
|
|
margin: 0 0.1rem;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
}
|
|
|
|
.dynCell {
|
|
position: relative;
|
|
&.day {
|
|
//position: relative;
|
|
&:hover .btn {
|
|
opacity: 1;
|
|
}
|
|
&:hover .cellsizer {
|
|
height: 140px;
|
|
padding-top: 2rem;
|
|
position: absolute;
|
|
width: 200%;
|
|
left: -50%;
|
|
top: -55%;
|
|
z-index: 20;
|
|
border: 1px solid;
|
|
}
|
|
$buttonBgColor: #4d4d4d;
|
|
|
|
// Reset button Style to nice one
|
|
button {
|
|
display: inline;
|
|
border: none;
|
|
padding: 0.6rem 3rem;
|
|
margin: 0;
|
|
text-decoration: none;
|
|
background: $buttonBgColor;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
transition: background 250ms ease-in-out, transform 150ms ease;
|
|
-webkit-appearance: none;
|
|
-moz-appearance: none;
|
|
}
|
|
|
|
button:disabled,
|
|
button[disabled] {
|
|
color: #aaa;
|
|
}
|
|
|
|
button:hover,
|
|
button:focus {
|
|
background: darken($buttonBgColor, 10%);
|
|
}
|
|
|
|
button:active {
|
|
transform: scale(0.99);
|
|
}
|
|
|
|
.btn {
|
|
position: absolute;
|
|
top: 0.1rem;
|
|
left: 0.1rem;
|
|
padding: 0;
|
|
width: 1.8rem;
|
|
height: 1.8rem;
|
|
margin: 0;
|
|
background-color: $buttonBgColor;
|
|
opacity: 0;
|
|
&.hide {
|
|
opacity: 0 !important;
|
|
}
|
|
&:hover,
|
|
&:focus {
|
|
background-color: darken($buttonBgColor, 10%);
|
|
}
|
|
&:nth-last-child(2) {
|
|
top: 0.1rem;
|
|
right: inherit;
|
|
left: 2.1rem;
|
|
}
|
|
&:nth-last-child(3) {
|
|
right: inherit;
|
|
top: 0.1rem;
|
|
left: 4.1rem;
|
|
}
|
|
&:nth-last-child(1) {
|
|
top: 0.1rem;
|
|
left: calc(100% - 1.9rem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@import "toastify-js/src/toastify.css";
|
|
@import "vue-select/dist/vue-select.css";
|
|
.planning {
|
|
overflow: auto;
|
|
|
|
td {
|
|
height: 50px;
|
|
}
|
|
|
|
#text {
|
|
height: 5.5rem;
|
|
padding: 1rem 2rem;
|
|
resize: none;
|
|
width: 37rem;
|
|
margin: 0 auto;
|
|
}
|
|
}
|
|
</style>
|