The machine's own type is blank for the 134 machines that came from the classic ASP database on machinetypeid=1, a LocationOnly placeholder the import refuses to carry across as a real subtype. The catalog model knows what those machines are, and its type is populated, so the column reads modeltypename under a heading that says so. Where both values exist they are identical - all 262 machines in the development database match exactly - so nothing is lost by showing the one that is reliably filled in. This does not fix the underlying gap. A null machinetypeid also excludes a machine from the map's subtype filter and drops its marker to the default colour, and no column heading affects that. Only populating machinetypeid does, which is what the backfill script is for.
155 lines
4.5 KiB
Vue
155 lines
4.5 KiB
Vue
<template>
|
|
<div>
|
|
<div class="page-header">
|
|
<h2>Machines</h2>
|
|
<router-link to="/print/asset-label-batch/machine" class="btn btn-secondary" target="_blank">Print Labels</router-link>
|
|
<router-link to="/machines/new" class="btn btn-primary">Add Machine</router-link>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="filters">
|
|
<input
|
|
v-model="search"
|
|
type="text"
|
|
class="form-control"
|
|
placeholder="Search machines..."
|
|
@input="debouncedSearch"
|
|
/>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div v-if="loading" class="loading">Loading...</div>
|
|
|
|
<template v-else>
|
|
<div class="table-container">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Machine #</th>
|
|
<th>Name</th>
|
|
<th>Serial Number</th>
|
|
<th>Model Type</th>
|
|
<th>Vendor</th>
|
|
<th>Status</th>
|
|
<th>Location</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="item in machines" :key="item.assetid" class="clickable-row" @click="$router.push(`/machines/${item.machine?.machineid || item.assetid}`)">
|
|
<td>
|
|
{{ item.assetnumber }}<template v-if="item.dualpathpartner"> / {{ item.dualpathpartner.assetnumber }}</template>
|
|
</td>
|
|
<td>{{ item.name || '-' }}</td>
|
|
<td class="mono">{{ item.serialnumber || '-' }}</td>
|
|
<!--
|
|
The catalog model's type, not the machine's own. 134 machines
|
|
arrived from the classic ASP database on machinetypeid=1 - a
|
|
LocationOnly placeholder the import refuses to carry across as
|
|
a real subtype - so Machine Type is blank for them while the
|
|
model knows exactly what they are.
|
|
-->
|
|
<td>{{ item.machine?.modeltypename || '-' }}</td>
|
|
<td>{{ item.machine?.vendorname || '-' }}</td>
|
|
<td>
|
|
<span class="badge" :style="colorStyle(item.statuscolor)">
|
|
{{ item.statusname || 'Unknown' }}
|
|
</span>
|
|
</td>
|
|
<td>{{ item.locationname || '-' }}</td>
|
|
<td class="actions" @click.stop>
|
|
<router-link
|
|
:to="`/machines/${item.machine?.machineid || item.assetid}`"
|
|
class="btn btn-secondary btn-sm"
|
|
>
|
|
View
|
|
</router-link>
|
|
</td>
|
|
</tr>
|
|
<tr v-if="machines.length === 0">
|
|
<td colspan="8" style="text-align: center; color: var(--text-light);">
|
|
No machines found
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<PaginationBar
|
|
:page="page"
|
|
:totalPages="totalPages"
|
|
:perPage="perPage"
|
|
@update:page="goToPage"
|
|
@update:perPage="changePerPage"
|
|
/>
|
|
</template>
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { colorStyle } from "@/utils/colorStyle"
|
|
import { machinesApi } from '@/api'
|
|
import PaginationBar from '@/components/PaginationBar.vue'
|
|
import { useListQuery } from '@/composables/listQuery'
|
|
|
|
const machines = ref([])
|
|
const loading = ref(true)
|
|
const { page, search, setPage, setSearch } = useListQuery({ onChange: loadMachines })
|
|
const totalPages = ref(1)
|
|
const perPage = ref(20)
|
|
|
|
let searchTimeout = null
|
|
|
|
onMounted(() => {
|
|
loadMachines()
|
|
})
|
|
|
|
async function loadMachines() {
|
|
loading.value = true
|
|
try {
|
|
const params = {
|
|
page: page.value,
|
|
perpage: perPage.value
|
|
}
|
|
if (search.value) params.search = search.value
|
|
|
|
const response = await machinesApi.list(params)
|
|
machines.value = response.data.data || []
|
|
totalPages.value = response.data.meta?.pagination?.totalpages || response.data.meta?.pagination?.total_pages || 1
|
|
} catch (error) {
|
|
console.error('Error loading machines:', error)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function debouncedSearch() {
|
|
clearTimeout(searchTimeout)
|
|
searchTimeout = setTimeout(() => {
|
|
setSearch(search.value)
|
|
loadMachines()
|
|
}, 300)
|
|
}
|
|
|
|
function goToPage(p) {
|
|
setPage(p)
|
|
loadMachines()
|
|
}
|
|
|
|
function changePerPage(newPerPage) {
|
|
perPage.value = newPerPage
|
|
setPage(1)
|
|
loadMachines()
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.mono {
|
|
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
|
}
|
|
</style>
|