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,30 +1,32 @@
|
|||
<template>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
<div class="q-pa-md">
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
<div class="row q-gutter-md">
|
||||
<q-skeleton type="QBtn" />
|
||||
<q-skeleton type="QBtn" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-skeleton type="QInput" square />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md">
|
||||
<q-skeleton type="QBtn" />
|
||||
<q-skeleton type="QBtn" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { ref, computed } from 'vue';
|
||||
|
||||
const state = ref({});
|
||||
|
||||
const user = ref({
|
||||
id: 0,
|
||||
name: '',
|
||||
|
@ -44,11 +46,27 @@ export function useState() {
|
|||
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 {
|
||||
getUser,
|
||||
setUser,
|
||||
getRoles,
|
||||
setRoles,
|
||||
set,
|
||||
get,
|
||||
unset,
|
||||
drawer
|
||||
};
|
||||
}
|
||||
|
|
|
@ -33,10 +33,6 @@ export function useValidator() {
|
|||
return validations(validation)[validation.validation];
|
||||
});
|
||||
|
||||
if (property === 'socialName') {
|
||||
console.log(modelValidations[property])
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ export default {
|
|||
noChanges: 'No changes to save',
|
||||
confirmRemove: 'You are about to delete this row. Are you sure?',
|
||||
rowAdded: 'Row added',
|
||||
rowRemoved: 'Row removed'
|
||||
rowRemoved: 'Row removed',
|
||||
pleaseWait: 'Please wait...'
|
||||
},
|
||||
moduleIndex: {
|
||||
allModules: 'All modules'
|
||||
|
|
|
@ -23,7 +23,8 @@ export default {
|
|||
noChanges: 'Sin cambios que guardar',
|
||||
confirmRemove: 'Vas a eliminar este registro. ¿Continuar?',
|
||||
rowAdded: 'Fila añadida',
|
||||
rowRemoved: 'Fila eliminada'
|
||||
rowRemoved: 'Fila eliminada',
|
||||
pleaseWait: 'Por favor, espera...'
|
||||
},
|
||||
moduleIndex: {
|
||||
allModules: 'Todos los módulos'
|
||||
|
|
|
@ -1,236 +1,188 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
// import { useQuasar } from 'quasar';
|
||||
// import axios from 'axios';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
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(() => {
|
||||
fetch();
|
||||
fetchWorkers();
|
||||
fetchBusinessTypes();
|
||||
fetchContactChannels();
|
||||
// fetch();
|
||||
// fetchWorkers();
|
||||
// fetchBusinessTypes();
|
||||
// fetchContactChannels();
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const quasar = useQuasar();
|
||||
// const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
const { validate } = useValidator();
|
||||
const state = useState();
|
||||
const session = useSession();
|
||||
const token = session.getToken();
|
||||
|
||||
const customer = ref(null);
|
||||
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 data2 = state.get('customer');
|
||||
console.log(data2);
|
||||
|
||||
const workers = ref([]);
|
||||
const workersCopy = ref([]);
|
||||
function fetchWorkers() {
|
||||
const filter = {
|
||||
where: {
|
||||
role: 'salesPerson',
|
||||
},
|
||||
};
|
||||
const options = { params: { filter } };
|
||||
axios.get(`Workers/activeWithRole`, options).then(({ data }) => {
|
||||
workers.value = data;
|
||||
workersCopy.value = data;
|
||||
});
|
||||
}
|
||||
const contactChannels = ref([]);
|
||||
const businessTypes = ref([]);
|
||||
|
||||
function filter(value, update, options, originalOptions, filter) {
|
||||
update(
|
||||
() => {
|
||||
if (value === '') {
|
||||
options.value = originalOptions.value;
|
||||
// const customer = ref(null);
|
||||
// const customerCopy = ref(null);
|
||||
// const hasChanges = ref(false);
|
||||
|
||||
return;
|
||||
}
|
||||
// function filter(value, update, options, originalOptions, filter) {
|
||||
// update(
|
||||
// () => {
|
||||
// if (value === '') {
|
||||
// options.value = originalOptions.value;
|
||||
|
||||
options.value = options.value.filter(filter);
|
||||
},
|
||||
(ref) => {
|
||||
ref.setOptionIndex(-1);
|
||||
ref.moveOptionSelection(1, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
// return;
|
||||
// }
|
||||
|
||||
function filterWorkers(value, update) {
|
||||
const search = value.toLowerCase();
|
||||
// options.value = options.value.filter(filter);
|
||||
// },
|
||||
// (ref) => {
|
||||
// ref.setOptionIndex(-1);
|
||||
// ref.moveOptionSelection(1, true);
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
|
||||
filter(value, update, workers, workersCopy, (row) => {
|
||||
const id = row.id;
|
||||
const name = row.name.toLowerCase();
|
||||
// function filterWorkers(value, update) {
|
||||
// const search = value.toLowerCase();
|
||||
|
||||
const idMatch = id == search;
|
||||
const nameMatch = name.indexOf(search) > -1;
|
||||
// filter(value, update, workers, workersCopy, (row) => {
|
||||
// const id = row.id;
|
||||
// const name = row.name.toLowerCase();
|
||||
|
||||
return idMatch || nameMatch;
|
||||
});
|
||||
}
|
||||
// const idMatch = id == search;
|
||||
// const nameMatch = name.indexOf(search) > -1;
|
||||
|
||||
function save() {
|
||||
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;
|
||||
}
|
||||
// return idMatch || nameMatch;
|
||||
// });
|
||||
// }
|
||||
</script>
|
||||
<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">
|
||||
<div class="container">
|
||||
<q-card class="q-pa-md">
|
||||
<skeleton-form v-if="!customer" />
|
||||
<q-form v-if="customer" @submit="save" @reset="onReset" greedy>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="customer.socialName"
|
||||
:label="t('customer.basicData.socialName')"
|
||||
:rules="validate('client.socialName')"
|
||||
autofocus
|
||||
/>
|
||||
<q-card>
|
||||
<form-model :url="`Clients/${route.params.id}`" model="customer">
|
||||
<template #form="{ data }">
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="data.socialName"
|
||||
:label="t('customer.basicData.socialName')"
|
||||
:rules="validate('client.socialName')"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="data.businessTypeFk"
|
||||
:options="businessTypes"
|
||||
option-value="code"
|
||||
option-label="description"
|
||||
emit-value
|
||||
:label="t('customer.basicData.businessType')"
|
||||
map-options
|
||||
:rules="validate('client.businessTypeFk')"
|
||||
:input-debounce="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="customer.businessTypeFk"
|
||||
:options="businessTypes"
|
||||
option-value="code"
|
||||
option-label="description"
|
||||
emit-value
|
||||
:label="t('customer.basicData.businessType')"
|
||||
map-options
|
||||
:rules="validate('client.businessTypeFk')"
|
||||
:input-debounce="0"
|
||||
/>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="data.contact"
|
||||
:label="t('customer.basicData.contact')"
|
||||
:rules="validate('client.contact')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="data.email"
|
||||
type="email"
|
||||
:label="t('customer.basicData.email')"
|
||||
:rules="validate('client.email')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="customer.contact"
|
||||
:label="t('customer.basicData.contact')"
|
||||
:rules="validate('client.contact')"
|
||||
clearable
|
||||
/>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="data.phone"
|
||||
:label="t('customer.basicData.phone')"
|
||||
:rules="validate('client.phone')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="data.mobile"
|
||||
:label="t('customer.basicData.mobile')"
|
||||
:rules="validate('client.mobile')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="customer.email"
|
||||
type="email"
|
||||
:label="t('customer.basicData.email')"
|
||||
:rules="validate('client.email')"
|
||||
clearable
|
||||
/>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="data.salesPersonFk"
|
||||
:options="workers"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
emit-value
|
||||
:label="t('customer.basicData.salesPerson')"
|
||||
map-options
|
||||
use-input
|
||||
@filter="filterWorkers"
|
||||
:rules="validate('client.salesPersonFk')"
|
||||
:input-debounce="0"
|
||||
>
|
||||
<template #before>
|
||||
<q-avatar color="orange">
|
||||
<q-img
|
||||
v-if="data.salesPersonFk"
|
||||
:src="`/api/Images/user/160x160/${data.salesPersonFk}/download?access_token=${token}`"
|
||||
spinner-color="white"
|
||||
/>
|
||||
</q-avatar>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="data.contactChannelFk"
|
||||
:options="contactChannels"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
emit-value
|
||||
:label="t('customer.basicData.contactChannel')"
|
||||
map-options
|
||||
:rules="validate('client.contactChannelFk')"
|
||||
:input-debounce="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="customer.phone"
|
||||
:label="t('customer.basicData.phone')"
|
||||
:rules="validate('client.phone')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="customer.mobile"
|
||||
:label="t('customer.basicData.mobile')"
|
||||
:rules="validate('client.mobile')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="customer.salesPersonFk"
|
||||
:options="workers"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
emit-value
|
||||
:label="t('customer.basicData.salesPerson')"
|
||||
map-options
|
||||
use-input
|
||||
@filter="filterWorkers"
|
||||
:rules="validate('client.salesPersonFk')"
|
||||
:input-debounce="0"
|
||||
>
|
||||
<template #before>
|
||||
<q-avatar color="orange">
|
||||
<q-img
|
||||
v-if="customer.salesPersonFk"
|
||||
:src="`/api/Images/user/160x160/${customer.salesPersonFk}/download?access_token=${token}`"
|
||||
spinner-color="white"
|
||||
/>
|
||||
</q-avatar>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="customer.contactChannelFk"
|
||||
:options="contactChannels"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
emit-value
|
||||
:label="t('customer.basicData.contactChannel')"
|
||||
map-options
|
||||
:rules="validate('client.contactChannelFk')"
|
||||
:input-debounce="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<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 />
|
||||
</div>
|
||||
</q-form>
|
||||
</template>
|
||||
</form-model>
|
||||
</q-card>
|
||||
</div>
|
||||
</q-page>
|
||||
|
|
Loading…
Reference in New Issue