1149 lines
35 KiB
Vue
1149 lines
35 KiB
Vue
<template>
|
|
<div v-if="formState.ready" v-resize="onResize" class="my-n8">
|
|
<gz-error :error-box-message="formState.errorBoxMessage"></gz-error>
|
|
<v-sheet height="64">
|
|
<v-toolbar flat class="ml-n3">
|
|
<v-btn text :small="isXS" :large="issmAndUp" @click="setToday">
|
|
{{ $ay.t("DateRangeToday") }}
|
|
</v-btn>
|
|
<v-btn fab text :small="isXS" @click="prev">
|
|
<v-icon :small="isXS">$prev</v-icon>
|
|
</v-btn>
|
|
<v-btn fab text :small="isXS" @click="next">
|
|
<v-icon :small="isXS">$next</v-icon>
|
|
</v-btn>
|
|
<v-toolbar-title v-if="$refs.calendar">
|
|
<v-btn
|
|
:small="isXS"
|
|
:large="issmAndUp"
|
|
text
|
|
@click="viewType = 'month'"
|
|
>
|
|
{{ $refs.calendar.title }}</v-btn
|
|
>
|
|
</v-toolbar-title>
|
|
<v-spacer v-if="issmAndUp"></v-spacer>
|
|
<v-btn
|
|
class="mr-3"
|
|
fab
|
|
text
|
|
:small="isXS"
|
|
:large="issmAndUp"
|
|
@click="settingsDialog = true"
|
|
>
|
|
<v-icon :small="isXS">$ayiCog</v-icon>
|
|
</v-btn>
|
|
|
|
<v-menu bottom right>
|
|
<template v-slot:activator="{ on, attrs }">
|
|
<v-btn
|
|
:small="isXS"
|
|
:large="issmAndUp"
|
|
text
|
|
v-bind="attrs"
|
|
v-on="on"
|
|
>
|
|
<span>{{ typeToLabel() }}</span>
|
|
<v-icon right>$sort</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<v-list>
|
|
<v-list-item @click="viewType = 'day'">
|
|
<v-list-item-title>{{ $ay.t("ScheduleDay") }}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item @click="viewType = 'week'">
|
|
<v-list-item-title>{{ $ay.t("ScheduleWeek") }}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item @click="viewType = 'month'">
|
|
<v-list-item-title>{{
|
|
$ay.t("ScheduleMonth")
|
|
}}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item @click="viewType = '4day'">
|
|
<v-list-item-title>{{ $ay.t("Schedule4Day") }}</v-list-item-title>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
</v-toolbar>
|
|
</v-sheet>
|
|
|
|
<v-sheet :height="calendarHeight">
|
|
<v-calendar
|
|
ref="calendar"
|
|
v-model="focus"
|
|
color="primary"
|
|
:events="events"
|
|
:event-color="getEventColor"
|
|
:type="viewType"
|
|
:locale="languageName"
|
|
:event-more-text="$ay.t('More')"
|
|
:first-time="formUserOptions.firstTime"
|
|
:weekdays="weekdays"
|
|
event-overlap-mode="column"
|
|
@click:more="viewDay"
|
|
@click:date="viewDay"
|
|
@change="fetchEvents"
|
|
@mousedown:event="startDrag"
|
|
@mousedown:time="startTime"
|
|
@mousemove:time="mouseMoveDayView"
|
|
@mousemove:day="mouseMoveMonthView"
|
|
@mouseup:day="endDragExtend"
|
|
@mouseup:time="endDragExtend"
|
|
@mouseleave.native="cancelDrag"
|
|
>
|
|
<template v-slot:event="{ event, timed, eventSummary }">
|
|
<div class="v-event-draggable">
|
|
<v-icon small :color="event.textColor" class="mr-1">{{
|
|
iconForEvent(event.type)
|
|
}}</v-icon>
|
|
<!-- eslint-disable vue/no-v-html -->
|
|
<span
|
|
:class="event.textColor + '--text'"
|
|
v-html="eventSummary()"
|
|
/><v-icon
|
|
v-if="!event.editable"
|
|
x-small
|
|
:color="event.textColor"
|
|
class="ml-1"
|
|
>
|
|
$ayiLock</v-icon
|
|
>
|
|
</div>
|
|
<div
|
|
v-if="timed && event.editable"
|
|
class="v-event-drag-bottom"
|
|
@mousedown.stop="extendBottom(event)"
|
|
></div>
|
|
</template>
|
|
</v-calendar>
|
|
<!-- NEW ITEM DIALOG -->
|
|
<template>
|
|
<v-row justify="center">
|
|
<v-dialog v-model="newItemDialog" max-width="360px" persistent>
|
|
<v-card>
|
|
<v-card-title>{{ $ay.t("New") }}</v-card-title>
|
|
<v-card-text>
|
|
<v-col cols="12">
|
|
<v-btn
|
|
x-large
|
|
block
|
|
@click="newItem($ay.ayt().WorkOrderItemScheduledUser)"
|
|
><v-icon large left>$ayiTools</v-icon
|
|
>{{ $ay.t("WorkOrder") }}</v-btn
|
|
>
|
|
</v-col>
|
|
<!-- <v-col cols="12">
|
|
<v-btn x-large block @click="newItem($ay.ayt().Reminder)"
|
|
><v-icon large left>$ayiStickyNote</v-icon
|
|
>{{ $ay.t("Reminder") }}</v-btn
|
|
>
|
|
</v-col> -->
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-btn text color="primary" @click="cancelAddNew">{{
|
|
$ay.t("Cancel")
|
|
}}</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</v-row>
|
|
</template>
|
|
<!-- MORE INFO DIALOG -->
|
|
<template>
|
|
<v-row justify="center">
|
|
<v-dialog v-model="moreInfoDialog" max-width="600px">
|
|
<v-card>
|
|
<v-toolbar>
|
|
<v-btn icon @click="openScheduledItem()">
|
|
<v-icon color="primary">{{ iconForSelectedEvent() }}</v-icon>
|
|
</v-btn>
|
|
<v-toolbar-title>{{ selectedEvent.name }}</v-toolbar-title>
|
|
</v-toolbar>
|
|
<v-card-text>
|
|
<!--woitemscheduleduser -->
|
|
<template>
|
|
<div>
|
|
<span class="text-h6">{{ $ay.t("WorkOrder") }}:</span>
|
|
<span class="text-body-1 ml-2"
|
|
>{{ evInfo.serial }} {{ evInfo.customerViz }}</span
|
|
>
|
|
</div>
|
|
<div>
|
|
<span class="text-h6">{{ $ay.t("Tags") }}:</span>
|
|
<span class="text-body-1 ml-2">{{
|
|
$ay.util().formatTags(evInfo.wotags)
|
|
}}</span>
|
|
</div>
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{ $ay.t("WorkOrderItemScheduledUserUserID") }}:</span
|
|
>
|
|
<span class="text-body-1 ml-2">{{ evInfo.scheduser }}</span>
|
|
</div>
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{ $ay.t("DashboardScheduled") }}:</span
|
|
>
|
|
<span class="text-body-1 ml-2"
|
|
>{{ $ay.dt(evInfo.startDate) }} — {{
|
|
$ay.dt(evInfo.stopDate)
|
|
}}</span
|
|
>
|
|
</div>
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{
|
|
$ay.t("WorkOrderItemScheduledUserEstimatedQuantity")
|
|
}}:</span
|
|
>
|
|
<span class="text-body-1 ml-2">{{ evInfo.qty }}</span>
|
|
</div>
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{
|
|
$ay.t("WorkOrderItemScheduledUserServiceRateID")
|
|
}}:</span
|
|
>
|
|
<span class="text-body-1 ml-2">{{ evInfo.rate }}</span>
|
|
</div>
|
|
|
|
<div v-if="evInfo.haswostatus">
|
|
<span class="text-h6">{{ $ay.t("WorkOrderStatus") }}:</span>
|
|
<span class="text-body-1 ml-2">{{ evInfo.wostatus }}</span>
|
|
<v-icon :color="evInfo.wostatuscolor" class="ml-4"
|
|
>$ayiFlag</v-icon
|
|
>
|
|
<v-icon
|
|
v-if="evInfo.wostatuslocked"
|
|
color="primary"
|
|
class="ml-4"
|
|
>$ayiLock</v-icon
|
|
>
|
|
<v-icon
|
|
v-if="evInfo.wostatuscompleted"
|
|
color="primary"
|
|
class="ml-4"
|
|
>$ayiCheckCircle</v-icon
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{ $ay.t("WorkOrderItemSummary") }}:</span
|
|
>
|
|
<span class="text-body-1 ml-2">
|
|
<v-icon class="mr-3" :color="evInfo.woitemstatuscolor"
|
|
>$ayiCircle</v-icon
|
|
>{{ evInfo.woitemstatus }}</span
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{ $ay.t("WorkOrderItemPriorityID") }}:</span
|
|
>
|
|
<span class="text-body-1 ml-2">
|
|
<v-icon class="mr-3" :color="evInfo.woitemprioritycolor"
|
|
>$ayiFireAlt</v-icon
|
|
>{{ evInfo.woitempriority }}</span
|
|
>
|
|
</div>
|
|
<div>
|
|
<span class="text-h6"
|
|
>{{ $ay.t("WorkOrderItemTags") }}:</span
|
|
>
|
|
<span class="text-body-1 ml-2">{{
|
|
$ay.util().formatTags(evInfo.woitemtags)
|
|
}}</span>
|
|
</div>
|
|
</template>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-btn color="primary" text @click="openScheduledItem()">{{
|
|
$ay.t("Open")
|
|
}}</v-btn>
|
|
|
|
<v-spacer v-if="!$vuetify.breakpoint.xs"></v-spacer>
|
|
|
|
<v-btn color="primary" text @click="moreInfoDialog = false">
|
|
{{ $ay.t("Close") }}
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</v-row>
|
|
</template>
|
|
</v-sheet>
|
|
<template>
|
|
<!-- ############## SETTINGS DIALOG #################-->
|
|
<v-row justify="center">
|
|
<v-dialog v-model="settingsDialog" max-width="600px">
|
|
<v-card>
|
|
<v-card-title>{{ $ay.t("ScheduleOptions") }} </v-card-title>
|
|
<v-card-text>
|
|
<v-row no-gutters>
|
|
<v-col cols="12" class="mt-2">
|
|
<gz-time-picker
|
|
v-model="tempFirstTime"
|
|
:label="$ay.t('ScheduleFirstHour')"
|
|
></gz-time-picker>
|
|
</v-col>
|
|
|
|
<v-col cols="12">
|
|
<GZDaysOfWeek
|
|
ref="daysofweek"
|
|
v-model="formUserOptions.excludeDaysOfWeek"
|
|
:label="$ay.t('ExcludeDaysOfWeek')"
|
|
></GZDaysOfWeek>
|
|
</v-col>
|
|
|
|
<span class="text-h6 mt-3">{{
|
|
$ay.t("ScheduleShowTypes")
|
|
}}</span>
|
|
<v-col cols="12">
|
|
<v-checkbox
|
|
v-model="formUserOptions.reminders"
|
|
:label="$ay.t('ReminderList')"
|
|
></v-checkbox>
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<v-checkbox
|
|
v-model="formUserOptions.reviews"
|
|
:label="$ay.t('ReviewList')"
|
|
></v-checkbox>
|
|
</v-col>
|
|
|
|
<v-col cols="12">
|
|
<v-checkbox
|
|
v-model="formUserOptions.wisu"
|
|
:label="$ay.t('WorkOrderList')"
|
|
></v-checkbox>
|
|
|
|
<v-radio-group
|
|
v-model="formUserOptions.wisuColorSource"
|
|
:mandatory="true"
|
|
:label="$ay.t('ScheduleWOColorFrom')"
|
|
class="ml-3 mt-n2"
|
|
>
|
|
<v-radio :label="$ay.t('NoColor')" value="0"></v-radio>
|
|
<v-radio
|
|
:label="$ay.t('WorkOrderStatus')"
|
|
value="2"
|
|
></v-radio>
|
|
<v-radio
|
|
:label="$ay.t('WorkOrderItemWorkOrderStatusID')"
|
|
value="3"
|
|
></v-radio>
|
|
<v-radio
|
|
:label="$ay.t('WorkOrderItemPriorityID')"
|
|
value="4"
|
|
></v-radio>
|
|
</v-radio-group>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-btn text color="primary" @click="settingsDialog = false">{{
|
|
$ay.t("Cancel")
|
|
}}</v-btn>
|
|
<v-spacer v-if="issmAndUp"></v-spacer>
|
|
<v-btn
|
|
color="primary"
|
|
text
|
|
class="ml-4"
|
|
@click="saveUserOptions()"
|
|
>{{ $ay.t("Save") }}</v-btn
|
|
>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</v-row>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
const FORM_KEY = "svc-schedule-user";
|
|
import GZDaysOfWeek from "../components/days-of-week-control.vue";
|
|
export default {
|
|
components: {
|
|
GZDaysOfWeek
|
|
},
|
|
data() {
|
|
return {
|
|
focus: "",
|
|
viewType: "month",
|
|
selectedEvent: {},
|
|
selectedElement: null,
|
|
events: [],
|
|
evInfo: {},
|
|
dragEvent: null,
|
|
extendEvent: null,
|
|
createStart: null,
|
|
extendOriginal: null,
|
|
dragged: false,
|
|
dragTimeout: null,
|
|
formState: {
|
|
ready: false,
|
|
dirty: false,
|
|
valid: true,
|
|
readOnly: false,
|
|
loading: true,
|
|
errorBoxMessage: null,
|
|
appError: null,
|
|
serverError: {}
|
|
},
|
|
calendarHeight: 600,
|
|
settingsDialog: false,
|
|
newItemDialog: false,
|
|
moreInfoDialog: false,
|
|
timeZoneName: window.$gz.locale.getResolvedTimeZoneName(),
|
|
languageName: window.$gz.locale.getResolvedLanguage(),
|
|
hour12: window.$gz.locale.getHour12(),
|
|
formUserOptions: {},
|
|
tempFirstTime: null,
|
|
lastMouseDownMS: null,
|
|
lastStart: null,
|
|
lastEnd: null,
|
|
userId: null,
|
|
userName: null
|
|
};
|
|
},
|
|
computed: {
|
|
weekdays() {
|
|
return window.$gz.util.DaysOfWeekToWeekdays(
|
|
this.formUserOptions.excludeDaysOfWeek
|
|
);
|
|
},
|
|
isXS() {
|
|
//console.log(this.$vuetify.breakpoint);
|
|
return this.$vuetify.breakpoint.xs;
|
|
},
|
|
issmAndUp() {
|
|
return this.$vuetify.breakpoint.smAndUp;
|
|
}
|
|
},
|
|
async created() {
|
|
const vm = this;
|
|
try {
|
|
this.userId = vm.$route.params.recordid;
|
|
this.userName = vm.$route.params.name;
|
|
await initForm(vm);
|
|
window.$gz.eventBus.$on("menu-click", clickHandler);
|
|
//----------------------------
|
|
generateMenu(vm);
|
|
} catch (error) {
|
|
window.$gz.errorHandler.handleFormError(error, vm);
|
|
} finally {
|
|
vm.formState.ready = true;
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
saveFormSettings(this);
|
|
window.$gz.eventBus.$off("menu-click", clickHandler);
|
|
},
|
|
methods: {
|
|
async refresh() {
|
|
await this.fetchEvents({ start: null, end: null });
|
|
},
|
|
openObject: function(type, id) {
|
|
window.$gz.eventBus.$emit("openobject", {
|
|
type: type,
|
|
id: id
|
|
});
|
|
},
|
|
newItem(atype) {
|
|
const newEvent = this.events[this.events.length - 1];
|
|
const addStart = window.$gz.locale.localScheduleFormatToUTC8601String(
|
|
newEvent.start,
|
|
this.timeZoneName
|
|
);
|
|
const addEnd = window.$gz.locale.localScheduleFormatToUTC8601String(
|
|
newEvent.end,
|
|
this.timeZoneName
|
|
);
|
|
switch (atype) {
|
|
case this.$ay.ayt().WorkOrderItemScheduledUser:
|
|
this.$router.push({
|
|
name: "workorder-edit",
|
|
params: {
|
|
recordid: 0,
|
|
add: {
|
|
type: atype,
|
|
start: addStart,
|
|
end: addEnd,
|
|
userId: this.userId == 0 ? null : this.userId,
|
|
name: this.userId == 0 ? null : this.userName
|
|
}
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
//remove faux item, server will provide it back once it's created anyway
|
|
this.events.splice(this.events.length - 1);
|
|
this.newItemDialog = false;
|
|
},
|
|
cancelAddNew() {
|
|
this.events.splice(this.events.length - 1);
|
|
this.newItemDialog = false;
|
|
},
|
|
|
|
extendBottom(event) {
|
|
//console.log("extend bottom fired");
|
|
if (event.editable) {
|
|
//capture time to see if it's a click or a drag/extend
|
|
this.lastMouseDownMS = new Date().getTime();
|
|
this.extendEvent = event;
|
|
this.createStart = event.start;
|
|
this.extendOriginal = event.end;
|
|
}
|
|
},
|
|
async endDragExtend() {
|
|
//On drag then dragged is set to true and dragEvent and dragTime are set
|
|
//on extend then dragged is set to true extendEvent (actual event), extendOriginal and createStart are set, dragEvent is null
|
|
//on create then dragged is set to false and createStart is only value set, dragEvent is null and extendEvent is null
|
|
|
|
//Handle the event, could be one of three things: changing an event start time, changing an event length or creating a new event
|
|
if (this.extendEvent && this.extendEvent.type == 0) {
|
|
//NEW, prompt for deets and create or if cancelled then just remove this faux event from events list (it will be the last one in the array)
|
|
this.newItemDialog = true;
|
|
} else {
|
|
//MORE INFO
|
|
if (this.lastMouseDownMS != null && this.itWasAClickNotADrag()) {
|
|
await this.showMoreInfo(this.dragEvent);
|
|
this.dragEvent = null; //this needs to be set or it will keep dragging off an editable event even as the moreinfo dialog show
|
|
return;
|
|
}
|
|
|
|
//MODIFY existing event, drag or extend
|
|
if (this.dragEvent || this.extendEvent) {
|
|
const param = {
|
|
type: null,
|
|
id: null,
|
|
start: null,
|
|
end: null,
|
|
userId: this.userId //always whatever user id we came in for from svc-schedule
|
|
};
|
|
|
|
if (this.dragEvent) {
|
|
param.type = this.dragEvent.type;
|
|
param.id = this.dragEvent.id;
|
|
param.start = window.$gz.locale.localScheduleFormatToUTC8601String(
|
|
this.dragEvent.start,
|
|
this.timeZoneName
|
|
);
|
|
param.end = window.$gz.locale.localScheduleFormatToUTC8601String(
|
|
this.dragEvent.end,
|
|
this.timeZoneName
|
|
);
|
|
} else {
|
|
param.type = this.extendEvent.type;
|
|
param.id = this.extendEvent.id;
|
|
param.start = window.$gz.locale.localScheduleFormatToUTC8601String(
|
|
this.extendEvent.start,
|
|
this.timeZoneName
|
|
);
|
|
param.end = window.$gz.locale.localScheduleFormatToUTC8601String(
|
|
this.extendEvent.end,
|
|
this.timeZoneName
|
|
);
|
|
}
|
|
try {
|
|
window.$gz.form.deleteAllErrorBoxErrors(this);
|
|
const res = await window.$gz.api.post("schedule/adjust", param);
|
|
if (res.error) {
|
|
this.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(this);
|
|
}
|
|
} catch (error) {
|
|
window.$gz.errorHandler.handleFormError(error, this);
|
|
}
|
|
}
|
|
}
|
|
this.dragTime = null;
|
|
this.dragEvent = null;
|
|
this.extendEvent = null;
|
|
this.createStart = null;
|
|
this.extendOriginal = null;
|
|
},
|
|
cancelDrag() {
|
|
if (this.extendEvent) {
|
|
if (this.extendOriginal) {
|
|
this.extendEvent.end = this.extendOriginal;
|
|
} else {
|
|
const i = this.events.indexOf(this.extendEvent);
|
|
if (i !== -1) {
|
|
this.events.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
this.extendEvent = null;
|
|
this.createStart = null;
|
|
this.dragTime = null;
|
|
this.dragEvent = null;
|
|
this.lastMouseDownMS = null;
|
|
},
|
|
startDrag({ event }) {
|
|
//# mouse down on an event triggers this call
|
|
if (event) {
|
|
this.lastMouseDownMS = new Date().getTime(); //snapshot time to disambiguate drag vs click
|
|
if (event.editable) {
|
|
this.dragged = false;
|
|
this.dragEvent = event;
|
|
this.dragTime = null;
|
|
this.extendOriginal = null;
|
|
} else {
|
|
this.dragged = false;
|
|
this.dragEvent = event;
|
|
this.dragTime = null;
|
|
}
|
|
}
|
|
},
|
|
itWasAClickNotADrag() {
|
|
if (this.lastMouseDownMS == null) {
|
|
if (this.$ay.dev) {
|
|
throw new Error("lastMouseDownMS is null!");
|
|
} else {
|
|
window.$gz.store.commit(
|
|
"logItem",
|
|
"home-schedule:lastMouseDownMS is unexpectedly null"
|
|
);
|
|
return true; //least dangerous option in production
|
|
}
|
|
}
|
|
const elapsed = new Date().getTime() - this.lastMouseDownMS;
|
|
this.lastMouseDownMS = null;
|
|
return elapsed < 200;
|
|
},
|
|
mouseMoveDayView(tms) {
|
|
//no event being dragged or exgtended?
|
|
if (!this.dragEvent && !this.extendEvent) {
|
|
return;
|
|
}
|
|
const mouse = this.toTime(tms);
|
|
if (this.dragEvent && this.dragTime !== null) {
|
|
//# DRAGGING PATH
|
|
const start = this.dragEvent.start;
|
|
const end = this.dragEvent.end;
|
|
const duration = end - start;
|
|
const newStartTime = mouse - this.dragTime;
|
|
const newStart = this.roundTime(newStartTime);
|
|
const newEnd = newStart + duration;
|
|
this.dragEvent.start = newStart;
|
|
this.dragEvent.end = newEnd;
|
|
} else if (this.extendEvent && this.createStart !== null) {
|
|
//# EXTENDING PATH
|
|
const mouseRounded = this.roundTime(mouse, false);
|
|
const min = Math.min(mouseRounded, this.createStart);
|
|
const max = Math.max(mouseRounded, this.createStart);
|
|
this.extendEvent.start = min;
|
|
this.extendEvent.end = max;
|
|
}
|
|
},
|
|
mouseMoveMonthView(dd) {
|
|
if (!this.dragEvent) {
|
|
return;
|
|
}
|
|
//# DRAGGING PATH MONTH VIEW
|
|
//need to get the actual start time as it isn't in the mouse date
|
|
const dragEventStartDate = new Date(this.dragEvent.start);
|
|
const mouseDate = new Date(
|
|
dd.year,
|
|
dd.month - 1,
|
|
dd.day,
|
|
dragEventStartDate.getHours(),
|
|
dragEventStartDate.getMinutes()
|
|
).getTime();
|
|
const moveDelta = mouseDate - this.dragEvent.start;
|
|
this.dragEvent.start = mouseDate;
|
|
this.dragEvent.end = this.dragEvent.end + moveDelta;
|
|
},
|
|
startTime(tms) {
|
|
//This is called on the start of dragging an existing schedule item or drag extending a NEW schedule item
|
|
const mouse = this.toTime(tms);
|
|
if (this.dragEvent && this.dragTime === null) {
|
|
//# DAY VIEW *DRAG* EXISTING START EVENT (not extend)
|
|
//(also called on simple click to view schedule more info)
|
|
if (this.dragEvent.editable) {
|
|
const start = this.dragEvent.start;
|
|
this.dragTime = mouse - start;
|
|
}
|
|
} else {
|
|
//# DAY VIEW CREATE START EVENT
|
|
this.createStart = this.roundTime(mouse);
|
|
this.extendEvent = {
|
|
name: "-",
|
|
color: this.$store.state.darkMode ? "white" : "black",
|
|
textColor: this.$store.state.darkMode ? "black" : "white",
|
|
start: this.createStart,
|
|
end: this.createStart,
|
|
timed: true,
|
|
type: 0,
|
|
id: 0,
|
|
editable: true
|
|
};
|
|
this.events.push(this.extendEvent);
|
|
}
|
|
},
|
|
roundTime(time, down = true) {
|
|
const roundTo = 15; // minutes
|
|
const roundDownTime = roundTo * 60 * 1000;
|
|
return down
|
|
? time - (time % roundDownTime)
|
|
: time + (roundDownTime - (time % roundDownTime));
|
|
},
|
|
toTime(tms) {
|
|
return new Date(
|
|
tms.year,
|
|
tms.month - 1,
|
|
tms.day,
|
|
tms.hour,
|
|
tms.minute
|
|
).getTime();
|
|
},
|
|
typeToLabel() {
|
|
switch (this.viewType) {
|
|
case "month":
|
|
return this.$ay.t("ScheduleMonth");
|
|
case "week":
|
|
return this.$ay.t("ScheduleWeek");
|
|
case "day":
|
|
return this.$ay.t("ScheduleDay");
|
|
case "4day":
|
|
return this.$ay.t("Schedule4Day");
|
|
}
|
|
},
|
|
onResize() {
|
|
this.calendarHeight = window.innerHeight * 0.84;
|
|
},
|
|
viewDay({ date }) {
|
|
//console.log("ViewDay clicked");
|
|
this.focus = date;
|
|
this.viewType = "day";
|
|
},
|
|
getEventColor(event) {
|
|
return event.color;
|
|
},
|
|
setToday() {
|
|
this.focus = "";
|
|
},
|
|
prev() {
|
|
this.$refs.calendar.prev();
|
|
},
|
|
next() {
|
|
this.$refs.calendar.next();
|
|
},
|
|
iconForSelectedEvent() {
|
|
return window.$gz.util.iconForType(this.selectedEvent.type);
|
|
},
|
|
iconForEvent(type) {
|
|
return window.$gz.util.iconForType(type);
|
|
},
|
|
openScheduledItem() {
|
|
window.$gz.eventBus.$emit("openobject", {
|
|
type: this.selectedEvent.type,
|
|
id: this.selectedEvent.id
|
|
});
|
|
},
|
|
async showMoreInfo(event) {
|
|
this.selectedEvent = event;
|
|
let route = null;
|
|
this.evInfo = {};
|
|
switch (event.type) {
|
|
case window.$gz.type.WorkOrderItemScheduledUser:
|
|
route = `workorder/items/scheduled-users/sched-info/${event.id}`;
|
|
break;
|
|
// case window.$gz.type.Reminder:
|
|
// route = `reminder/sched-info/${event.id}`;
|
|
// break;
|
|
// case window.$gz.type.Review:
|
|
// route = `review/sched-info/${event.id}`;
|
|
// break;
|
|
}
|
|
if (route) {
|
|
const res = await window.$gz.api.get(route);
|
|
if (!res.error) {
|
|
this.evInfo = res.data;
|
|
this.moreInfoDialog = true;
|
|
} else {
|
|
this.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(this);
|
|
}
|
|
}
|
|
},
|
|
async fetchEvents({ start, end }) {
|
|
if (start) {
|
|
this.lastStart = start;
|
|
this.lastEnd = end;
|
|
} else {
|
|
start = this.lastStart;
|
|
end = this.lastEnd;
|
|
}
|
|
try {
|
|
window.$gz.form.deleteAllErrorBoxErrors(this);
|
|
const res = await window.$gz.api.post("schedule/user", {
|
|
view: window.$gz.util.calendarViewToAyaNovaEnum(this.viewType),
|
|
dark: this.$store.state.darkMode,
|
|
start: window.$gz.locale.localTimeDateStringToUTC8601String(
|
|
`${start.date}T00:00:00`,
|
|
this.timeZoneName
|
|
),
|
|
end: window.$gz.locale.localTimeDateStringToUTC8601String(
|
|
`${end.date}T23:59:59`,
|
|
this.timeZoneName
|
|
),
|
|
wisuColorSource: this.formUserOptions.wisuColorSource,
|
|
wisu: this.formUserOptions.wisu, //workorder item scheduled user records
|
|
reviews: this.formUserOptions.reviews,
|
|
reminders: this.formUserOptions.reminders,
|
|
userId: this.userId
|
|
});
|
|
if (res.error) {
|
|
this.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(this);
|
|
} else {
|
|
this.events.splice(0);
|
|
const timeZoneName = this.timeZoneName;
|
|
let i = res.data.length;
|
|
while (i--) {
|
|
const x = res.data[i];
|
|
this.events.push({
|
|
start: new Date(
|
|
new Date(x.start)
|
|
.toLocaleString("sv-SE", {
|
|
timeZone: timeZoneName
|
|
})
|
|
.replace(" ", "T")
|
|
).getTime(),
|
|
end: new Date(
|
|
new Date(x.end)
|
|
.toLocaleString("sv-SE", {
|
|
timeZone: timeZoneName
|
|
})
|
|
.replace(" ", "T")
|
|
).getTime(),
|
|
timed: true,
|
|
name: x.name,
|
|
color: x.color,
|
|
textColor: x.textColor,
|
|
type: x.type,
|
|
id: x.id,
|
|
editable: x.editable,
|
|
userId: x.userId
|
|
});
|
|
}
|
|
}
|
|
} catch (error) {
|
|
window.$gz.errorHandler.handleFormError(error, this);
|
|
}
|
|
},
|
|
async saveUserOptions() {
|
|
this.settingsDialog = false;
|
|
await saveFormUserOptions(this);
|
|
await this.refresh();
|
|
}
|
|
//eom
|
|
}
|
|
};
|
|
|
|
/////////////////////////////
|
|
//
|
|
//
|
|
async function clickHandler(menuItem) {
|
|
if (!menuItem) {
|
|
return;
|
|
}
|
|
const m = window.$gz.menu.parseMenuItem(menuItem);
|
|
if (m.owner == FORM_KEY && !m.disabled) {
|
|
switch (m.key) {
|
|
// case "report":
|
|
// const res = await m.vm.$refs.reportSelector.open(
|
|
// {
|
|
// AType: window.$gz.type.Project,
|
|
// selectedRowIds: [m.vm.obj.id]
|
|
// },
|
|
// m.id
|
|
// );
|
|
// if (res == null) {
|
|
// return;
|
|
// }
|
|
//
|
|
// window.$gz.form.setLastReportMenuItem(FORM_KEY, res, m.vm);
|
|
// break;
|
|
case "WorkOrderItemScheduledUserList":
|
|
m.vm.$router.push({
|
|
name: "svc-workorder-item-scheduled-users",
|
|
params: {
|
|
aType: window.$gz.type.User,
|
|
objectId: m.vm.userId,
|
|
name: m.vm.userName
|
|
}
|
|
});
|
|
break;
|
|
case "WorkOrderItemLaborList":
|
|
m.vm.$router.push({
|
|
name: "svc-workorder-item-labors",
|
|
params: {
|
|
aType: window.$gz.type.User,
|
|
objectId: m.vm.userId,
|
|
name: m.vm.userName
|
|
}
|
|
});
|
|
break;
|
|
|
|
case "ReminderList":
|
|
m.vm.$router.push({
|
|
name: "home-reminders"
|
|
});
|
|
break;
|
|
|
|
case "ReviewList":
|
|
m.vm.$router.push({
|
|
name: "home-reviews"
|
|
});
|
|
break;
|
|
|
|
default:
|
|
window.$gz.eventBus.$emit(
|
|
"notify-warning",
|
|
FORM_KEY + "::context click: [" + m.key + "]"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////
|
|
//
|
|
//
|
|
function generateMenu(vm) {
|
|
const menuOptions = {
|
|
isMain: true,
|
|
readOnly: vm.formState.readOnly,
|
|
icon: "$ayiCalendarDay",
|
|
title: "Schedule",
|
|
helpUrl: "svc-schedule",
|
|
formData: {
|
|
recordName: vm.userName
|
|
},
|
|
menuItems: []
|
|
};
|
|
|
|
// //
|
|
// menuOptions.menuItems.push({
|
|
// title: "Report",
|
|
// icon: "$ayiFileAlt",
|
|
// key: FORM_KEY + ":report",
|
|
// vm: vm
|
|
// });
|
|
|
|
//
|
|
// const lastReport = window.$gz.form.getLastReport(FORM_KEY);
|
|
// if (lastReport != null) {
|
|
// menuOptions.menuItems.push({
|
|
// title: lastReport.name,
|
|
// notrans: true,
|
|
// icon: "$ayiFileAlt",
|
|
// key: FORM_KEY + ":report:" + lastReport.id,
|
|
// vm: vm
|
|
// });
|
|
// }
|
|
|
|
// menuOptions.menuItems.push({
|
|
// title: "ReminderList",
|
|
// icon: "$ayiStickyNote",
|
|
// key: FORM_KEY + ":ReminderList",
|
|
// vm: vm
|
|
// });
|
|
|
|
// menuOptions.menuItems.push({
|
|
// title: "ReviewList",
|
|
// icon: "$ayiCalendarCheck",
|
|
// key: FORM_KEY + ":ReviewList",
|
|
// vm: vm
|
|
// });
|
|
|
|
menuOptions.menuItems.push({ divider: true, inset: false });
|
|
|
|
menuOptions.menuItems.push({
|
|
title: "WorkOrderItemScheduledUserList",
|
|
icon: "$ayiUserClock",
|
|
key: FORM_KEY + ":WorkOrderItemScheduledUserList",
|
|
vm: vm
|
|
});
|
|
|
|
if (vm.userId != 0) {
|
|
menuOptions.menuItems.push({
|
|
title: "WorkOrderItemLaborList",
|
|
icon: "$ayiHammer",
|
|
key: FORM_KEY + ":WorkOrderItemLaborList",
|
|
vm: vm
|
|
});
|
|
}
|
|
|
|
menuOptions.menuItems.push({ divider: true, inset: false });
|
|
|
|
window.$gz.eventBus.$emit("menu-change", menuOptions);
|
|
}
|
|
|
|
/////////////////////////////////
|
|
//
|
|
//
|
|
async function initForm(vm) {
|
|
await fetchTranslatedText();
|
|
getFormSettings(vm);
|
|
await getFormUserOptions(vm);
|
|
}
|
|
|
|
function getFormSettings(vm) {
|
|
let formSettings = window.$gz.form.getFormSettings(FORM_KEY);
|
|
if (!formSettings || !formSettings.temp || !formSettings.temp.viewType) {
|
|
//defaults
|
|
formSettings = { temp: { viewType: "month", focus: null } };
|
|
}
|
|
|
|
vm.viewType = formSettings.temp.viewType;
|
|
vm.focus = formSettings.temp.focus;
|
|
|
|
return formSettings;
|
|
}
|
|
|
|
function saveFormSettings(vm) {
|
|
const formSettings = window.$gz.form.getFormSettings(FORM_KEY);
|
|
formSettings.temp = { viewType: vm.viewType, focus: vm.focus };
|
|
|
|
window.$gz.form.setFormSettings(FORM_KEY, formSettings);
|
|
}
|
|
|
|
////////////////////
|
|
//
|
|
async function getFormUserOptions(vm) {
|
|
const res = await window.$gz.api.get(`form-user-options/${FORM_KEY}`);
|
|
if (res.error) {
|
|
vm.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(vm);
|
|
} else {
|
|
if (res.data == null) {
|
|
//make a default
|
|
vm.formUserOptions = {
|
|
firstTime: "00:00",
|
|
excludeDaysOfWeek: 0,
|
|
wisuColorSource: "2",
|
|
wisu: true,
|
|
reviews: true,
|
|
reminders: true
|
|
};
|
|
} else {
|
|
vm.formUserOptions = JSON.parse(res.data.options);
|
|
}
|
|
//takes local time in "HH:MM" format and converts to ISO UTC format for picker consumption
|
|
const d = new Date();
|
|
const temp = new Date(
|
|
d.getFullYear(),
|
|
d.getMonth(),
|
|
d.getDate(),
|
|
vm.formUserOptions.firstTime.split(":")[0],
|
|
vm.formUserOptions.firstTime.split(":")[1]
|
|
);
|
|
vm.tempFirstTime = window.$gz.locale.localTimeDateStringToUTC8601String(
|
|
temp.toISOString(),
|
|
vm.timeZoneName
|
|
);
|
|
}
|
|
}
|
|
|
|
////////////////////
|
|
//
|
|
async function saveFormUserOptions(vm) {
|
|
//translate tempFirstTime to local time
|
|
if (vm.tempFirstTime) {
|
|
//convert picker's utc time to local hour:MM
|
|
const localTime = window.$gz.DateTime.fromISO(vm.tempFirstTime).toLocal();
|
|
vm.formUserOptions.firstTime = `${localTime.hour}:${localTime.minute}`;
|
|
}
|
|
const res = await window.$gz.api.post("form-user-options", {
|
|
formKey: FORM_KEY,
|
|
options: JSON.stringify(vm.formUserOptions)
|
|
});
|
|
if (res.error) {
|
|
vm.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(vm);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//
|
|
// Ensures UI translated text is available
|
|
//
|
|
async function fetchTranslatedText() {
|
|
await window.$gz.translation.cacheTranslations([
|
|
"DateRangeToday",
|
|
"ExcludeDaysOfWeek",
|
|
"ScheduleMonth",
|
|
"ScheduleDay",
|
|
"ScheduleWeek",
|
|
"Schedule4Day",
|
|
"ScheduleFirstHour",
|
|
"ScheduleWOColorFrom",
|
|
"ScheduleOptions",
|
|
"ScheduleShowTypes",
|
|
"NoColor",
|
|
"WorkOrder",
|
|
"Reminder",
|
|
"WorkOrderList",
|
|
"ReminderList",
|
|
"ReviewList",
|
|
"DashboardScheduled",
|
|
"WorkOrderItemScheduledUserUserID",
|
|
"WorkOrderItemPriorityID",
|
|
"WorkOrderItemSummary",
|
|
"WorkOrderItemWorkOrderStatusID",
|
|
"WorkOrderStatus",
|
|
"WorkOrderItemScheduledUserEstimatedQuantity",
|
|
"WorkOrderItemScheduledUserServiceRateID",
|
|
"WorkOrderItemTags",
|
|
"ReminderName",
|
|
"ReviewDate",
|
|
"ReminderNotes",
|
|
"ReviewName",
|
|
"ReviewNotes",
|
|
"ReviewCompletedDate",
|
|
"ReviewCompletionNotes"
|
|
]);
|
|
}
|
|
</script>
|
|
<style scoped lang="scss">
|
|
.v-event-draggable {
|
|
padding-left: 6px;
|
|
}
|
|
|
|
.v-event-timed {
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
}
|
|
|
|
.v-event-drag-bottom {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 4px;
|
|
height: 4px;
|
|
cursor: ns-resize;
|
|
|
|
&::after {
|
|
display: none;
|
|
position: absolute;
|
|
left: 50%;
|
|
height: 4px;
|
|
border-top: 1px solid gray;
|
|
border-bottom: 1px solid gray;
|
|
width: 32px;
|
|
margin-left: -8px;
|
|
// opacity: 0.8;
|
|
content: "";
|
|
}
|
|
|
|
&:hover::after {
|
|
display: block;
|
|
}
|
|
}
|
|
</style>
|