|
|
@@ -0,0 +1,250 @@
|
|
|
+<template>
|
|
|
+ <div class="container-fluid">
|
|
|
+ <div class="row my-3">
|
|
|
+ <div class="col-lg-6">
|
|
|
+ <div class="card h-100">
|
|
|
+ <div class="card-header text-right">
|
|
|
+ <button type="button" class="btn btn-default xs-toggle" data-toggle="collapse" data-target="#assetTab">
|
|
|
+ <span class="sr-only">Toggle Navigation</span>
|
|
|
+ <span class="icon-bar"></span>
|
|
|
+ <span class="icon-bar"></span>
|
|
|
+ <span class="icon-bar"></span>
|
|
|
+ </button>
|
|
|
+ <ul class="nav nav-pills card-header-pills nav-justified xs-collapse collapse" id="assetTab" role="tablist">
|
|
|
+ <li class="nav-item">
|
|
|
+ <a class="nav-link active" id="assetinfo-tab" data-toggle="pill" href="#assetinfo" role="tab" aria-controls="assetinfo" aria-selected="true">Hardware</a>
|
|
|
+ </li>
|
|
|
+ <!-- @if($workOrder->asset->group !== null)
|
|
|
+ <li class="nav-item">
|
|
|
+ <a class="nav-link" id="group-tab" data-toggle="pill" href="#group" role="tab" aria-controls="group" aria-selected="false">Group</a>
|
|
|
+ </li>
|
|
|
+ @endif -->
|
|
|
+ <li class="nav-item">
|
|
|
+ <a class="nav-link" id="credentials-tab" data-toggle="pill" href="#credentials" role="tab" aria-controls="credentials" aria-selected="false">Credentials</a>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="tab-pane active" id="assetinfo" role="tabpanel" aria-labelledby="assetinfo-tab">
|
|
|
+ <asset-info v-if="!assetLoading" :asset="asset"></asset-info>
|
|
|
+ <circle-spinner v-else :color="'#663399'"></circle-spinner>
|
|
|
+ </div>
|
|
|
+ <!-- @if($workOrder->asset->group !== null)
|
|
|
+ <div class="tab-pane" id="group" role="tabpanel" aria-labelledby="group-tab">
|
|
|
+ Name: {{$workOrder->asset->group->pcgroupname}}
|
|
|
+ </div>
|
|
|
+ @endif -->
|
|
|
+ <div class="tab-pane" id="credentials" role="tabpanel" aria-labelledby="credentials-tab">
|
|
|
+ <credential-list v-if="!credentialsLoading && !credentialDescriptionsLoading" :credentials="credentials" :descriptions="credentialDescriptions" :pcid="asset.pcid"></credential-list>
|
|
|
+ <circle-spinner v-else color="#663399"></circle-spinner>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="col-lg-6">
|
|
|
+ <div class="card h-100">
|
|
|
+ <div class="card-header text-right">
|
|
|
+ <button type="button" class="btn btn-default xs-toggle" data-toggle="collapse" data-target="#workorderTab">
|
|
|
+ <span class="sr-only">Toggle Navigation</span>
|
|
|
+ <span class="icon-bar"></span>
|
|
|
+ <span class="icon-bar"></span>
|
|
|
+ <span class="icon-bar"></span>
|
|
|
+ </button>
|
|
|
+ <ul class="nav nav-pills card-header-pills nav-justified xs-collapse collapse" id="workorderTab" role="tablist">
|
|
|
+ <li class="nav-item">
|
|
|
+ <a class="nav-link active" id="workordersumm-tab" data-toggle="pill" href="#workordersumm" role="tab" aria-controls="workordersumm" aria-selected="true">Summary</a>
|
|
|
+ </li>
|
|
|
+ <li class="nav-item">
|
|
|
+ <a class="nav-link" id="attachments-tab" data-toggle="pill" href="#attachments" role="tab" aria-controls="attachments" aria-selected="false">Attachments</a>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ <div class='card-body'>
|
|
|
+ <div class='tab-content'>
|
|
|
+ <div class="tab-pane active" id="workordersumm" role="tabpanel" aria-labelledby="workordersumm-tab">
|
|
|
+ <work-order-info v-if="!woLoading && !storesLoading" :work-order="workOrder" :stores="stores"></work-order-info>
|
|
|
+ <circle-spinner v-else :color="'#663399'"></circle-spinner>
|
|
|
+ </div>
|
|
|
+ <div class="tab-pane" id="attachments" role="tabpanel" aria-labelledby="attachments-tab">
|
|
|
+ TODO 2
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row my-3 no-gutters">
|
|
|
+ <div class="col-12">
|
|
|
+ <div class="card">
|
|
|
+ <div class="card-body">
|
|
|
+ <h5 class="card-title">Customer Notes</h5>
|
|
|
+ <notes v-if="!workOrderNotesLoading" :notes="publicNotes" :authusername="authUser" :note-type="0" :woid="id"></notes>
|
|
|
+ <circle-spinner v-else color="#663399"></circle-spinner>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="row my-3 no-gutters">
|
|
|
+ <div class="col-12">
|
|
|
+ <div class="card">
|
|
|
+ <div class="card-body">
|
|
|
+ <h5 class="card-title">Private/Billing Notes</h5>
|
|
|
+ <notes v-if="!workOrderNotesLoading" :notes="privateNotes" :authusername="authUser" :note-type="1" :woid="id"></notes>
|
|
|
+ <circle-spinner v-else color="#663399"></circle-spinner>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import WorkOrderInfo from '../components/WorkOrderInfo.vue'
|
|
|
+import AssetInfo from '../components/AssetInfo.vue'
|
|
|
+import CircleSpinner from '../components/CircleSpinner.vue'
|
|
|
+import CredentialList from '../components/CredentialList.vue'
|
|
|
+import Notes from '../components/Notes.vue'
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ WorkOrderInfo,
|
|
|
+ AssetInfo,
|
|
|
+ CircleSpinner,
|
|
|
+ CredentialList,
|
|
|
+ Notes,
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ id: {
|
|
|
+ type: String,
|
|
|
+ required: true,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data () {
|
|
|
+ return {
|
|
|
+ workOrder: {},
|
|
|
+ asset: {},
|
|
|
+ stores: {},
|
|
|
+ credentials: {},
|
|
|
+ credentialDescriptions: {},
|
|
|
+ workOrderNotes: [],
|
|
|
+ woLoading: true,
|
|
|
+ assetLoading: true,
|
|
|
+ storesLoading: true,
|
|
|
+ credentialsLoading: true,
|
|
|
+ credentialDescriptionsLoading: true,
|
|
|
+ workOrderNotesLoading: true,
|
|
|
+ authUser: localStorage.getItem('user'),
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ publicNotes: function() {
|
|
|
+ let notes = []
|
|
|
+ notes = this.workOrderNotes.filter(note => note.notetype === 0)
|
|
|
+ return notes
|
|
|
+ },
|
|
|
+ privateNotes: function() {
|
|
|
+ let notes = []
|
|
|
+ notes = this.workOrderNotes.filter(note => note.notetype === 1)
|
|
|
+ return notes
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ // Get authentication info from current user from local storage
|
|
|
+ let token = localStorage.getItem('jwt')
|
|
|
+ let user = localStorage.getItem('user')
|
|
|
+
|
|
|
+ // Set some axios config options for Content-Type and Authentication.
|
|
|
+ axios.defaults.headers.common['Content-Type'] = 'application/json'
|
|
|
+ axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
|
|
|
+
|
|
|
+ // Get WorkOrder from API
|
|
|
+ axios.get('/api/workorders/'+this.id).then(response => {
|
|
|
+ this.workOrder = response.data
|
|
|
+ this.woLoading = false
|
|
|
+ }).catch(error => {
|
|
|
+ console.log(error)
|
|
|
+ })
|
|
|
+
|
|
|
+ // Get list of stores from API
|
|
|
+ axios.get('/api/stores/').then(response => {
|
|
|
+ this.stores = response.data
|
|
|
+ this.storesLoading = false
|
|
|
+ }).catch(error => {
|
|
|
+ console.log(error)
|
|
|
+ })
|
|
|
+
|
|
|
+ // Get Asset from API (will most likely be replaced with list of assets
|
|
|
+ // in the future. Current each WO can only have one but that is likely
|
|
|
+ // to change)
|
|
|
+ axios.get(`/api/workorders/${this.id}/asset`).then(response => {
|
|
|
+ this.asset = response.data
|
|
|
+ this.assetLoading = false
|
|
|
+
|
|
|
+ // Establish listener for liveupdate broadcasts.
|
|
|
+ // Must be done here or we can't guarantee this.asset
|
|
|
+ // exists by the time we execute this code.
|
|
|
+ Echo.channel('asset.'+this.asset.pcid)
|
|
|
+ .listen('AssetUpdated', (e) => {
|
|
|
+ this.asset = e.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ // Get Credentials for this asset. May be relocated to be part of asset
|
|
|
+ // Component when WOs can have more than one asset.
|
|
|
+ axios.get(`/api/assets/${this.asset.pcid}/credentials`).then (response => {
|
|
|
+ this.credentials = response.data
|
|
|
+ this.credentialsLoading = false
|
|
|
+ }).catch(error => {
|
|
|
+ console.log(error)
|
|
|
+ })
|
|
|
+
|
|
|
+ // Get default list of Credential Descriptions. May be relocated along with
|
|
|
+ // the above.
|
|
|
+ axios.get('/api/credentials/descriptions').then(response => {
|
|
|
+ this.credentialDescriptions = response.data
|
|
|
+ this.credentialDescriptionsLoading = false
|
|
|
+ }).catch(error => {
|
|
|
+ console.log(error)
|
|
|
+ })
|
|
|
+ }).catch(error => {
|
|
|
+ console.log(error)
|
|
|
+ })
|
|
|
+
|
|
|
+ axios.get(`/api/workorders/${this.id}/notes`).then(response => {
|
|
|
+ this.workOrderNotes = response.data
|
|
|
+ this.workOrderNotesLoading = false
|
|
|
+ }).catch(error => {
|
|
|
+ console.log(error)
|
|
|
+ })
|
|
|
+
|
|
|
+ Echo.channel('work-order.'+this.id)
|
|
|
+ .listen('WorkOrderUpdated', (e) => {
|
|
|
+ this.workOrder = e.data;
|
|
|
+ });
|
|
|
+
|
|
|
+ Echo.channel('wonotes.'+this.id)
|
|
|
+ .listen('WorkOrderNoteAdded', (e) => {
|
|
|
+ this.workOrderNotes.push(e.note)
|
|
|
+ })
|
|
|
+ .listen('WorkOrderNoteUpdated', (e) => {
|
|
|
+ let index = this.workOrderNotes.findIndex((note) => {
|
|
|
+ return note.noteid === e.note.noteid
|
|
|
+ })
|
|
|
+ // Sometimes when switching or deleting items from the end of a list,
|
|
|
+ // They go away before the modal can be hidden, this will hide the
|
|
|
+ // modal in case the component can't hide it itself. There may be
|
|
|
+ // a better way to do this.
|
|
|
+ $(`#note${e.note.noteid}switchModal`).modal('hide')
|
|
|
+ // Note has to be edited this way, or else Vue cannot
|
|
|
+ // see it to recompute the computed values.
|
|
|
+ this.workOrderNotes.splice(index, 1, e.note)
|
|
|
+ })
|
|
|
+ .listen('WorkOrderNoteDeleted', (e) => {
|
|
|
+ let index = this.workOrderNotes.findIndex((note) => {
|
|
|
+ return note.noteid === e.note['noteid']
|
|
|
+ })
|
|
|
+ $(`#note${e.note['noteid']}deleteModal`).modal('hide')
|
|
|
+ this.workOrderNotes.splice(index, 1)
|
|
|
+ })
|
|
|
+ },
|
|
|
+}
|
|
|
+</script>
|