refactor: refs #8684 improve input handling and rendering in VnTable enhance item request logic in ItemRequest
gitea/salix-front/pipeline/pr-dev This commit is unstable Details

This commit is contained in:
Pablo Natek 2025-05-05 14:39:37 +02:00
parent cb1fa3c7f5
commit d64788732e
4 changed files with 81 additions and 52 deletions

View File

@ -110,7 +110,6 @@ const components = {
component: markRaw(VnCheckbox), component: markRaw(VnCheckbox),
event: updateEvent, event: updateEvent,
attrs: { attrs: {
class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
'toggle-indeterminate': true, 'toggle-indeterminate': true,
size: 'sm', size: 'sm',
}, },

View File

@ -398,8 +398,7 @@ const clickHandler = async (event) => {
if (isDateElement || isTimeElement || isQSelectDropDown) return; if (isDateElement || isTimeElement || isQSelectDropDown) return;
if (clickedElement === null) { if (clickedElement === null) {
console.log('destroyInput 1'); destroyInput(editingRow.value, editingField.value);
await destroyInput(editingRow.value, editingField.value);
return; return;
} }
const rowIndex = clickedElement.getAttribute('data-row-index'); const rowIndex = clickedElement.getAttribute('data-row-index');
@ -409,8 +408,7 @@ const clickHandler = async (event) => {
if (editingRow.value !== null && editingField.value !== null) { if (editingRow.value !== null && editingField.value !== null) {
if (editingRow.value == rowIndex && editingField.value == colField) return; if (editingRow.value == rowIndex && editingField.value == colField) return;
console.log('destroyInput 2'); destroyInput(editingRow.value, editingField.value);
await destroyInput(editingRow.value, editingField.value);
} }
if ( if (
@ -419,18 +417,16 @@ const clickHandler = async (event) => {
CrudModelRef.value.formData[rowIndex ?? editingRow.value], CrudModelRef.value.formData[rowIndex ?? editingRow.value],
) )
) { ) {
await renderInput(Number(rowIndex), colField, clickedElement); renderInput(Number(rowIndex), colField, clickedElement);
} }
}; };
async function handleTabKey(event, rowIndex, colField) { function handleTabKey(event, rowIndex, colField) {
if (editingRow.value == rowIndex && editingField.value == colField) { if (editingRow.value == rowIndex && editingField.value == colField)
console.log('destroyInput 3'); destroyInput(editingRow.value, editingField.value);
await destroyInput(editingRow.value, editingField.value);
}
const direction = event.shiftKey ? -1 : 1; const direction = event.shiftKey ? -1 : 1;
const { nextRowIndex, nextColumnName } = await handleTabNavigation( const { nextRowIndex, nextColumnName } = handleTabNavigation(
rowIndex, rowIndex,
colField, colField,
direction, direction,
@ -439,11 +435,10 @@ async function handleTabKey(event, rowIndex, colField) {
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return; if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
event.preventDefault(); event.preventDefault();
console.log('nextColumnName: ', nextColumnName); renderInput(nextRowIndex, nextColumnName, null);
await renderInput(nextRowIndex, nextColumnName, null);
} }
async function renderInput(rowId, field, clickedElement) { function renderInput(rowId, field, clickedElement) {
editingField.value = field; editingField.value = field;
editingRow.value = rowId; editingRow.value = rowId;
@ -480,28 +475,20 @@ async function renderInput(rowId, field, clickedElement) {
} else row[column.name] = value; } else row[column.name] = value;
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row); await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
}, },
keyup: async (event) => { keyup: (event) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
console.log('destroyInput 4'); destroyInput(rowId, field, clickedElement);
await destroyInput(rowId, field, clickedElement);
} }
}, },
keydown: async (event) => { keydown: (event) => {
switch (event.key) { switch (event.key) {
case 'Tab': case 'Tab':
console.log('field: ', field); handleTabKey(event, rowId, field);
console.log('target: ', event.target);
await handleTabKey(event, rowId, field);
event.stopPropagation(); event.stopPropagation();
const column = $props.columns.find((col) => col.name === field);
if (typeof column?.beforeDestroy === 'function')
await column.beforeDestroy(
CrudModelRef.value.formData[editingRow.value],
);
break; break;
case 'Escape': case 'Escape':
console.log('destroyInput 5'); destroyInput(rowId, field, clickedElement);
await destroyInput(rowId, field, clickedElement);
break; break;
default: default:
break; break;
@ -534,17 +521,23 @@ async function updateSelectValue(value, column, row, oldValue) {
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row); await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
} }
async function destroyInput(rowIndex, field, clickedElement) { function destroyInput(rowIndex, field, clickedElement) {
if (!clickedElement) if (!clickedElement)
clickedElement = document.querySelector( clickedElement = document.querySelector(
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`, `[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
); );
if (clickedElement) { if (clickedElement) {
await nextTick(); const column = $props.columns.find((col) => col.name === field);
render(null, clickedElement); if (typeof column?.beforeDestroy === 'function')
Array.from(clickedElement.childNodes).forEach((child) => { column.beforeDestroy(CrudModelRef.value.formData[rowIndex]);
child.style.visibility = 'visible';
child.style.position = ''; nextTick().then(() => {
render(null, clickedElement);
Array.from(clickedElement.childNodes).forEach((child) => {
child.style.visibility = 'visible';
child.style.position = '';
});
}); });
} }
@ -553,7 +546,7 @@ async function destroyInput(rowIndex, field, clickedElement) {
editingField.value = null; editingField.value = null;
} }
async function handleTabNavigation(rowIndex, colName, direction) { function handleTabNavigation(rowIndex, colName, direction) {
const columns = $props.columns; const columns = $props.columns;
const totalColumns = columns.length; const totalColumns = columns.length;
let currentColumnIndex = columns.findIndex((col) => col.name === colName); let currentColumnIndex = columns.findIndex((col) => col.name === colName);

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted, nextTick } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'filters/index'; import { toCurrency } from 'filters/index';
@ -23,7 +23,6 @@ const stateStore = useStateStore();
const denyFormRef = ref(null); const denyFormRef = ref(null);
const denyRequestId = ref(null); const denyRequestId = ref(null);
const userParams = { const userParams = {
state: 'pending',
daysOnward: 7, daysOnward: 7,
}; };
const tableRef = ref(); const tableRef = ref();
@ -136,6 +135,7 @@ const columns = computed(() => [
align: 'left', align: 'left',
component: 'input', component: 'input',
columnClass: 'expand', columnClass: 'expand',
isEditable: ({ isOk }) => isOk === null,
}, },
{ {
label: t('item.buyRequest.achieved'), label: t('item.buyRequest.achieved'),
@ -143,22 +143,35 @@ const columns = computed(() => [
align: 'left', align: 'left',
component: 'input', component: 'input',
columnClass: 'shrink', columnClass: 'shrink',
isEditable: (row) => row?.itemFk, isEditable: ({ itemFk, isOk }) => {
beforeDestroy: async ({ id, itemFk, saleQuantity, state }) => { if (itemFk && isOk === null) return true;
if (!saleQuantity) { },
await tableRef.value.reload(); beforeDestroy: (row) => {
return; console.log('row: ', row);
if (!row.saleQuantity) {
return tableRef.value.reload();
} }
try { try {
await axios.post(`TicketRequests/${id}/confirm`, { axios
id, .post(`TicketRequests/${row.id}/confirm`, {
itemFk: parseInt(itemFk), id: row.id,
quantity: parseInt(saleQuantity), itemFk: parseInt(row.itemFk),
}); quantity: parseInt(row.saleQuantity),
await tableRef.value.reload(); })
.then(() => {
axios
.get(`Items/findOne`, { where: { id: row.itemFk } })
.then((response) => {
console.log('response: ', response);
row.itemDescription = response.data.name;
row.state = 1;
});
notify(t('globals.dataSaved'), 'positive');
return tableRef.value.reload();
});
} catch (error) { } catch (error) {
notify(error.response.data.error.message, 'negative'); notify(error.response.data.error.message, 'negative');
await tableRef.value.reload(); return tableRef.value.reload();
} }
}, },
}, },
@ -174,7 +187,7 @@ const columns = computed(() => [
{ {
label: t('globals.state'), label: t('globals.state'),
name: 'state', name: 'state',
format: (row) => getState(row.isOk), format: ({ isOk }) => getState(isOk),
align: 'left', align: 'left',
}, },
{ {
@ -202,6 +215,7 @@ const columns = computed(() => [
icon: 'thumb_down', icon: 'thumb_down',
fill: true, fill: true,
isPrimary: true, isPrimary: true,
show: ({ isOk }) => isOk === null,
action: (row) => showDenyRequestForm(row.id), action: (row) => showDenyRequestForm(row.id),
}, },
], ],
@ -309,7 +323,8 @@ const showDenyRequestForm = (requestId) => {
v-model="data.observation" v-model="data.observation"
fill-input fill-input
:required="true" :required="true"
autogrow auto-grow
data-cy="discardTextArea"
/> />
</template> </template>
</FormModelPopup> </FormModelPopup>

View File

@ -0,0 +1,22 @@
describe('Item Request', () => {
beforeEach(() => {
cy.login('buyer');
cy.visit(`/#/item/request`);
});
it('should fill the id and quantity then check the concept was updated', async () => {
cy.get('td[data-row-index="0"][data-col-field="itemFk"]')
.should('exist')
.type('4');
cy.get('td[data-row-index="0"][data-col-field="saleQuantity"]')
.should('exist')
.type('10{esc}');
cy.checkNotification('Data saved');
});
it('should now click on the second declain request icon then type the reason', async () => {
cy.selectOption('[data-cy="State_select"]', 'Pending');
cy.get('button[title="Discard"]').eq(0).click();
cy.dataCy('discardTextArea').should('exist').type('test(enter)');
cy.checkNotification('Data saved');
});
});