4043-form_data #25
|
@ -0,0 +1,46 @@
|
||||||
|
<script setup>
|
||||||
|
import { h, onMounted } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
autoLoad: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: String,
|
||||||
|
default: '20',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['fetch-data']);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if ($props.autoLoad) {
|
||||||
|
await fetch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetch() {
|
||||||
|
const { data } = await axios.get($props.url, {
|
||||||
|
params: { filter: $props.filter },
|
||||||
|
});
|
||||||
|
|
||||||
|
return emit('fetch-data', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
return h('div', []);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<render />
|
||||||
|
</template>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, onUnmounted, computed, ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import SkeletonForm from 'src/components/SkeletonForm.vue';
|
||||||
|
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const state = useState();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['fetch-data']);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => await fetch());
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
state.unset($props.model);
|
||||||
|
});
|
||||||
|
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const hasChanges = ref(false);
|
||||||
|
const formData = computed(() => state.get($props.model));
|
||||||
|
const originalData = ref();
|
||||||
|
|
||||||
|
async function fetch() {
|
||||||
|
const { data } = await axios.get($props.url, {
|
||||||
|
params: { filter: $props.filter },
|
||||||
|
});
|
||||||
|
|
||||||
|
state.set($props.model, data);
|
||||||
|
originalData.value = Object.assign({}, data);
|
||||||
|
|
||||||
|
watch(formData.value, () => (hasChanges.value = true));
|
||||||
|
|
||||||
|
return emit('fetch-data', state.get($props.model));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
if (!hasChanges.value) {
|
||||||
|
return quasar.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: t('globals.noChanges'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
isLoading.value = true;
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, 5000);
|
||||||
|
});
|
||||||
|
await axios.patch($props.url, formData.value);
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
state.set($props.model, originalData.value);
|
||||||
|
hasChanges.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<q-banner v-if="hasChanges" inline-actions class="text-white bg-red"> You have changes pending to save </q-banner>
|
||||||
|
<q-form v-if="formData" @submit="save" @reset="reset" class="q-pa-md">
|
||||||
|
<slot name="form" :data="formData"></slot>
|
||||||
|
<slot name="actions">
|
||||||
|
<q-btn :label="t('globals.save')" type="submit" color="primary" />
|
||||||
|
<q-btn
|
||||||
|
:label="t('globals.reset')"
|
||||||
|
type="reset"
|
||||||
|
class="q-ml-sm"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
:disable="!hasChanges"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
</q-form>
|
||||||
|
<skeleton-form v-if="!formData" />
|
||||||
|
<q-inner-loading :showing="isLoading" :label="t('globals.pleaseWait')" color="primary" />
|
||||||
|
</template>
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-skeleton type="QInput" square />
|
<q-skeleton type="QInput" square />
|
||||||
|
@ -27,4 +28,5 @@
|
||||||
<q-skeleton type="QBtn" />
|
<q-skeleton type="QBtn" />
|
||||||
<q-skeleton type="QBtn" />
|
<q-skeleton type="QBtn" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
|
const state = ref({});
|
||||||
|
|
||||||
const user = ref({
|
const user = ref({
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -44,11 +46,27 @@ export function useState() {
|
||||||
roles.value = data;
|
roles.value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set(name, data) {
|
||||||
|
state.value[name] = ref(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(name) {
|
||||||
|
return state.value[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function unset(name) {
|
||||||
|
delete state.value[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getUser,
|
getUser,
|
||||||
setUser,
|
setUser,
|
||||||
getRoles,
|
getRoles,
|
||||||
setRoles,
|
setRoles,
|
||||||
|
set,
|
||||||
|
get,
|
||||||
|
unset,
|
||||||
drawer
|
drawer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,6 @@ export function useValidator() {
|
||||||
return validations(validation)[validation.validation];
|
return validations(validation)[validation.validation];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (property === 'socialName') {
|
|
||||||
console.log(modelValidations[property])
|
|
||||||
}
|
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ export default {
|
||||||
noChanges: 'No changes to save',
|
noChanges: 'No changes to save',
|
||||||
confirmRemove: 'You are about to delete this row. Are you sure?',
|
confirmRemove: 'You are about to delete this row. Are you sure?',
|
||||||
rowAdded: 'Row added',
|
rowAdded: 'Row added',
|
||||||
rowRemoved: 'Row removed'
|
rowRemoved: 'Row removed',
|
||||||
|
pleaseWait: 'Please wait...'
|
||||||
},
|
},
|
||||||
moduleIndex: {
|
moduleIndex: {
|
||||||
allModules: 'All modules'
|
allModules: 'All modules'
|
||||||
|
|
|
@ -23,7 +23,8 @@ export default {
|
||||||
noChanges: 'Sin cambios que guardar',
|
noChanges: 'Sin cambios que guardar',
|
||||||
confirmRemove: 'Vas a eliminar este registro. ¿Continuar?',
|
confirmRemove: 'Vas a eliminar este registro. ¿Continuar?',
|
||||||
rowAdded: 'Fila añadida',
|
rowAdded: 'Fila añadida',
|
||||||
rowRemoved: 'Fila eliminada'
|
rowRemoved: 'Fila eliminada',
|
||||||
|
pleaseWait: 'Por favor, espera...'
|
||||||
},
|
},
|
||||||
moduleIndex: {
|
moduleIndex: {
|
||||||
allModules: 'Todos los módulos'
|
allModules: 'Todos los módulos'
|
||||||
|
|
|
@ -1,135 +1,90 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
// import { useQuasar } from 'quasar';
|
||||||
import axios from 'axios';
|
// import axios from 'axios';
|
||||||
import { useSession } from 'src/composables/useSession';
|
import { useSession } from 'src/composables/useSession';
|
||||||
import { useValidator } from 'src/composables/useValidator';
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
import SkeletonForm from 'src/components/SkeletonForm.vue';
|
import { useState } from 'src/composables/useState';
|
||||||
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
|
import FormModel from 'src/components/FormModel.vue';
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetch();
|
// fetch();
|
||||||
fetchWorkers();
|
// fetchWorkers();
|
||||||
fetchBusinessTypes();
|
// fetchBusinessTypes();
|
||||||
fetchContactChannels();
|
// fetchContactChannels();
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const quasar = useQuasar();
|
// const quasar = useQuasar();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { validate } = useValidator();
|
const { validate } = useValidator();
|
||||||
|
const state = useState();
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const token = session.getToken();
|
const token = session.getToken();
|
||||||
|
const data2 = state.get('customer');
|
||||||
const customer = ref(null);
|
console.log(data2);
|
||||||
const customerCopy = ref(null);
|
|
||||||
const hasChanges = ref(false);
|
|
||||||
|
|
||||||
function fetch() {
|
|
||||||
const id = route.params.id;
|
|
||||||
const filter = {
|
|
||||||
include: [],
|
|
||||||
};
|
|
||||||
const options = { params: { filter } };
|
|
||||||
axios.get(`Clients/${id}`, options).then(({ data }) => {
|
|
||||||
customer.value = data;
|
|
||||||
customerCopy.value = Object.assign({}, data);
|
|
||||||
|
|
||||||
watch(customer.value, () => (hasChanges.value = true));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const businessTypes = ref([]);
|
|
||||||
function fetchBusinessTypes() {
|
|
||||||
axios.get(`BusinessTypes`).then(({ data }) => {
|
|
||||||
businessTypes.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const contactChannels = ref([]);
|
|
||||||
function fetchContactChannels() {
|
|
||||||
axios.get(`ContactChannels`).then(({ data }) => {
|
|
||||||
contactChannels.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const workers = ref([]);
|
const workers = ref([]);
|
||||||
const workersCopy = ref([]);
|
const contactChannels = ref([]);
|
||||||
function fetchWorkers() {
|
const businessTypes = ref([]);
|
||||||
const filter = {
|
|
||||||
where: {
|
|
||||||
role: 'salesPerson',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const options = { params: { filter } };
|
|
||||||
axios.get(`Workers/activeWithRole`, options).then(({ data }) => {
|
|
||||||
workers.value = data;
|
|
||||||
workersCopy.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function filter(value, update, options, originalOptions, filter) {
|
// const customer = ref(null);
|
||||||
update(
|
// const customerCopy = ref(null);
|
||||||
() => {
|
// const hasChanges = ref(false);
|
||||||
if (value === '') {
|
|
||||||
options.value = originalOptions.value;
|
|
||||||
|
|
||||||
return;
|
// function filter(value, update, options, originalOptions, filter) {
|
||||||
}
|
// update(
|
||||||
|
// () => {
|
||||||
|
// if (value === '') {
|
||||||
|
// options.value = originalOptions.value;
|
||||||
|
|
||||||
options.value = options.value.filter(filter);
|
// return;
|
||||||
},
|
// }
|
||||||
(ref) => {
|
|
||||||
ref.setOptionIndex(-1);
|
|
||||||
ref.moveOptionSelection(1, true);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterWorkers(value, update) {
|
// options.value = options.value.filter(filter);
|
||||||
const search = value.toLowerCase();
|
// },
|
||||||
|
// (ref) => {
|
||||||
|
// ref.setOptionIndex(-1);
|
||||||
|
// ref.moveOptionSelection(1, true);
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
filter(value, update, workers, workersCopy, (row) => {
|
// function filterWorkers(value, update) {
|
||||||
const id = row.id;
|
// const search = value.toLowerCase();
|
||||||
const name = row.name.toLowerCase();
|
|
||||||
|
|
||||||
const idMatch = id == search;
|
// filter(value, update, workers, workersCopy, (row) => {
|
||||||
const nameMatch = name.indexOf(search) > -1;
|
// const id = row.id;
|
||||||
|
// const name = row.name.toLowerCase();
|
||||||
|
|
||||||
return idMatch || nameMatch;
|
// const idMatch = id == search;
|
||||||
});
|
// const nameMatch = name.indexOf(search) > -1;
|
||||||
}
|
|
||||||
|
|
||||||
function save() {
|
// return idMatch || nameMatch;
|
||||||
const id = route.params.id;
|
// });
|
||||||
const formData = customer.value;
|
// }
|
||||||
|
|
||||||
if (!hasChanges.value) {
|
|
||||||
return quasar.notify({
|
|
||||||
type: 'negative',
|
|
||||||
message: t('globals.noChanges'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.patch(`Clients/${id}`, formData).then((hasChanges.value = false));
|
|
||||||
}
|
|
||||||
|
|
||||||
function onReset() {
|
|
||||||
customer.value = customerCopy.value;
|
|
||||||
hasChanges.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
<fetch-data
|
||||||
|
url="Workers/activeWithRole"
|
||||||
|
:filter="{ where: { role: 'salesPerson' } }"
|
||||||
|
@fetch-data="($data) => (workers = $data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<fetch-data url="ContactChannels" @fetch-data="($data) => (contactChannels = $data)" auto-load />
|
||||||
|
<fetch-data url="BusinessTypes" @fetch-data="($data) => (businessTypes = $data)" auto-load />
|
||||||
<q-page class="q-pa-md">
|
<q-page class="q-pa-md">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<q-card class="q-pa-md">
|
<q-card>
|
||||||
<skeleton-form v-if="!customer" />
|
<form-model :url="`Clients/${route.params.id}`" model="customer">
|
||||||
<q-form v-if="customer" @submit="save" @reset="onReset" greedy>
|
<template #form="{ data }">
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.socialName"
|
v-model="data.socialName"
|
||||||
:label="t('customer.basicData.socialName')"
|
:label="t('customer.basicData.socialName')"
|
||||||
:rules="validate('client.socialName')"
|
:rules="validate('client.socialName')"
|
||||||
autofocus
|
autofocus
|
||||||
|
@ -137,7 +92,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="customer.businessTypeFk"
|
v-model="data.businessTypeFk"
|
||||||
:options="businessTypes"
|
:options="businessTypes"
|
||||||
option-value="code"
|
option-value="code"
|
||||||
option-label="description"
|
option-label="description"
|
||||||
|
@ -152,7 +107,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.contact"
|
v-model="data.contact"
|
||||||
:label="t('customer.basicData.contact')"
|
:label="t('customer.basicData.contact')"
|
||||||
:rules="validate('client.contact')"
|
:rules="validate('client.contact')"
|
||||||
clearable
|
clearable
|
||||||
|
@ -160,7 +115,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.email"
|
v-model="data.email"
|
||||||
type="email"
|
type="email"
|
||||||
:label="t('customer.basicData.email')"
|
:label="t('customer.basicData.email')"
|
||||||
:rules="validate('client.email')"
|
:rules="validate('client.email')"
|
||||||
|
@ -171,7 +126,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.phone"
|
v-model="data.phone"
|
||||||
:label="t('customer.basicData.phone')"
|
:label="t('customer.basicData.phone')"
|
||||||
:rules="validate('client.phone')"
|
:rules="validate('client.phone')"
|
||||||
clearable
|
clearable
|
||||||
|
@ -179,7 +134,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.mobile"
|
v-model="data.mobile"
|
||||||
:label="t('customer.basicData.mobile')"
|
:label="t('customer.basicData.mobile')"
|
||||||
:rules="validate('client.mobile')"
|
:rules="validate('client.mobile')"
|
||||||
clearable
|
clearable
|
||||||
|
@ -189,7 +144,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="customer.salesPersonFk"
|
v-model="data.salesPersonFk"
|
||||||
:options="workers"
|
:options="workers"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
|
@ -204,8 +159,8 @@ function onReset() {
|
||||||
<template #before>
|
<template #before>
|
||||||
<q-avatar color="orange">
|
<q-avatar color="orange">
|
||||||
<q-img
|
<q-img
|
||||||
v-if="customer.salesPersonFk"
|
v-if="data.salesPersonFk"
|
||||||
:src="`/api/Images/user/160x160/${customer.salesPersonFk}/download?access_token=${token}`"
|
:src="`/api/Images/user/160x160/${data.salesPersonFk}/download?access_token=${token}`"
|
||||||
spinner-color="white"
|
spinner-color="white"
|
||||||
/>
|
/>
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
|
@ -214,7 +169,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="customer.contactChannelFk"
|
v-model="data.contactChannelFk"
|
||||||
:options="contactChannels"
|
:options="contactChannels"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
|
@ -226,11 +181,8 @@ function onReset() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</template>
|
||||||
<q-btn :label="t('globals.save')" type="submit" color="primary" />
|
</form-model>
|
||||||
<q-btn :label="t('globals.reset')" type="reset" class="q-ml-sm" color="primary" flat />
|
|
||||||
</div>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
Loading…
Reference in New Issue