Updated Asset Entry and Views
This commit is contained in:
132
src/App.vue
132
src/App.vue
@@ -130,6 +130,10 @@
|
||||
<AssetDrawer
|
||||
v-model="assetDrawer"
|
||||
:asset-form="assetForm"
|
||||
:asset-files="activeFiles"
|
||||
:asset-notes="activeNotes"
|
||||
:asset-tasks="activeTasks"
|
||||
:asset-warranties="activeWarranties"
|
||||
:category-items="categoryItems"
|
||||
:drawer-error="drawerError"
|
||||
:entity-options="entityOptions"
|
||||
@@ -139,8 +143,18 @@
|
||||
:selected-template-id="selectedTemplateId"
|
||||
:status-items="statusItems"
|
||||
:template-options="templateOptions"
|
||||
@add-note="addNote"
|
||||
@add-task="addTask"
|
||||
@add-warranty="addWarranty"
|
||||
@delete-file="deleteAssetFile"
|
||||
@delete-note="deleteNote"
|
||||
@delete-task="deleteTask"
|
||||
@delete-warranty="deleteWarranty"
|
||||
@download-file="downloadAssetFile"
|
||||
@save-asset="saveAsset"
|
||||
@select-template="applyTemplate"
|
||||
@toggle-task="toggleTask"
|
||||
@upload-file="uploadAssetFile"
|
||||
/>
|
||||
|
||||
<MassEditDialog
|
||||
@@ -166,7 +180,7 @@ import AssetDrawer from './components/AssetDrawer.vue';
|
||||
import MassEditDialog from './components/MassEditDialog.vue';
|
||||
import TopNav from './components/TopNav.vue';
|
||||
import { apiRequest, loginRequest, saveBlob } from './services/api';
|
||||
import { blankAsset, defaultValueForField, normalizeCustomFields } from './utils/assets';
|
||||
import { blankAsset, defaultValueForField, makeDefaultBooks, normalizeCustomFields } from './utils/assets';
|
||||
import { currency, shortDate } from './utils/format';
|
||||
import { bookItems, customFieldTypes, navItems, statusItems, themeItems } from './constants';
|
||||
|
||||
@@ -193,6 +207,10 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
activeView: 'dashboard',
|
||||
activeFiles: [],
|
||||
activeNotes: [],
|
||||
activeTasks: [],
|
||||
activeWarranties: [],
|
||||
assets: [],
|
||||
assetDrawer: false,
|
||||
assetFilters: { search: '', status: null },
|
||||
@@ -373,7 +391,10 @@ export default {
|
||||
for (const field of normalizeCustomFields(template.custom_fields)) {
|
||||
if (customFields[field.key] === undefined) customFields[field.key] = defaultValueForField(field);
|
||||
}
|
||||
this.assetForm = { ...this.assetForm, ...template.defaults, custom_fields: customFields, template_id: template.id };
|
||||
const merged = { ...this.assetForm, ...template.defaults, custom_fields: customFields, template_id: template.id };
|
||||
// For a brand-new asset, realign the book defaults to the template's method/life.
|
||||
if (!merged.id) merged.books = makeDefaultBooks(merged);
|
||||
this.assetForm = merged;
|
||||
},
|
||||
async assignAsset(form) {
|
||||
this.assignmentSaving = true;
|
||||
@@ -406,11 +427,79 @@ export default {
|
||||
const blob = await (await this.api(`/api/reports/depreciation.pdf?year=${this.reportFilters.year}&book=${this.reportFilters.book}`)).blob();
|
||||
saveBlob(blob, `mixedassets-${this.reportFilters.book}-${this.reportFilters.year}.pdf`);
|
||||
},
|
||||
editAsset(asset) {
|
||||
this.assetForm = { ...blankAsset(), ...asset, custom_fields: asset.custom_fields || {} };
|
||||
this.selectedTemplateId = asset.template_id || null;
|
||||
async editAsset(asset) {
|
||||
this.drawerError = '';
|
||||
const full = await this.refreshActiveAsset(asset.id);
|
||||
this.assetForm = {
|
||||
...blankAsset(),
|
||||
...full,
|
||||
custom_fields: full.custom_fields || {},
|
||||
books: full.books && full.books.length ? full.books : makeDefaultBooks(full)
|
||||
};
|
||||
this.selectedTemplateId = full.template_id || null;
|
||||
this.assetDrawer = true;
|
||||
},
|
||||
async refreshActiveAsset(id) {
|
||||
const data = await (await this.api(`/api/assets/${id}`)).json();
|
||||
const asset = data.asset;
|
||||
this.activeFiles = asset.files || [];
|
||||
this.activeWarranties = asset.warranties || [];
|
||||
this.activeTasks = asset.tasks || [];
|
||||
this.activeNotes = asset.notes_log || [];
|
||||
return asset;
|
||||
},
|
||||
clearActiveCollections() {
|
||||
this.activeFiles = [];
|
||||
this.activeWarranties = [];
|
||||
this.activeTasks = [];
|
||||
this.activeNotes = [];
|
||||
},
|
||||
async uploadAssetFile(file) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
await this.api(`/api/assets/${this.assetForm.id}/files`, { method: 'POST', body: formData });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
},
|
||||
async downloadAssetFile(file) {
|
||||
const blob = await (await this.api(`/api/assets/${this.assetForm.id}/files/${file.id}`)).blob();
|
||||
saveBlob(blob, file.file_name);
|
||||
},
|
||||
async deleteAssetFile(fileId) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/files/${fileId}`, { method: 'DELETE' });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
},
|
||||
async addWarranty(warranty) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/warranties`, { method: 'POST', body: JSON.stringify(warranty) });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
},
|
||||
async deleteWarranty(id) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/warranties/${id}`, { method: 'DELETE' });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
},
|
||||
async addTask(task) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/tasks`, { method: 'POST', body: JSON.stringify(task) });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
await this.loadDashboard();
|
||||
},
|
||||
async toggleTask(task) {
|
||||
const status = task.status === 'complete' ? 'open' : 'complete';
|
||||
await this.api(`/api/assets/${this.assetForm.id}/tasks/${task.id}`, { method: 'PUT', body: JSON.stringify({ status }) });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
await this.loadDashboard();
|
||||
},
|
||||
async deleteTask(id) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/tasks/${id}`, { method: 'DELETE' });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
await this.loadDashboard();
|
||||
},
|
||||
async addNote(body) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/notes`, { method: 'POST', body: JSON.stringify({ body }) });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
},
|
||||
async deleteNote(id) {
|
||||
await this.api(`/api/assets/${this.assetForm.id}/notes/${id}`, { method: 'DELETE' });
|
||||
await this.refreshActiveAsset(this.assetForm.id);
|
||||
},
|
||||
async exportAssets(format) {
|
||||
const blob = await (await this.api(`/api/export/assets?format=${format}`)).blob();
|
||||
saveBlob(blob, `mixedassets-assets.${format}`);
|
||||
@@ -541,27 +630,38 @@ export default {
|
||||
this.assetForm.entity_id = this.entities[0]?.id || null;
|
||||
this.selectedTemplateId = null;
|
||||
this.drawerError = '';
|
||||
this.clearActiveCollections();
|
||||
this.assetDrawer = true;
|
||||
},
|
||||
async saveAsset(assetInput) {
|
||||
this.saving = true;
|
||||
this.drawerError = '';
|
||||
try {
|
||||
const payload = {
|
||||
...assetInput,
|
||||
books: this.bookItems.map((book) => ({
|
||||
book_type: book,
|
||||
depreciation_method: assetInput.depreciation_method,
|
||||
useful_life_months: assetInput.useful_life_months,
|
||||
cost: assetInput.acquisition_cost
|
||||
}))
|
||||
};
|
||||
const books = (assetInput.books && assetInput.books.length ? assetInput.books : makeDefaultBooks(assetInput))
|
||||
.map((book) => ({
|
||||
...book,
|
||||
cost: book.cost === '' || book.cost === null || book.cost === undefined ? null : Number(book.cost)
|
||||
}));
|
||||
const payload = { ...assetInput, books };
|
||||
const method = assetInput.id ? 'PUT' : 'POST';
|
||||
const url = assetInput.id ? `/api/assets/${assetInput.id}` : '/api/assets';
|
||||
await this.api(url, { method, body: JSON.stringify(payload) });
|
||||
this.assetDrawer = false;
|
||||
const saved = await (await this.api(url, { method, body: JSON.stringify(payload) })).json();
|
||||
await this.loadAssets();
|
||||
await this.loadDashboard();
|
||||
if (!assetInput.id && saved.asset) {
|
||||
// Keep the drawer open on the freshly created asset so files, warranties,
|
||||
// tasks, and notes can be attached without reopening.
|
||||
this.assetForm = {
|
||||
...blankAsset(),
|
||||
...saved.asset,
|
||||
custom_fields: saved.asset.custom_fields || {},
|
||||
books: saved.asset.books && saved.asset.books.length ? saved.asset.books : makeDefaultBooks(saved.asset)
|
||||
};
|
||||
this.selectedTemplateId = saved.asset.template_id || null;
|
||||
await this.refreshActiveAsset(saved.asset.id);
|
||||
} else {
|
||||
this.assetDrawer = false;
|
||||
}
|
||||
} catch (error) {
|
||||
this.drawerError = error.message;
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user