365 lines
11 KiB
Vue
365 lines
11 KiB
Vue
<template>
|
|
<div v-if="value != null">
|
|
<!-- Title and menu -->
|
|
<v-col cols="12">
|
|
<v-menu offset-y>
|
|
<template v-slot:activator="{ on, attrs }">
|
|
<div class="text-h6">
|
|
<v-icon large color="primary">$ayiWrench</v-icon>
|
|
{{ $ay.t("WorkOrderItemList") }}
|
|
<v-btn large icon v-bind="attrs" v-on="on">
|
|
<v-icon small color="primary">$ayiEllipsisV</v-icon>
|
|
</v-btn>
|
|
</div>
|
|
</template>
|
|
<v-list>
|
|
<v-list-item v-if="canAdd" @click="newItem">
|
|
<v-list-item-icon>
|
|
<v-icon>$ayiPlus</v-icon>
|
|
</v-list-item-icon>
|
|
<v-list-item-title>{{ $ay.t("New") }}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item v-if="canDelete" @click="deleteItem">
|
|
<v-list-item-icon>
|
|
<v-icon>$ayiTrashAlt</v-icon>
|
|
</v-list-item-icon>
|
|
<v-list-item-title>{{ $ay.t("Delete") }}</v-list-item-title>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
</v-col>
|
|
|
|
<template v-if="showTable">
|
|
<!-- ################################ WORK ORDER ITEMS TABLE ############################### -->
|
|
<v-col cols="12">
|
|
<v-data-table
|
|
:headers="headerList"
|
|
:items="itemList"
|
|
item-key="index"
|
|
v-model="selectedRow"
|
|
class="elevation-1"
|
|
disable-pagination
|
|
disable-filtering
|
|
disable-sort
|
|
hide-default-footer
|
|
data-cy="itemsTable"
|
|
dense
|
|
:item-class="itemRowClasses"
|
|
@click:row="handleRowClick"
|
|
:show-select="$vuetify.breakpoint.xs"
|
|
single-select
|
|
>
|
|
</v-data-table>
|
|
</v-col>
|
|
</template>
|
|
<template v-if="activeItemIndex != null">
|
|
<v-col v-if="form().showMe(this, 'WorkOrderItemSummary')" cols="12">
|
|
<v-textarea
|
|
v-model="value.items[activeItemIndex].notes"
|
|
:readonly="formState.readOnly"
|
|
:label="$ay.t('WorkOrderItemSummary')"
|
|
:error-messages="
|
|
form().serverErrors(this, `items[${activeItemIndex}].notes`)
|
|
"
|
|
ref="notes"
|
|
data-cy="notes"
|
|
@input="fieldValueChanged('notes')"
|
|
auto-grow
|
|
></v-textarea>
|
|
</v-col>
|
|
|
|
<v-col
|
|
v-if="form().showMe(this, 'Sequence')"
|
|
cols="12"
|
|
sm="6"
|
|
lg="4"
|
|
xl="3"
|
|
>
|
|
<v-text-field
|
|
v-model="value.items[activeItemIndex].sequence"
|
|
:readonly="formState.readOnly"
|
|
:label="$ay.t('Sequence')"
|
|
ref="sequence"
|
|
:rules="[form().integerValid(this, 'sequence')]"
|
|
:error-messages="form().serverErrors(this, 'sequence')"
|
|
@input="fieldValueChanged('sequence')"
|
|
type="number"
|
|
></v-text-field>
|
|
</v-col>
|
|
|
|
<v-col v-if="form().showMe(this, 'WorkOrderItemTechNotes')" cols="12">
|
|
<v-textarea
|
|
v-model="value.items[activeItemIndex].techNotes"
|
|
:readonly="formState.readOnly"
|
|
:label="$ay.t('WorkOrderItemTechNotes')"
|
|
:error-messages="form().serverErrors(this, 'techNotes')"
|
|
ref="techNotes"
|
|
data-cy="techNotes"
|
|
@input="fieldValueChanged('techNotes')"
|
|
auto-grow
|
|
></v-textarea>
|
|
</v-col>
|
|
|
|
<GzWoItemScheduledUsers
|
|
v-if="pvm.subRights.scheduledUsers.visible"
|
|
v-model="value"
|
|
:pvm="pvm"
|
|
:active-wo-item-index="activeItemIndex"
|
|
data-cy="woItemScheduledUsers"
|
|
@graph-item-deleted="$emit('graph-item-deleted', $event)"
|
|
@change="$emit('change')"
|
|
/>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/* XXXeslint-disable */
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
import GzWoItemScheduledUsers from "../components/work-order-item-scheduled-users.vue";
|
|
|
|
export default {
|
|
components: {
|
|
GzWoItemScheduledUsers
|
|
},
|
|
created() {
|
|
this.setDefaultView();
|
|
},
|
|
data() {
|
|
return {
|
|
activeItemIndex: null,
|
|
selectedRow: []
|
|
};
|
|
},
|
|
props: {
|
|
value: {
|
|
default: null,
|
|
type: Object
|
|
},
|
|
pvm: {
|
|
default: null,
|
|
type: Object
|
|
}
|
|
},
|
|
methods: {
|
|
newItem() {
|
|
let newIndex = this.value.items.length;
|
|
this.value.items.push({
|
|
id: 0,
|
|
concurrency: 0,
|
|
notes: null,
|
|
wiki: null,
|
|
customFields: "{}",
|
|
tags: [],
|
|
workOrderId: this.value.id,
|
|
techNotes: null,
|
|
workorderItemStatusId: null,
|
|
workorderItemPriorityId: null,
|
|
requestDate: null,
|
|
warrantyService: false,
|
|
sequence: newIndex + 1, //indexes are zero based but sequences are visible to user so 1 based
|
|
isDirty: true,
|
|
expenses: [],
|
|
labors: [],
|
|
loans: [],
|
|
parts: [],
|
|
partRequests: [],
|
|
scheduledUsers: [],
|
|
tasks: [],
|
|
travels: [],
|
|
units: [],
|
|
outsideServices: []
|
|
});
|
|
this.$emit("change");
|
|
this.selectedRow = [{ index: newIndex }];
|
|
this.activeItemIndex = newIndex;
|
|
},
|
|
async deleteItem() {
|
|
if ((await window.$gz.dialog.confirmDelete()) != true) {
|
|
return;
|
|
}
|
|
|
|
let o = this.value.items[this.activeItemIndex];
|
|
if (o.id != 0) {
|
|
//it's a previously saved item so it needs to be removed at the server too
|
|
this.$emit("graph-item-deleted", {
|
|
atype: window.$gz.type.WorkOrderItem,
|
|
id: o.id,
|
|
objectIndex: this.activeItemIndex
|
|
});
|
|
}
|
|
this.value.items.splice(this.activeItemIndex, 1);
|
|
this.setDefaultView();
|
|
},
|
|
setDefaultView: function() {
|
|
//if only one record left then display it otherwise just let the datatable show what the user can click on
|
|
if (this.value && this.value.items && this.value.items.length == 1) {
|
|
this.selectedRow = [{ index: 0 }];
|
|
this.activeItemIndex = 0;
|
|
} else {
|
|
this.selectedRow = [];
|
|
this.activeItemIndex = null; //select nothing in essence resetting a child selects and this one too clearing form
|
|
}
|
|
},
|
|
handleRowClick: function(item) {
|
|
this.activeItemIndex = item.index;
|
|
this.selectedRow = [{ index: item.index }];
|
|
},
|
|
form() {
|
|
return window.$gz.form;
|
|
},
|
|
fieldValueChanged(ref) {
|
|
if (!this.formState.loading && !this.formState.readonly) {
|
|
//flag this record dirty so it gets picked up by save
|
|
this.value.items[this.activeItemIndex].isDirty = true;
|
|
window.$gz.form.fieldValueChanged(this.pvm, ref);
|
|
}
|
|
},
|
|
itemRowClasses: function(item) {
|
|
const path = `Items[${item.index}].`;
|
|
if (this.form().childRowHasError(this, path)) {
|
|
return "font-weight-black font-italic error--text";
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
headerList: function() {
|
|
/*
|
|
public uint Concurrency { get; set; }
|
|
public string Notes { get; set; }//Was Summary
|
|
public string Wiki { get; set; }
|
|
public string CustomFields { get; set; }
|
|
public List<string> Tags { get; set; } = new List<string>();
|
|
|
|
[Required]
|
|
public long WorkOrderId { get; set; }
|
|
public string TechNotes { get; set; }
|
|
public long? WorkorderItemStatusId { get; set; }
|
|
public long? WorkorderItemPriorityId { get; set; }
|
|
public DateTime RequestDate { get; set; }
|
|
public bool WarrantyService { get; set; } = false;
|
|
|
|
|
|
IN ORDER: notes, status, date, priority, warranty, tags
|
|
|
|
except they will not prefill at server but will be set here since the wo differs from the po in that there is no instant update with new viz fields to populate from server
|
|
and it's probably not a big list to fill anyway
|
|
|
|
|
|
If the column is a text, left-align it
|
|
If the column is a number or number + unit, (or date) right-align it (like excel)
|
|
*/
|
|
let headers = [];
|
|
|
|
if (this.form().showMe(this, "Items.Sequence")) {
|
|
headers.push({
|
|
text: this.$ay.t("Sequence"),
|
|
align: "left",
|
|
value: "sequence"
|
|
});
|
|
}
|
|
|
|
headers.push({
|
|
text: this.$ay.t("WorkOrderItemSummary"), //mandatory not hidden
|
|
align: "left",
|
|
value: "notes"
|
|
});
|
|
|
|
if (this.form().showMe(this, "Items.WorkOrderItemWorkOrderStatusID")) {
|
|
headers.push({
|
|
text: this.$ay.t("WorkOrderItemWorkOrderStatusID"),
|
|
align: "left",
|
|
value: "status"
|
|
});
|
|
}
|
|
|
|
if (this.form().showMe(this, "Items.RequestDate")) {
|
|
headers.push({
|
|
text: this.$ay.t("WorkOrderItemRequestDate"),
|
|
align: "right",
|
|
value: "requestDate"
|
|
});
|
|
}
|
|
|
|
if (this.form().showMe(this, "Items.WorkOrderItemPriorityID")) {
|
|
headers.push({
|
|
text: this.$ay.t("WorkOrderItemPriorityID"),
|
|
align: "left",
|
|
value: "priority"
|
|
});
|
|
}
|
|
|
|
if (this.form().showMe(this, "Items.WorkOrderItemWarrantyService")) {
|
|
headers.push({
|
|
text: this.$ay.t("WorkOrderItemWarrantyService"),
|
|
align: "center",
|
|
value: "warranty"
|
|
});
|
|
}
|
|
|
|
if (this.form().showMe(this, "Items.Tags")) {
|
|
headers.push({
|
|
text: this.$ay.t("Tags"),
|
|
align: "left",
|
|
value: "tags"
|
|
});
|
|
}
|
|
|
|
// headers.push({ text: "", value: "actions" });
|
|
|
|
return headers;
|
|
},
|
|
itemList: function() {
|
|
return this.value.items
|
|
.map((x, i) => {
|
|
return {
|
|
index: i,
|
|
id: x.id,
|
|
sequence: x.sequence,
|
|
notes: x.notes,
|
|
quantityReceived: window.$gz.locale.decimalLocalized(
|
|
x.quantityReceived,
|
|
this.pvm.languageName
|
|
),
|
|
status: x.workorderItemStatusId, //todo: get real status name etc here
|
|
requestDate: window.$gz.locale.utcDateToShortDateAndTimeLocalized(
|
|
x.requestDate,
|
|
this.pvm.timeZoneName,
|
|
this.pvm.languageName,
|
|
this.pvm.hour12
|
|
),
|
|
priority: x.workorderItemPriorityId, //todo: get actual priority, color etc here
|
|
warranty: x.warrantyService,
|
|
tags: x.tags
|
|
};
|
|
})
|
|
.sort((a, b) => a.sequence - b.sequence);
|
|
},
|
|
formState: function() {
|
|
return this.pvm.formState;
|
|
},
|
|
formCustomTemplateKey: function() {
|
|
return this.pvm.formCustomTemplateKey;
|
|
},
|
|
showTable: function() {
|
|
return this.value && this.value.items && this.value.items.length > 1;
|
|
},
|
|
canAdd: function() {
|
|
return (
|
|
!this.pvm.formState.readOnly &&
|
|
this.pvm.rights.change &&
|
|
this.pvm.subRights.items.create
|
|
);
|
|
},
|
|
canDelete: function() {
|
|
return (
|
|
this.activeItemIndex != null &&
|
|
!this.pvm.formState.readOnly &&
|
|
this.pvm.rights.change &&
|
|
this.pvm.subRights.items.delete
|
|
);
|
|
}
|
|
}
|
|
};
|
|
</script>
|