feat: refs #8304 added remove option to operator #1195

Merged
jtubau merged 27 commits from 8304-workerChangesAndFixes into dev 2025-02-05 12:25:27 +00:00
8 changed files with 244 additions and 71 deletions

View File

@ -17,7 +17,7 @@ import { useSession } from 'src/composables/useSession';
const route = useRoute(); const route = useRoute();
const quasar = useQuasar(); const quasar = useQuasar();
const { t } = useI18n(); const { t } = useI18n();
const rows = ref(); const rows = ref([]);
const dmsRef = ref(); const dmsRef = ref();
const formDialog = ref({}); const formDialog = ref({});
const token = useSession().getTokenMultimedia(); const token = useSession().getTokenMultimedia();
@ -389,6 +389,14 @@ defineExpose({
</div> </div>
</template> </template>
</QTable> </QTable>
<div
v-else
class="info-row q-pa-md text-center"
>
<h5>
{{ t('No data to display') }}
</h5>
</div>
</template> </template>
</VnPaginate> </VnPaginate>
<QDialog v-model="formDialog.show"> <QDialog v-model="formDialog.show">

View File

@ -1,51 +1,78 @@
import { describe, it, expect, vi, beforeAll, afterEach, beforeEach } from 'vitest'; import {
describe,
it,
expect,
vi,
beforeAll,
afterEach,
beforeEach,
afterAll,
} from 'vitest';
import { createWrapper, axios } from 'app/test/vitest/helper'; import { createWrapper, axios } from 'app/test/vitest/helper';
import VnNotes from 'src/components/ui/VnNotes.vue'; import VnNotes from 'src/components/ui/VnNotes.vue';
import vnDate from 'src/boot/vnDate';
describe('VnNotes', () => { describe('VnNotes', () => {
jtubau marked this conversation as resolved Outdated

Hay que darle una vuelta a este único parámetro de la función, lo veo muy largo para estar ahi

Hay que darle una vuelta a este único parámetro de la función, lo veo muy largo para estar ahi
let vm; let vm;
let wrapper; let wrapper;
let spyFetch; let spyFetch;
let postMock; let postMock;
let expectedBody; let patchMock;
const mockData= {name: 'Tony', lastName: 'Stark', text: 'Test Note', observationTypeFk: 1}; let expectedInsertBody;
let expectedUpdateBody;
function generateExpectedBody() { const defaultOptions = {
expectedBody = {...vm.$props.body, ...{ text: vm.newNote.text, observationTypeFk: vm.newNote.observationTypeFk }}; url: '/test',
} body: { name: 'Tony', lastName: 'Stark' },
selectType: false,
async function setTestParams(text, observationType, type){ saveUrl: null,
vm.newNote.text = text; justInput: false,
vm.newNote.observationTypeFk = observationType; };
wrapper.setProps({ selectType: type }); function generateWrapper(
} options = defaultOptions,
text = null,
beforeAll(async () => { observationType = null,
vi.spyOn(axios, 'get').mockReturnValue({ data: [] }); ) {
vi.spyOn(axios, 'get').mockResolvedValue({ data: [] });
wrapper = createWrapper(VnNotes, { wrapper = createWrapper(VnNotes, {
propsData: { propsData: options,
url: '/test',
body: { name: 'Tony', lastName: 'Stark' },
}
}); });
wrapper = wrapper.wrapper; wrapper = wrapper.wrapper;
vm = wrapper.vm; vm = wrapper.vm;
}); vm.newNote.text = text;
vm.newNote.observationTypeFk = observationType;
}
function createSpyFetch() {
spyFetch = vi.spyOn(vm.$refs.vnPaginateRef, 'fetch');
}
function generateExpectedBody() {
expectedInsertBody = {
...vm.$props.body,
...{ text: vm.newNote.text, observationTypeFk: vm.newNote.observationTypeFk },
};
expectedUpdateBody = { ...vm.$props.body, ...{ notes: vm.newNote.text } };
}
beforeEach(() => { beforeEach(() => {
postMock = vi.spyOn(axios, 'post').mockResolvedValue(mockData); postMock = vi.spyOn(axios, 'post');
spyFetch = vi.spyOn(vm.vnPaginateRef, 'fetch').mockImplementation(() => vi.fn()); patchMock = vi.spyOn(axios, 'patch');
}); });
afterEach(() => { afterEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
expectedBody = {}; expectedInsertBody = {};
expectedUpdateBody = {};
});
afterAll(() => {
vi.restoreAllMocks();
}); });
describe('insert', () => { describe('insert', () => {
it('should not call axios.post and vnPaginateRef.fetch if newNote.text is null', async () => { it('should not call axios.post and vnPaginateRef.fetch when newNote.text is null', async () => {
await setTestParams( null, null, true ); generateWrapper({ selectType: true });
createSpyFetch();
await vm.insert(); await vm.insert();
@ -53,8 +80,9 @@ describe('VnNotes', () => {
expect(spyFetch).not.toHaveBeenCalled(); expect(spyFetch).not.toHaveBeenCalled();
}); });
it('should not call axios.post and vnPaginateRef.fetch if newNote.text is empty', async () => { it('should not call axios.post and vnPaginateRef.fetch when newNote.text is empty', async () => {
await setTestParams( "", null, false ); generateWrapper(null, '');
createSpyFetch();
await vm.insert(); await vm.insert();
@ -62,8 +90,9 @@ describe('VnNotes', () => {
expect(spyFetch).not.toHaveBeenCalled(); expect(spyFetch).not.toHaveBeenCalled();
}); });
it('should not call axios.post and vnPaginateRef.fetch if observationTypeFk is missing and selectType is true', async () => { it('should not call axios.post and vnPaginateRef.fetch when observationTypeFk is null and selectType is true', async () => {
await setTestParams( "Test Note", null, true ); generateWrapper({ selectType: true }, 'Test Note');
createSpyFetch();
await vm.insert(); await vm.insert();
@ -71,37 +100,57 @@ describe('VnNotes', () => {
expect(spyFetch).not.toHaveBeenCalled(); expect(spyFetch).not.toHaveBeenCalled();
}); });
it('should call axios.post and vnPaginateRef.fetch if observationTypeFk is missing and selectType is false', async () => { it('should call axios.post and vnPaginateRef.fetch when observationTypeFk is missing and selectType is false', async () => {
await setTestParams( "Test Note", null, false ); generateWrapper(null, 'Test Note');
createSpyFetch();
generateExpectedBody(); generateExpectedBody();
await vm.insert(); await vm.insert();
expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedBody); expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedInsertBody);
expect(spyFetch).toHaveBeenCalled();
});
it('should call axios.post and vnPaginateRef.fetch if observationTypeFk is setted and selectType is false', async () => {
await setTestParams( "Test Note", 1, false );
generateExpectedBody();
await vm.insert();
expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedBody);
expect(spyFetch).toHaveBeenCalled(); expect(spyFetch).toHaveBeenCalled();
}); });
it('should call axios.post and vnPaginateRef.fetch when newNote is valid', async () => { it('should call axios.post and vnPaginateRef.fetch when newNote is valid', async () => {
await setTestParams( "Test Note", 1, true ); generateWrapper({ selectType: true }, 'Test Note', 1);
createSpyFetch();
generateExpectedBody(); generateExpectedBody();
await vm.insert(); await vm.insert();
expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedBody); expect(postMock).toHaveBeenCalledWith(vm.$props.url, expectedInsertBody);
expect(spyFetch).toHaveBeenCalled(); expect(spyFetch).toHaveBeenCalled();
}); });
}); });
});
describe('update', () => {
it('should call axios.patch with saveUrl when saveUrl is set and justInput is true', async () => {
generateWrapper({
url: '/business',
justInput: true,
saveUrl: '/saveUrlTest',
});
generateExpectedBody();
await vm.update();
expect(patchMock).toHaveBeenCalledWith(vm.$props.saveUrl, expectedUpdateBody);
});
it('should call axios.patch with url when saveUrl is not set and justInput is true', async () => {
generateWrapper({
url: '/business',
body: { workerFk: 1110 },
justInput: true,
});
generateExpectedBody();
await vm.update();
expect(patchMock).toHaveBeenCalledWith(
`${vm.$props.url}/${vm.$props.body.workerFk}`,
expectedUpdateBody,
);
});
});
});

View File

@ -1,6 +1,6 @@
<script setup> <script setup>
import axios from 'axios'; import axios from 'axios';
import { ref, reactive } from 'vue'; import { ref, reactive, useAttrs, computed } from 'vue';
import { onBeforeRouteLeave } from 'vue-router'; import { onBeforeRouteLeave } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
@ -16,12 +16,22 @@ import VnSelect from 'components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
const emit = defineEmits(['onFetch']);
Review

Tengo dudas de este componente porque le hemos metido la lógica de cuando es input, y tenemos que jugar con 2 condiciones
Mi propuesta es definir un componente tipo VnObservation que se comporte como cuando dices que es just-input=true, VnNoteType para el Vnelect y VnNote que tenga solo la lógica del textarea
Pero creo que son demasiados cambios para esta PR

Conclusión: VnNotes depende de 3 condiciones para renderizar que elemento u otro. Desacoplar la lógica

Tengo dudas de este componente porque le hemos metido la lógica de cuando es input, y tenemos que jugar con 2 condiciones Mi propuesta es definir un componente tipo VnObservation que se comporte como cuando dices que es just-input=true, VnNoteType para el Vnelect y VnNote que tenga solo la lógica del textarea Pero creo que son demasiados cambios para esta PR Conclusión: VnNotes depende de 3 condiciones para renderizar que elemento u otro. Desacoplar la lógica
Review

Yo lo dejaria en 2. Un VnNoteInput y un VnNote.
Donde el VnNoteInput seria el textArea.
Y el VnNote tener la logica, y este dividido en 2 partes.
Arriba un slot que por defecto contenga el VnNoteInput
Y abajo el VnPaginate

Yo lo dejaria en 2. Un VnNoteInput y un VnNote. Donde el VnNoteInput seria el textArea. Y el VnNote tener la logica, y este dividido en 2 partes. Arriba un slot que por defecto contenga el VnNoteInput Y abajo el VnPaginate
Review

Por tanto, lo dejamos así y creamos tarea con los comentarios que hemos puesto
Importante: referenciar la PR y ambos comentarios en la descripción de la tarea. Indicando: que la funcionalidad que fusionemos en esta PR debe quedar en el mismo estado. Añadir estos como checklist

Por tanto, lo dejamos así y creamos tarea con los comentarios que hemos puesto *Importante*: referenciar la PR y ambos comentarios en la descripción de la tarea. *Indicando*: que la funcionalidad que fusionemos en esta PR debe quedar en el mismo estado. Añadir estos como checklist
const $attrs = useAttrs();
const isRequired = computed(() => {
return Object.keys($attrs).includes('required')
});
const $props = defineProps({ const $props = defineProps({
url: { type: String, default: null }, url: { type: String, default: null },
saveUrl: {type: String, default: null},
jtubau marked this conversation as resolved Outdated

Porque prop y no un attr?

Porque prop y no un attr?
filter: { type: Object, default: () => {} }, filter: { type: Object, default: () => {} },
body: { type: Object, default: () => {} }, body: { type: Object, default: () => {} },
addNote: { type: Boolean, default: false }, addNote: { type: Boolean, default: false },
selectType: { type: Boolean, default: false }, selectType: { type: Boolean, default: false },
justInput: { type: Boolean, default: false },
}); });
const { t } = useI18n(); const { t } = useI18n();
@ -29,6 +39,13 @@ const quasar = useQuasar();
const newNote = reactive({ text: null, observationTypeFk: null }); const newNote = reactive({ text: null, observationTypeFk: null });
jtubau marked this conversation as resolved Outdated

Diría que esta lógica ya existe o está implementada en qFormMixin

Diría que esta lógica ya existe o está implementada en qFormMixin
const observationTypes = ref([]); const observationTypes = ref([]);
const vnPaginateRef = ref(); const vnPaginateRef = ref();
let originalText;
function handleClick(e) {
if (e.shiftKey && e.key === 'Enter') return;
if ($props.justInput) confirmAndUpdate();
else insert();
}
async function insert() { async function insert() {
if (!newNote.text || ($props.selectType && !newNote.observationTypeFk)) return; if (!newNote.text || ($props.selectType && !newNote.observationTypeFk)) return;
@ -41,8 +58,36 @@ async function insert() {
await axios.post($props.url, newBody); await axios.post($props.url, newBody);
await vnPaginateRef.value.fetch(); await vnPaginateRef.value.fetch();
} }
function confirmAndUpdate() {
if(!newNote.text && originalText)
quasar
.dialog({
component: VnConfirm,
componentProps: {
jtubau marked this conversation as resolved Outdated

.onOk(update)

.onOk(update)
title: t('New note is empty'),
message: t('Are you sure remove this note?'),
},
})
.onOk(update)
.onCancel(() => {
newNote.text = originalText;
});
else update();
}
async function update() {
originalText = newNote.text;
const body = $props.body;
const newBody = {
...body,
...{ notes: newNote.text },
};
jtubau marked this conversation as resolved Outdated

ufff...en el limite

ufff...en el limite

que seria sacar la evaluación a una const y pasar la const como condición?
const changesOnNote = (newNote.text && !$props.justInput) || (newNote.text !== originalText) && $props.justInput;
if (changesOnNote)

algo asi?

que seria sacar la evaluación a una const y pasar la const como condición? const changesOnNote = (newNote.text && !$props.justInput) || (newNote.text !== originalText) && $props.justInput; if (changesOnNote) algo asi?
await axios.patch(`${$props.saveUrl ?? `${$props.url}/${$props.body.workerFk}`}`, newBody);
}
onBeforeRouteLeave((to, from, next) => { onBeforeRouteLeave((to, from, next) => {
if (newNote.text) if ((newNote.text && !$props.justInput) || (newNote.text !== originalText) && $props.justInput)
quasar.dialog({ quasar.dialog({
component: VnConfirm, component: VnConfirm,
componentProps: { componentProps: {
@ -53,6 +98,13 @@ onBeforeRouteLeave((to, from, next) => {
}); });
else next(); else next();
}); });
function fetchData([ data ]) {
newNote.text = data?.notes;
originalText = data?.notes;
emit('onFetch', data);
}
jtubau marked this conversation as resolved Outdated

Si usamos selectType para vincularlo con un VnSelect, porque si lo relacionamos con VnInput no hacemos inputType?

Si usamos selectType para vincularlo con un VnSelect, porque si lo relacionamos con VnInput no hacemos inputType?
</script> </script>
<template> <template>
jtubau marked this conversation as resolved Outdated

Demasiadas operaciones para mantener en el apartado template
Como max. 2

Demasiadas operaciones para mantener en el apartado template Como max. 2

function fetchData(data) {
newNote.text = data[0]?.notes;
originalText = data[0]?.notes;
emit('onFetch', data);
}

<FetchData
v-if="justInput"
:url="url"
:filter="filter"
@on-fetch="(data) => (fetchData(data))"
auto-load
/>

así mejor no? le pondrías otro nombre?

function fetchData(data) { newNote.text = data[0]?.notes; originalText = data[0]?.notes; emit('onFetch', data); } <FetchData v-if="justInput" :url="url" :filter="filter" @on-fetch="(data) => (fetchData(data))" auto-load /> así mejor no? le pondrías otro nombre?
<FetchData <FetchData
@ -62,8 +114,19 @@ onBeforeRouteLeave((to, from, next) => {
auto-load auto-load
@on-fetch="(data) => (observationTypes = data)" @on-fetch="(data) => (observationTypes = data)"
jtubau marked this conversation as resolved Outdated

podemos simplificar con :class="{condicion: "clase CSS"}

podemos simplificar con :class="{condicion: "clase CSS"}
/> />
<QCard class="q-pa-xs q-mb-lg full-width" v-if="$props.addNote"> <FetchData
<QCardSection horizontal> v-if="justInput"
:url="url"
:filter="filter"
@on-fetch="fetchData"
auto-load
/>
<QCard
class="q-pa-xs q-mb-lg full-width"
:class="{ 'just-input': $props.justInput }"
v-if="$props.addNote || $props.justInput"
>
<QCardSection horizontal v-if="!$props.justInput">
{{ t('New note') }} {{ t('New note') }}
</QCardSection> </QCardSection>
<QCardSection class="q-px-xs q-my-none q-py-none"> <QCardSection class="q-px-xs q-my-none q-py-none">
@ -75,19 +138,19 @@ onBeforeRouteLeave((to, from, next) => {
v-model="newNote.observationTypeFk" v-model="newNote.observationTypeFk"
option-label="description" option-label="description"
style="flex: 0.15" style="flex: 0.15"
:required="true" :required="isRequired"
@keyup.enter.stop="insert" @keyup.enter.stop="insert"
/> />
<VnInput <VnInput
v-model.trim="newNote.text" v-model.trim="newNote.text"
type="textarea" type="textarea"
:label="t('Add note here...')" :label="$props.justInput && newNote.text ? '' : t('Add note here...')"
filled filled
size="lg" size="lg"
autogrow autogrow
@keyup.enter.stop="insert" @keyup.enter.stop="handleClick"
:required="isRequired"
clearable clearable
:required="true"
> >
<template #append> <template #append>
<QBtn <QBtn
@ -95,7 +158,7 @@ onBeforeRouteLeave((to, from, next) => {
icon="save" icon="save"
color="primary" color="primary"
flat flat
@click="insert" @click="handleClick"
class="q-mb-xs" class="q-mb-xs"
dense dense
data-cy="saveNote" data-cy="saveNote"
@ -106,6 +169,7 @@ onBeforeRouteLeave((to, from, next) => {
</QCardSection> </QCardSection>
</QCard> </QCard>
<VnPaginate <VnPaginate
v-if="!$props.justInput"
:data-key="$props.url" :data-key="$props.url"
:url="$props.url" :url="$props.url"
order="created DESC" order="created DESC"
@ -198,6 +262,11 @@ onBeforeRouteLeave((to, from, next) => {
} }
} }
} }
.just-input {
padding-right: 18px;
margin-bottom: 2px;
box-shadow: none;
}
</style> </style>
<i18n> <i18n>
es: es:
@ -205,4 +274,6 @@ onBeforeRouteLeave((to, from, next) => {
New note: Nueva nota New note: Nueva nota
Save (Enter): Guardar (Intro) Save (Enter): Guardar (Intro)
Observation type: Tipo de observación Observation type: Tipo de observación
New note is empty: La nueva nota esta vacia
Are you sure remove this note?: Estas seguro de quitar esta nota?
</i18n> </i18n>

View File

@ -19,23 +19,26 @@ onMounted(() => {
const observer = new MutationObserver( const observer = new MutationObserver(
() => () =>
(hasContent.value = (hasContent.value =
actions.value?.childNodes?.length + data.value?.childNodes?.length) actions.value?.childNodes?.length + data.value?.childNodes?.length),
); );
if (actions.value) observer.observe(actions.value, opts); if (actions.value) observer.observe(actions.value, opts);
if (data.value) observer.observe(data.value, opts); if (data.value) observer.observe(data.value, opts);
}); });
onBeforeUnmount(() => stateStore.toggleSubToolbar()); const actionsChildCount = () => !!actions.value?.childNodes?.length;
onBeforeUnmount(() => stateStore.toggleSubToolbar() && hasSubToolbar);
</script> </script>
jtubau marked this conversation as resolved Outdated

no hace falta definir llaves y return

no hace falta definir llaves y return
<template> <template>
<QToolbar <QToolbar
id="subToolbar" id="subToolbar"
class="justify-end sticky"
v-show="hasContent || $slots['st-actions'] || $slots['st-data']" v-show="hasContent || $slots['st-actions'] || $slots['st-data']"
class="justify-end sticky"
> >
<slot name="st-data"> <slot name="st-data">
<div id="st-data"></div> <div id="st-data" :class="{ 'full-width': !actionsChildCount() }">
</div>
</slot> </slot>
<QSpace /> <QSpace />
<slot name="st-actions"> <slot name="st-actions">

View File

@ -23,5 +23,6 @@ const noteFilter = computed(() => {
:body="{ clientFk: route.params.id }" :body="{ clientFk: route.params.id }"
style="overflow-y: auto" style="overflow-y: auto"
:select-type="true" :select-type="true"
required
/> />
</template> </template>

View File

@ -1,7 +1,8 @@
<script setup> <script setup>
import { nextTick, ref, watch } from 'vue'; import { nextTick, ref, watch, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useAcl } from 'src/composables/useAcl';
import WorkerCalendarFilter from 'pages/Worker/Card/WorkerCalendarFilter.vue'; import WorkerCalendarFilter from 'pages/Worker/Card/WorkerCalendarFilter.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
@ -9,10 +10,17 @@ import WorkerCalendarItem from 'pages/Worker/Card/WorkerCalendarItem.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
import axios from 'axios'; import axios from 'axios';
import VnNotes from 'src/components/ui/VnNotes.vue';
import { useStateStore } from 'src/stores/useStateStore';
const stateStore = useStateStore();
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const acl = useAcl();
const canSeeNotes = computed(() =>
acl.hasAny([{ model: 'Worker', props: '__get__business', accessType: 'READ' }]),
);
const workerIsFreelance = ref(); const workerIsFreelance = ref();
const WorkerFreelanceRef = ref(); const WorkerFreelanceRef = ref();
const workerCalendarFilterRef = ref(null); const workerCalendarFilterRef = ref(null);
@ -26,6 +34,10 @@ const contractHolidays = ref(null);
const yearHolidays = ref(null); const yearHolidays = ref(null);
const eventsMap = ref({}); const eventsMap = ref({});
const festiveEventsMap = ref({}); const festiveEventsMap = ref({});
const saveUrl = ref();
const body = {
workerFk: route.params.id,
jsegarra marked this conversation as resolved
Review

entiendo la buena practica pero al ser 1 sola linea, menor abajo
2 bien, pero 3 ya no

entiendo la buena practica pero al ser 1 sola linea, menor abajo 2 bien, pero 3 ya no
};
const onFetchActiveContract = (data) => { const onFetchActiveContract = (data) => {
if (!data) return; if (!data) return;
@ -67,7 +79,7 @@ const onFetchAbsences = (data) => {
name: holidayName, name: holidayName,
isFestive: true, isFestive: true,
}, },
true true,
); );
}); });
} }
@ -146,7 +158,7 @@ watch(
async () => { async () => {
await nextTick(); await nextTick();
await activeContractRef.value.fetch(); await activeContractRef.value.fetch();
} },
); );
watch([year, businessFk], () => refreshData()); watch([year, businessFk], () => refreshData());
</script> </script>
@ -181,6 +193,20 @@ watch([year, businessFk], () => refreshData());
/> />
</template> </template>
</RightMenu> </RightMenu>
<Teleport to="#st-data" v-if="stateStore.isSubToolbarShown() && canSeeNotes">
<VnNotes
:just-input="true"
:url="`Workers/${route.params.id}/business`"
:filter="{ fields: ['id', 'notes', 'workerFk'] }"
:save-url="saveUrl"
@on-fetch="
(data) => {
saveUrl = `Businesses/${data.id}`;
}
"
:body="body"
/>
</Teleport>
<QPage class="column items-center"> <QPage class="column items-center">
<QCard v-if="workerIsFreelance"> <QCard v-if="workerIsFreelance">
<QCardSection class="text-center"> <QCardSection class="text-center">

View File

@ -180,8 +180,6 @@ const yearList = ref(generateYears());
:is-clearable="false" :is-clearable="false"
/> />
</QItemSection> </QItemSection>
</QItem>
<QItem>
<QItemSection> <QItemSection>
<VnSelect <VnSelect
:label="t('Contract')" :label="t('Contract')"

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { ref, computed } from 'vue'; import { ref, computed, watch } from 'vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
@ -19,6 +19,7 @@ const trainsData = ref([]);
const machinesData = ref([]); const machinesData = ref([]);
const route = useRoute(); const route = useRoute();
const routeId = computed(() => route.params.id); const routeId = computed(() => route.params.id);
const selected = ref([]);
jtubau marked this conversation as resolved
Review

No entiendo la propiedad selected que papel hace

No entiendo la propiedad selected que papel hace
Review

para pasarle a crudModel que operario es y que pueda eliminarlo con el botón del subtoolbar

para pasarle a crudModel que operario es y que pueda eliminarlo con el botón del subtoolbar
Review

Okey, veo la necesidad, pero la ejecución es compleja.
Se puede hacer con menos lineas

Okey, veo la necesidad, pero la ejecución es compleja. Se puede hacer con menos lineas
const initialData = computed(() => { const initialData = computed(() => {
return { return {
@ -41,6 +42,21 @@ async function insert() {
await axios.post('Operators', initialData.value); await axios.post('Operators', initialData.value);
crudModelRef.value.reload(); crudModelRef.value.reload();
} }
watch(
Review

No veo la utilidad de este watch

No veo la utilidad de este watch
() => crudModelRef.value?.formData,
(formData) => {
if (formData && formData.length) {
if (JSON.stringify(selected.value) !== JSON.stringify(formData)) {
selected.value = formData;
}
} else if (selected.value.length > 0) {
selected.value = [];
}
},
{ immediate: true, deep: true }
);
</script> </script>
<template> <template>
jtubau marked this conversation as resolved
Review

Revisar esta sección porque los botones de la subtoolbar se ven raros, mas altos o comprimidos

Revisar esta sección porque los botones de la subtoolbar se ven raros, mas altos o comprimidos
@ -67,6 +83,7 @@ async function insert() {
:data-required="{ workerFk: route.params.id }" :data-required="{ workerFk: route.params.id }"
ref="crudModelRef" ref="crudModelRef"
search-url="operator" search-url="operator"
:selected="selected"
auto-load auto-load
> >
<template #body="{ rows }"> <template #body="{ rows }">