Merge branch 'master' of https://gitea.verdnatura.es/verdnatura/salix-front into test
gitea/salix-front/pipeline/head This commit looks good
Details
gitea/salix-front/pipeline/head This commit looks good
Details
This commit is contained in:
commit
966d59e52d
|
@ -1,12 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { nextTick, ref, watch } from 'vue';
|
import { nextTick, ref } from 'vue';
|
||||||
import { QInput } from 'quasar';
|
import VnInput from './VnInput.vue';
|
||||||
|
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
insertable: {
|
insertable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -14,70 +11,25 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
|
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
|
||||||
|
const model = defineModel({ prop: 'modelValue' });
|
||||||
|
const inputRef = ref(false);
|
||||||
|
|
||||||
let internalValue = ref($props.modelValue);
|
function setCursorPosition(pos) {
|
||||||
|
const input = inputRef.value.vnInputRef.$el.querySelector('input');
|
||||||
watch(
|
input.focus();
|
||||||
() => $props.modelValue,
|
input.setSelectionRange(pos, pos);
|
||||||
(newVal) => {
|
|
||||||
internalValue.value = newVal;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => internalValue.value,
|
|
||||||
(newVal) => {
|
|
||||||
emit('update:modelValue', newVal);
|
|
||||||
accountShortToStandard();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleKeydown = (e) => {
|
|
||||||
if (e.key === 'Backspace') return;
|
|
||||||
if (e.key === '.') {
|
|
||||||
accountShortToStandard();
|
|
||||||
// TODO: Fix this setTimeout, with nextTick doesn't work
|
|
||||||
setTimeout(() => {
|
|
||||||
setCursorPosition(0, e.target);
|
|
||||||
}, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($props.insertable && e.key.match(/[0-9]/)) {
|
|
||||||
handleInsertMode(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function setCursorPosition(pos, el = vnInputRef.value) {
|
|
||||||
el.focus();
|
|
||||||
el.setSelectionRange(pos, pos);
|
|
||||||
}
|
}
|
||||||
const vnInputRef = ref(false);
|
|
||||||
const handleInsertMode = (e) => {
|
async function handleUpdateModel(val) {
|
||||||
e.preventDefault();
|
model.value = val?.at(-1) === '.' ? useAccountShortToStandard(val) : val;
|
||||||
const input = e.target;
|
await nextTick(() => setCursorPosition(0));
|
||||||
const cursorPos = input.selectionStart;
|
|
||||||
const { maxlength } = vnInputRef.value;
|
|
||||||
let currentValue = internalValue.value;
|
|
||||||
if (!currentValue) currentValue = e.key;
|
|
||||||
const newValue = e.key;
|
|
||||||
if (newValue && !isNaN(newValue) && cursorPos < maxlength) {
|
|
||||||
internalValue.value =
|
|
||||||
currentValue.substring(0, cursorPos) +
|
|
||||||
newValue +
|
|
||||||
currentValue.substring(cursorPos + 1);
|
|
||||||
}
|
|
||||||
nextTick(() => {
|
|
||||||
input.setSelectionRange(cursorPos + 1, cursorPos + 1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
function accountShortToStandard() {
|
|
||||||
internalValue.value = internalValue.value?.replace(
|
|
||||||
'.',
|
|
||||||
'0'.repeat(11 - internalValue.value.length)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QInput @keydown="handleKeydown" ref="vnInputRef" v-model="internalValue" />
|
<VnInput
|
||||||
|
v-model="model"
|
||||||
|
ref="inputRef"
|
||||||
|
:insertable
|
||||||
|
@update:model-value="handleUpdateModel"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -83,7 +83,7 @@ const mixinRules = [
|
||||||
requiredFieldRule,
|
requiredFieldRule,
|
||||||
...($attrs.rules ?? []),
|
...($attrs.rules ?? []),
|
||||||
(val) => {
|
(val) => {
|
||||||
const { maxlength } = vnInputRef.value;
|
const maxlength = $props.maxlength;
|
||||||
if (maxlength && +val.length > maxlength)
|
if (maxlength && +val.length > maxlength)
|
||||||
return t(`maxLength`, { value: maxlength });
|
return t(`maxLength`, { value: maxlength });
|
||||||
const { min, max } = vnInputRef.value.$attrs;
|
const { min, max } = vnInputRef.value.$attrs;
|
||||||
|
@ -108,7 +108,7 @@ const handleInsertMode = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const input = e.target;
|
const input = e.target;
|
||||||
const cursorPos = input.selectionStart;
|
const cursorPos = input.selectionStart;
|
||||||
const { maxlength } = vnInputRef.value;
|
const maxlength = $props.maxlength;
|
||||||
let currentValue = value.value;
|
let currentValue = value.value;
|
||||||
if (!currentValue) currentValue = e.key;
|
if (!currentValue) currentValue = e.key;
|
||||||
const newValue = e.key;
|
const newValue = e.key;
|
||||||
|
@ -143,7 +143,7 @@ const handleUppercase = () => {
|
||||||
:rules="mixinRules"
|
:rules="mixinRules"
|
||||||
:lazy-rules="true"
|
:lazy-rules="true"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
|
:data-cy="$attrs['data-cy'] ?? $attrs.label + '_input'"
|
||||||
>
|
>
|
||||||
<template #prepend v-if="$slots.prepend">
|
<template #prepend v-if="$slots.prepend">
|
||||||
<slot name="prepend" />
|
<slot name="prepend" />
|
||||||
|
|
|
@ -132,7 +132,8 @@ const card = toRef(props, 'item');
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 192px;
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,6 +369,7 @@ globals:
|
||||||
countryFk: Country
|
countryFk: Country
|
||||||
countryCodeFk: Country
|
countryCodeFk: Country
|
||||||
companyFk: Company
|
companyFk: Company
|
||||||
|
nickname: Alias
|
||||||
model: Model
|
model: Model
|
||||||
fuel: Fuel
|
fuel: Fuel
|
||||||
active: Active
|
active: Active
|
||||||
|
|
|
@ -370,6 +370,7 @@ globals:
|
||||||
countryFk: País
|
countryFk: País
|
||||||
countryCodeFk: País
|
countryCodeFk: País
|
||||||
companyFk: Empresa
|
companyFk: Empresa
|
||||||
|
nickname: Alias
|
||||||
errors:
|
errors:
|
||||||
statusUnauthorized: Acceso denegado
|
statusUnauthorized: Acceso denegado
|
||||||
statusInternalServerError: Ha ocurrido un error interno del servidor
|
statusInternalServerError: Ha ocurrido un error interno del servidor
|
||||||
|
|
|
@ -108,7 +108,6 @@ function handleLocation(data, location) {
|
||||||
<VnAccountNumber
|
<VnAccountNumber
|
||||||
v-model="data.account"
|
v-model="data.account"
|
||||||
:label="t('supplier.fiscalData.account')"
|
:label="t('supplier.fiscalData.account')"
|
||||||
clearable
|
|
||||||
data-cy="supplierFiscalDataAccount"
|
data-cy="supplierFiscalDataAccount"
|
||||||
insertable
|
insertable
|
||||||
:maxlength="10"
|
:maxlength="10"
|
||||||
|
@ -185,8 +184,8 @@ function handleLocation(data, location) {
|
||||||
/>
|
/>
|
||||||
<VnCheckbox
|
<VnCheckbox
|
||||||
v-model="data.isVies"
|
v-model="data.isVies"
|
||||||
:label="t('globals.isVies')"
|
:label="t('globals.isVies')"
|
||||||
:info="t('whenActivatingIt')"
|
:info="t('whenActivatingIt')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import VnSection from 'src/components/common/VnSection.vue';
|
import VnSection from 'src/components/common/VnSection.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import SupplierSummary from './Card/SupplierSummary.vue';
|
import SupplierSummary from './Card/SupplierSummary.vue';
|
||||||
|
@ -53,7 +52,7 @@ const columns = computed(() => [
|
||||||
label: t('globals.alias'),
|
label: t('globals.alias'),
|
||||||
name: 'alias',
|
name: 'alias',
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
name: 'search',
|
name: 'nickname',
|
||||||
},
|
},
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
|
@ -120,6 +119,21 @@ const columns = computed(() => [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const filterColumns = computed(() => {
|
||||||
|
const copy = [...columns.value];
|
||||||
|
copy.splice(copy.length - 1, 0, {
|
||||||
|
align: 'left',
|
||||||
|
label: t('globals.params.provinceFk'),
|
||||||
|
name: 'provinceFk',
|
||||||
|
options: provincesOptions.value,
|
||||||
|
columnFilter: {
|
||||||
|
component: 'select',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -130,7 +144,7 @@ const columns = computed(() => [
|
||||||
/>
|
/>
|
||||||
<VnSection
|
<VnSection
|
||||||
:data-key="dataKey"
|
:data-key="dataKey"
|
||||||
:columns="columns"
|
:columns="filterColumns"
|
||||||
prefix="supplier"
|
prefix="supplier"
|
||||||
:array-data-props="{
|
:array-data-props="{
|
||||||
url: 'Suppliers/filter',
|
url: 'Suppliers/filter',
|
||||||
|
@ -165,17 +179,6 @@ const columns = computed(() => [
|
||||||
</template>
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
<template #moreFilterPanel="{ params, searchFn }">
|
|
||||||
<VnSelect
|
|
||||||
:label="t('globals.params.provinceFk')"
|
|
||||||
v-model="params.provinceFk"
|
|
||||||
@update:model-value="searchFn()"
|
|
||||||
:options="provincesOptions"
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
class="q-px-sm q-pr-lg"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</VnSection>
|
</VnSection>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,50 @@
|
||||||
describe('VnInput Component', () => {
|
describe('VnAccountNumber', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
cy.visit('/#/supplier/1/fiscal-data');
|
cy.visit('/#/supplier/1/fiscal-data');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace character at cursor position in insert mode', () => {
|
describe('VnInput handleInsertMode()', () => {
|
||||||
// Simula escribir en el input
|
it('should replace character at cursor position in insert mode', () => {
|
||||||
cy.dataCy('supplierFiscalDataAccount').clear();
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type(
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('4100000001');
|
'{selectall}4100000001',
|
||||||
// Coloca el cursor en la posición 0
|
);
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('{movetostart}');
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('{movetostart}');
|
||||||
// Escribe un número y verifica que se reemplace correctamente
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('999');
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('999');
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
|
||||||
cy.dataCy('supplierFiscalDataAccount').should('have.value', '9990000001');
|
'have.value',
|
||||||
|
'9990000001',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace character at cursor position in insert mode', () => {
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').clear();
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('4100000001');
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('{movetostart}');
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('999');
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
|
||||||
|
'have.value',
|
||||||
|
'9990000001',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should respect maxlength prop', () => {
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').clear();
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('123456789012345');
|
||||||
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
|
||||||
|
'have.value',
|
||||||
|
'1234567890',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace character at cursor position in insert mode', () => {
|
it('should convert short account number to standard format', () => {
|
||||||
// Simula escribir en el input
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').clear();
|
||||||
cy.dataCy('supplierFiscalDataAccount').clear();
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('123.');
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('4100000001');
|
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
|
||||||
// Coloca el cursor en la posición 0
|
'have.value',
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('{movetostart}');
|
'1230000000',
|
||||||
// Escribe un número y verifica que se reemplace correctamente en la posicion incial
|
);
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('999');
|
|
||||||
cy.dataCy('supplierFiscalDataAccount').should('have.value', '9990000001');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should respect maxlength prop', () => {
|
|
||||||
cy.dataCy('supplierFiscalDataAccount').clear();
|
|
||||||
cy.dataCy('supplierFiscalDataAccount').type('123456789012345');
|
|
||||||
cy.dataCy('supplierFiscalDataAccount').should('have.value', '1234567890'); // asumiendo que maxlength es 10
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue