Password Policy/App rename/PM Scheduling Improvements

This commit is contained in:
2026-06-06 02:32:47 -05:00
parent dfd999b6a9
commit f024286b5e
59 changed files with 3814 additions and 299 deletions

View File

@@ -109,6 +109,31 @@
<v-btn icon="mdi-delete-outline" size="x-small" variant="text" color="error" @click="form.components.splice(index, 1)" />
</div>
<div class="toolbar-row mt-4 mb-1">
<h3 class="section-title">Usage meters</h3>
<v-spacer />
<v-btn size="small" variant="tonal" prepend-icon="mdi-plus" @click="addMeter">Add meter</v-btn>
</div>
<p class="quiet text-body-2">
Track usage (operating hours, kWh, gallons, cycles…) so service comes due on accumulated use, not just the calendar.
Requires usage-based scheduling in PM settings.
</p>
<div v-for="(meter, index) in form.meters" :key="`m${index}`" class="pm-component">
<v-text-field v-model="meter.label" density="compact" hide-details placeholder="Meter (e.g. Operating Hours)" style="flex:1 1 auto" />
<v-text-field v-model="meter.unit" density="compact" hide-details placeholder="Unit" style="max-width:100px" />
<v-text-field v-model.number="meter.usage_interval" type="number" density="compact" hide-details placeholder="Due every" style="max-width:130px" />
<v-btn icon="mdi-delete-outline" size="x-small" variant="text" color="error" @click="form.meters.splice(index, 1)" />
</div>
<v-switch
v-model="form.lifespan_adjust"
color="primary"
density="compact"
hide-details
class="mt-3"
label="Tighten the interval as the asset ages (lifespan wear curve)"
/>
<div class="toolbar-row mt-4 mb-1">
<h3 class="section-title">Guidance photos</h3>
<v-spacer />
@@ -145,7 +170,7 @@ import { currency } from '../utils/format';
import { clonePlain } from '../utils/clone';
function blankPlan() {
return { id: null, name: '', description: '', category: '', frequency_value: 3, frequency_unit: 'months', estimated_minutes: null, instructions: '', steps: [], components: [], photos: [] };
return { id: null, name: '', description: '', category: '', frequency_value: 3, frequency_unit: 'months', estimated_minutes: null, instructions: '', steps: [], components: [], meters: [], lifespan_adjust: false, photos: [] };
}
export default {
@@ -248,6 +273,8 @@ export default {
...clonePlain(full),
steps: clonePlain(full.steps || []),
components: clonePlain(full.components || []),
meters: clonePlain(full.meters || []),
lifespan_adjust: Boolean(full.lifespan_adjust),
photos: clonePlain(full.photos || [])
};
this.dialog = true;
@@ -258,6 +285,9 @@ export default {
addComponent() {
this.form.components.push({ part_number: '', description: '', supplier: '', cost: null });
},
addMeter() {
this.form.meters.push({ label: '', unit: '', usage_interval: null });
},
onPhotoPick(event) {
for (const file of Array.from(event.target.files || [])) {
const reader = new FileReader();