5673-hotFix_improve_crudModel_vnSelect #100
|
@ -9,7 +9,7 @@
|
|||
"lint": "eslint --ext .js,.vue ./",
|
||||
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||
"test:e2e": "cypress open",
|
||||
"test:e2e:ci": "cypress run --browser chromium",
|
||||
"test:e2e:ci": "cd ../salix && gulp docker && cd ../salix-front && cypress run --browser chromium",
|
||||
|
||||
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
||||
"test:unit": "vitest",
|
||||
"test:unit:ci": "vitest run"
|
||||
|
|
|
@ -46,7 +46,7 @@ const onResponseError = (error) => {
|
|||
message = responseError.message;
|
||||
}
|
||||
|
||||
switch (response.status) {
|
||||
switch (response?.status) {
|
||||
case 500:
|
||||
message = 'errors.statusInternalServerError';
|
||||
break;
|
||||
|
@ -58,7 +58,7 @@ const onResponseError = (error) => {
|
|||
break;
|
||||
}
|
||||
|
||||
if (session.isLoggedIn() && response.status === 401) {
|
||||
if (session.isLoggedIn() && response?.status === 401) {
|
||||
session.destroy();
|
||||
const hash = window.location.hash;
|
||||
const url = hash.slice(1);
|
||||
|
|
|
@ -8,6 +8,7 @@ import { useStateStore } from 'stores/useStateStore';
|
|||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import SkeletonTable from 'components/ui/SkeletonTable.vue';
|
||||
import { tMobile } from 'src/composables/tMobile';
|
||||
|
||||
const quasar = useQuasar();
|
||||
const stateStore = useStateStore();
|
||||
|
@ -62,9 +63,10 @@ const hasChanges = ref(false);
|
|||
const originalData = ref();
|
||||
const vnPaginateRef = ref();
|
||||
const formData = ref();
|
||||
const saveButtonRef = ref(null);
|
||||
const formUrl = computed(() => $props.url);
|
||||
|
||||
const emit = defineEmits(['onFetch', 'update:selected']);
|
||||
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
|
||||
|
||||
defineExpose({
|
||||
reload,
|
||||
|
@ -73,12 +75,9 @@ defineExpose({
|
|||
onSubmit,
|
||||
reset,
|
||||
hasChanges,
|
||||
saveChanges,
|
||||
});
|
||||
|
||||
function tMobile(...args) {
|
||||
if (!quasar.platform.is.mobile) return t(...args);
|
||||
}
|
||||
|
||||
async function fetch(data) {
|
||||
if (data && Array.isArray(data)) {
|
||||
let $index = 0;
|
||||
|
@ -135,6 +134,7 @@ async function saveChanges(data) {
|
|||
|
||||
hasChanges.value = false;
|
||||
isLoading.value = false;
|
||||
emit('saveChanges', data);
|
||||
}
|
||||
|
||||
async function insert() {
|
||||
|
@ -269,7 +269,7 @@ watch(formUrl, async () => {
|
|||
<SkeletonTable v-if="!formData" />
|
||||
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
|
||||
<QBtnGroup push class="q-gutter-x-sm">
|
||||
<slot name="moreActions" />
|
||||
<slot name="moreBeforeActions" />
|
||||
<QBtn
|
||||
:label="tMobile('globals.remove')"
|
||||
color="primary"
|
||||
|
@ -292,6 +292,7 @@ watch(formUrl, async () => {
|
|||
/>
|
||||
<QBtn
|
||||
:label="tMobile('globals.save')"
|
||||
ref="saveButtonRef"
|
||||
color="primary"
|
||||
icon="save"
|
||||
@click="onSubmit"
|
||||
|
@ -299,6 +300,7 @@ watch(formUrl, async () => {
|
|||
:title="t('globals.save')"
|
||||
v-if="$props.defaultSave"
|
||||
/>
|
||||
<slot name="moreAfterActions" />
|
||||
</QBtnGroup>
|
||||
</Teleport>
|
||||
<QInnerLoading
|
||||
|
|
|
@ -19,6 +19,8 @@ const $props = defineProps({
|
|||
const { optionLabel, options } = toRefs($props);
|
||||
const myOptions = ref([]);
|
||||
const myOptionsOriginal = ref([]);
|
||||
const vnSelectRef = ref(null);
|
||||
|
||||
function setOptions(data) {
|
||||
myOptions.value = JSON.parse(JSON.stringify(data));
|
||||
myOptionsOriginal.value = JSON.parse(JSON.stringify(data));
|
||||
|
@ -29,6 +31,7 @@ const filter = (val, options) => {
|
|||
const search = val.toLowerCase();
|
||||
|
||||
if (val === '') return options;
|
||||
|
||||
return options.filter((row) => {
|
||||
const id = row.id;
|
||||
const name = row[$props.optionLabel].toLowerCase();
|
||||
|
@ -41,9 +44,17 @@ const filter = (val, options) => {
|
|||
};
|
||||
|
||||
const filterHandler = (val, update) => {
|
||||
update(() => {
|
||||
myOptions.value = filter(val, myOptionsOriginal.value);
|
||||
});
|
||||
update(
|
||||
() => {
|
||||
myOptions.value = filter(val, myOptionsOriginal.value);
|
||||
},
|
||||
(ref) => {
|
||||
if (val !== '' && ref.options.length > 0) {
|
||||
ref.setOptionIndex(-1);
|
||||
ref.moveOptionSelection(1, true);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
watch(options, (newValue) => {
|
||||
|
@ -70,7 +81,15 @@ const value = computed({
|
|||
map-options
|
||||
use-input
|
||||
@filter="filterHandler"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
hide-selected
|
||||
fill-input
|
||||
ref="vnSelectRef"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="close" @click.stop="value = null" class="cursor-pointer" />
|
||||
</template>
|
||||
<template v-for="(_, slotName) in $slots" #[slotName]="slotData">
|
||||
<slot :name="slotName" v-bind="slotData" />
|
||||
</template>
|
||||
</QSelect>
|
||||
</template>
|
||||
|
|
|
@ -140,14 +140,6 @@ async function onLoad(...params) {
|
|||
{{ t('No data to display') }}
|
||||
</h5>
|
||||
</div>
|
||||
<div
|
||||
v-if="store.data && store.data.length === 0 && !isLoading"
|
||||
class="info-row q-pa-md text-center"
|
||||
>
|
||||
<h5>
|
||||
{{ t('No results found') }}
|
||||
</h5>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.skeleton && props.autoLoad && !store.data"
|
||||
class="card-list q-gutter-y-md"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
export function tMobile(...args) {
|
||||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
if (!quasar.platform.is.mobile) return t(...args);
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import CrudModel from 'components/CrudModel.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
|
||||
import { getUrl } from 'composables/getUrl';
|
||||
import { tMobile } from 'composables/tMobile';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const claimDevelopmentForm = ref();
|
||||
|
@ -16,6 +19,12 @@ const claimResponsibles = ref([]);
|
|||
const claimRedeliveries = ref([]);
|
||||
const workers = ref([]);
|
||||
const selected = ref([]);
|
||||
const insertButtonRef = ref();
|
||||
let salixUrl;
|
||||
|
||||
onMounted(async () => {
|
||||
salixUrl = await getUrl(`claim/${route.params.id}`);
|
||||
});
|
||||
|
||||
const developmentsFilter = {
|
||||
fields: [
|
||||
|
@ -43,6 +52,7 @@ const columns = computed(() => [
|
|||
model: 'claimReasonFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'description',
|
||||
tabIndex: 1,
|
||||
},
|
||||
{
|
||||
name: 'claimResult',
|
||||
|
@ -54,6 +64,7 @@ const columns = computed(() => [
|
|||
model: 'claimResultFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'description',
|
||||
tabIndex: 2,
|
||||
},
|
||||
{
|
||||
name: 'claimResponsible',
|
||||
|
@ -65,6 +76,7 @@ const columns = computed(() => [
|
|||
model: 'claimResponsibleFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'description',
|
||||
tabIndex: 3,
|
||||
},
|
||||
{
|
||||
name: 'worker',
|
||||
|
@ -75,6 +87,7 @@ const columns = computed(() => [
|
|||
model: 'workerFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'nickname',
|
||||
tabIndex: 4,
|
||||
},
|
||||
{
|
||||
name: 'claimRedelivery',
|
||||
|
@ -86,8 +99,13 @@ const columns = computed(() => [
|
|||
model: 'claimRedeliveryFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'description',
|
||||
tabIndex: 5,
|
||||
},
|
||||
]);
|
||||
|
||||
function goToAction() {
|
||||
location.href = `${salixUrl}/action`;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
|
@ -115,8 +133,9 @@ const columns = computed(() => [
|
|||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Workers/activeWithInheritedRole"
|
||||
:where="{ role: 'employee' }"
|
||||
url="Workers/search"
|
||||
:where="{ active: 1 }"
|
||||
order="name ASC"
|
||||
@on-fetch="(data) => (workers = data)"
|
||||
auto-load
|
||||
/>
|
||||
|
@ -129,6 +148,8 @@ const columns = computed(() => [
|
|||
:data-required="{ claimFk: route.params.id }"
|
||||
v-model:selected="selected"
|
||||
auto-load
|
||||
@save-changes="goToAction"
|
||||
:default-save="false"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
|
@ -142,19 +163,40 @@ const columns = computed(() => [
|
|||
:grid="$q.screen.lt.md"
|
||||
>
|
||||
<template #body-cell="{ row, col }">
|
||||
<QTd auto-width>
|
||||
<QTd
|
||||
auto-width
|
||||
@keyup.ctrl.enter.stop="claimDevelopmentForm.saveChanges()"
|
||||
>
|
||||
<VnSelectFilter
|
||||
:label="col.label"
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
/>
|
||||
:autofocus="col.tabIndex == 1"
|
||||
input-debounce="0"
|
||||
>
|
||||
<template #option="scope" v-if="col.name == 'worker'">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ scope.opt?.nickname }}
|
||||
{{ scope.opt?.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard bordered flat>
|
||||
<QCard
|
||||
bordered
|
||||
flat
|
||||
@keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
|
||||
>
|
||||
<QCardSection>
|
||||
<QCheckbox v-model="props.selected" dense />
|
||||
</QCardSection>
|
||||
|
@ -169,6 +211,8 @@ const columns = computed(() => [
|
|||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
dense
|
||||
input-debounce="0"
|
||||
:autofocus="col.tabIndex == 1"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
@ -178,9 +222,28 @@ const columns = computed(() => [
|
|||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
<template #moreAfterActions>
|
||||
<QBtn
|
||||
:label="tMobile('globals.save')"
|
||||
ref="saveButtonRef"
|
||||
color="primary"
|
||||
icon="save"
|
||||
:disable="!claimDevelopmentForm?.hasChanges"
|
||||
@click="claimDevelopmentForm?.onSubmit"
|
||||
:title="t('globals.save')"
|
||||
/>
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn fab color="primary" icon="add" @click="claimDevelopmentForm.insert()" />
|
||||
<QBtn
|
||||
ref="insertButtonRef"
|
||||
fab
|
||||
color="primary"
|
||||
icon="add"
|
||||
@click="claimDevelopmentForm.insert()"
|
||||
@keydown.ctrl.enter.stop="claimDevelopmentForm.saveChanges()"
|
||||
@keydown.enter.stop
|
||||
/>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ const claimLinesForm = ref();
|
|||
const claim = ref(null);
|
||||
async function onFetchClaim(data) {
|
||||
claim.value = data;
|
||||
|
||||
fetchMana();
|
||||
}
|
||||
|
||||
|
@ -147,8 +146,11 @@ function showImportDialog() {
|
|||
quasar
|
||||
.dialog({
|
||||
component: ClaimLinesImport,
|
||||
componentProps: {
|
||||
ticketId: claim.value.ticketFk,
|
||||
},
|
||||
})
|
||||
.onOk(() => arrayData.refresh());
|
||||
.onOk(() => claimLinesForm.value.reload());
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
@ -14,6 +14,13 @@ const route = useRoute();
|
|||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
|
||||
const $props = defineProps({
|
||||
ticketId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'delivered',
|
||||
|
@ -99,7 +106,7 @@ function cancel() {
|
|||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
url="Sales/getClaimableFromTicket?ticketFk=16"
|
||||
alexm
commented
La seccio de linies anava mal pq se havia ficat un 16 ahi pq si... La seccio de linies anava mal pq se havia ficat un 16 ahi pq si...
|
||||
:url="`Sales/getClaimableFromTicket?ticketFk=${$props.ticketId}`"
|
||||
@on-fetch="(data) => (claimableSales = data)"
|
||||
auto-load
|
||||
/>
|
||||
|
|
|
@ -13,15 +13,17 @@ describe('ClaimDevelopment', () => {
|
|||
it('should reset line', () => {
|
||||
cy.selectOption(firstLineReason, 'Novato');
|
||||
cy.resetCard();
|
||||
cy.getValue(firstLineReason).should('have.text', 'Prisas');
|
||||
cy.getValue(firstLineReason).should('have.value', 'Prisas');
|
||||
});
|
||||
|
||||
it('should edit line', () => {
|
||||
cy.selectOption(firstLineReason, 'Novato');
|
||||
cy.saveCard();
|
||||
|
||||
cy.reload();
|
||||
cy.getValue(firstLineReason).should('have.text', 'Novato');
|
||||
cy.saveCard();
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/claim/${claimId}/development`);
|
||||
|
||||
cy.getValue(firstLineReason).should('have.value', 'Novato');
|
||||
|
||||
//Restart data
|
||||
cy.selectOption(firstLineReason, 'Prisas');
|
||||
|
@ -29,13 +31,16 @@ describe('ClaimDevelopment', () => {
|
|||
});
|
||||
|
||||
it('should add and remove new line', () => {
|
||||
//add row
|
||||
cy.addCard();
|
||||
cy.get(thirdRow).should('exist');
|
||||
|
||||
const rowData = [false, 'Novato', 'Roces', 'Compradores', 'employeeNick', 'Tour'];
|
||||
cy.fillRow(thirdRow, rowData);
|
||||
|
||||
cy.saveCard();
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/claim/${claimId}/development`);
|
||||
|
||||
cy.validateRow(thirdRow, rowData);
|
||||
|
||||
cy.reload();
|
||||
|
|
|
@ -54,7 +54,7 @@ Cypress.Commands.add('getValue', (selector) => {
|
|||
else if ($el.find('.q-select__dropdown-icon').length) {
|
||||
return cy.get(
|
||||
selector +
|
||||
'> .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > span'
|
||||
'> .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > input'
|
||||
);
|
||||
} else {
|
||||
// Puedes añadir un log o lanzar un error si el elemento no es reconocido
|
||||
|
@ -76,7 +76,6 @@ Cypress.Commands.add('checkOption', (selector) => {
|
|||
// Global buttons
|
||||
Cypress.Commands.add('saveCard', () => {
|
||||
cy.get('[title="Save"]').click();
|
||||
cy.get('[title="Save"]').should('have.class', 'disabled');
|
||||
});
|
||||
Cypress.Commands.add('resetCard', () => {
|
||||
cy.get('[title="Reset"]').click();
|
||||
|
@ -123,7 +122,7 @@ Cypress.Commands.add('validateRow', (rowSelector, expectedValues) => {
|
|||
cy.getValue(`:nth-child(${index + 1})`).should(`${prefix}be.checked`);
|
||||
continue;
|
||||
}
|
||||
cy.getValue(`:nth-child(${index + 1})`).should('have.text', value);
|
||||
cy.getValue(`:nth-child(${index + 1})`).should('have.value', value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Aixina forcem que se fasa gulp docker quan tirem els e2e