From e2e34089e254ce47928ce30fb252f730a708b998 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 31 Jul 2023 15:24:34 +0200 Subject: [PATCH] refs #5673 feat(FormModel): support crud --- src/components/FormModel.vue | 157 ++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 4 deletions(-) diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 9d0916a8e..0d5f75ec1 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -29,12 +29,26 @@ const $props = defineProps({ type: String, default: null, }, + crud: { + type: Boolean, + default: null, + }, + primaryKey: { + type: String, + default: 'id', + }, + dataRequired: { + type: Object, + default: null, + }, }); const emit = defineEmits(['onFetch']); defineExpose({ save, + insert, + remove, }); onMounted(async () => await fetch()); @@ -55,7 +69,7 @@ async function fetch() { }); state.set($props.model, data); - originalData.value = Object.assign({}, data); + originalData.value = JSON.parse(JSON.stringify(data)); watch(formData.value, () => (hasChanges.value = true)); @@ -72,7 +86,7 @@ async function save() { isLoading.value = true; await axios.patch($props.urlUpdate || $props.url, formData.value); - originalData.value = formData.value; + originalData.value = JSON.parse(JSON.stringify(formData.value)); hasChanges.value = false; isLoading.value = false; } @@ -96,22 +110,157 @@ function filter(value, update, filterOptions) { ); } +async function crudSave() { + if (!hasChanges.value) { + return quasar.notify({ + type: 'negative', + message: t('globals.noChanges'), + }); + } + isLoading.value = true; + const changes = getChanges(); + await saveChanges(changes); + if (changes.creates?.length) await fetch(); +} + +async function saveChanges(changes) { + try { + await axios.post($props.urlUpdate || $props.url + '/crud', changes); + } catch (e) { + quasar.notify({ + type: 'negative', + message: 'Some fields are invalid', + }); + } + + originalData.value = JSON.parse(JSON.stringify(formData.value)); + hasChanges.value = false; + isLoading.value = false; +} + +async function insert() { + const $index = formData.value.length + 1; + formData.value.push(Object.assign({ $index }, $props.dataRequired)); + hasChanges.value = true; +} + +// function addRemove(ids) { +// for (let id of ids) { +// const index = removed.value.indexOf(id); +// if (index > -1) { +// removed.value = removed.value.slice(index, 1); +// continue; +// } +// removed.value.push(id); +// } +// } + +async function remove(data) { + if (!data.length) + return quasar.notify({ + type: 'warning', + message: t('globals.noChanges'), + }); + + const pk = $props.primaryKey; + let ids = data.map((d) => d[pk]).filter(Boolean); + let preRemove = data.map((d) => d.$index).filter(Boolean); + let newData = formData.value; + + // addRemove(ids); + if (preRemove.length) { + newData = newData.filter( + (form) => !preRemove.some((index) => index == form.$index) + ); + state.set($props.model, newData); + const changes = getChanges(); + if (!changes.creates?.length && !changes.updates?.length) + hasChanges.value = false; + } + if (ids.length) { + await saveChanges({ deletes: ids }); + newData = newData.filter((form) => !ids.some((id) => id == form[pk])); + state.set($props.model, newData); + } +} + +async function onSubmit() { + if ($props.crud) return crudSave(); + return save(); +} + watch(formUrl, async () => { originalData.value = null; reset(); fetch(); }); + +function getChanges() { + const updates = []; + const creates = []; + + const pk = $props.primaryKey; + + for (const [i, row] of formData.value.entries()) { + if (!row[pk]) { + creates.push(row); + } else if (originalData.value) { + const data = getDifferences(originalData.value[i], row); + if (!isEmpty(data)) { + updates.push({ + data, + where: { [pk]: row[pk] }, + }); + } + } + } + const changes = { updates, creates }; + + for (let prop in changes) { + if (changes[prop].length === 0) changes[prop] = undefined; + } + + return changes; +} + +function getDifferences(obj1, obj2) { + let diff = {}; + for (let key in obj1) { + if (obj2[key] && obj1[key] !== obj2[key]) { + diff[key] = obj2[key]; + } + } + for (let key in obj2) { + if (obj1[key] === undefined && obj2[key]) { + diff[key] = obj2[key]; + } + } + return diff; +} + +function isEmpty(obj) { + if (obj == null) return true; + if (obj === undefined) return true; + if (Object.keys(obj).length === 0) return true; + + if (obj.length > 0) return false; +}