Files
MixedAssets/src/views/AssignmentsView.vue
2026-06-03 13:58:12 -05:00

169 lines
6.6 KiB
Vue

<template>
<section class="content-grid">
<v-card class="metric span-3">
<div class="metric-label">Assigned</div>
<div class="metric-value">{{ summary.active_assignments || 0 }}</div>
<div class="metric-subtle">Assets with active custody</div>
</v-card>
<v-card class="metric span-3">
<div class="metric-label">Unassigned</div>
<div class="metric-value">{{ summary.unassigned_assets || 0 }}</div>
<div class="metric-subtle">Need owner/location review</div>
</v-card>
<v-card class="metric span-3">
<div class="metric-label">Employees</div>
<div class="metric-value">{{ employees.length }}</div>
<div class="metric-subtle">Manual or Workday synced</div>
</v-card>
<v-card class="metric span-3">
<div class="metric-label">Locations</div>
<div class="metric-value">{{ summary.assigned_locations || 0 }}</div>
<div class="metric-subtle">Active assignment sites</div>
</v-card>
<v-card class="span-5 panel-pad">
<h2 class="section-title mb-4">Assign asset</h2>
<v-select v-model="assignmentForm.asset_id" :items="assetOptions" item-title="title" item-value="value" label="Asset" />
<v-select v-model="assignmentForm.employee_id" :items="employeeOptions" item-title="title" item-value="value" clearable label="Employee" @update:model-value="applyEmployeeDefaults" />
<v-text-field v-model="assignmentForm.department" label="Department" />
<v-text-field v-model="assignmentForm.location" label="Location" />
<v-textarea v-model="assignmentForm.notes" label="Notes" rows="2" />
<v-btn color="primary" prepend-icon="mdi-account-check" :loading="assignmentSaving" @click="$emit('assign-asset', assignmentForm)">Assign asset</v-btn>
</v-card>
<v-card class="span-7 panel-pad">
<div class="toolbar-row mb-4">
<h2 class="section-title">Employees</h2>
<v-spacer />
<v-btn variant="tonal" prepend-icon="mdi-account-plus" @click="employeeDialog = true">Add employee</v-btn>
</div>
<v-list lines="two">
<v-list-item v-for="employee in employees" :key="employee.id" prepend-icon="mdi-account">
<v-list-item-title>{{ employee.name }}</v-list-item-title>
<v-list-item-subtitle>{{ employee.email || employee.employee_number }} · {{ employee.department || 'No department' }} · {{ employee.location || 'No location' }}</v-list-item-subtitle>
<template #append>
<v-chip size="small" variant="tonal">{{ employee.source }}</v-chip>
</template>
</v-list-item>
</v-list>
</v-card>
<v-card class="span-12 panel-pad">
<div class="toolbar-row mb-4">
<h2 class="section-title">Traceability</h2>
<v-spacer />
<v-btn variant="tonal" prepend-icon="mdi-refresh" @click="$emit('reload')">Refresh</v-btn>
</div>
<div style="overflow-x:auto">
<table class="asset-table">
<thead>
<tr>
<th>Asset</th>
<th>Employee</th>
<th>Department</th>
<th>Location</th>
<th>Assigned</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="assignment in assignments" :key="assignment.id">
<td>
<strong>{{ assignment.asset_code }}</strong><br />
<span class="quiet">{{ assignment.asset_description }}</span>
</td>
<td>{{ assignment.employee_name || 'Unassigned employee' }}</td>
<td>{{ assignment.department || '-' }}</td>
<td>{{ assignment.location || '-' }}</td>
<td>{{ shortDate(assignment.assigned_at) }}</td>
<td><span :class="['status-chip', assignment.active ? 'status-in_service' : 'status-disposed']">{{ assignment.status }}</span></td>
<td class="text-right">
<v-btn v-if="assignment.active" size="small" variant="text" color="warning" @click="$emit('release-assignment', assignment)">Release</v-btn>
</td>
</tr>
</tbody>
</table>
</div>
</v-card>
<v-dialog v-model="employeeDialog" max-width="480">
<v-card>
<v-card-title>Add employee</v-card-title>
<v-card-text>
<v-text-field v-model="employeeForm.name" label="Name" />
<v-text-field v-model="employeeForm.email" label="Email" />
<v-text-field v-model="employeeForm.employee_number" label="Employee number" />
<v-text-field v-model="employeeForm.department" label="Department" />
<v-text-field v-model="employeeForm.location" label="Location" />
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn variant="text" @click="employeeDialog = false">Cancel</v-btn>
<v-btn color="primary" @click="saveEmployee">Save employee</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</section>
</template>
<script>
export default {
props: {
assignments: { type: Array, required: true },
assets: { type: Array, required: true },
assignmentSaving: { type: Boolean, default: false },
employees: { type: Array, required: true },
shortDate: { type: Function, required: true },
summary: { type: Object, required: true }
},
emits: ['add-employee', 'assign-asset', 'release-assignment', 'reload'],
data() {
return {
assignmentForm: {
asset_id: null,
employee_id: null,
department: '',
location: '',
notes: ''
},
employeeDialog: false,
employeeForm: {
name: '',
email: '',
employee_number: '',
department: '',
location: ''
}
};
},
computed: {
assetOptions() {
return this.assets.map((asset) => ({
title: `${asset.asset_id} · ${asset.description}`,
value: asset.id
}));
},
employeeOptions() {
return this.employees.map((employee) => ({
title: `${employee.name}${employee.department ? ` · ${employee.department}` : ''}`,
value: employee.id
}));
}
},
methods: {
applyEmployeeDefaults(id) {
const employee = this.employees.find((item) => item.id === id);
if (!employee) return;
this.assignmentForm.department = employee.department || '';
this.assignmentForm.location = employee.location || '';
},
saveEmployee() {
this.$emit('add-employee', { ...this.employeeForm });
this.employeeDialog = false;
this.employeeForm = { name: '', email: '', employee_number: '', department: '', location: '' };
}
}
};
</script>