4774-traducciones #853
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
import { computed, nextTick, ref, useAttrs, watch } from 'vue';
|
||||
import { useRouter, onBeforeRouteLeave } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -98,6 +98,7 @@ defineExpose({
|
|||
formData,
|
||||
originalData,
|
||||
vnPaginateRef,
|
||||
resetData,
|
||||
});
|
||||
|
||||
onBeforeRouteLeave((to, from, next) => {
|
||||
|
|
|
@ -184,6 +184,12 @@ watch(
|
|||
{ immediate: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => $props.create,
|
||||
(value) => (createForm.value = value),
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
||||
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
|
||||
|
||||
|
@ -474,6 +480,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
|||
<QBtn
|
||||
v-for="(btn, index) of col.actions"
|
||||
v-show="btn.show ? btn.show(row) : true"
|
||||
v-bind="row.attrs"
|
||||
:key="index"
|
||||
:title="btn.title"
|
||||
:icon="btn.icon"
|
||||
|
@ -489,6 +496,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
|||
: 'hidden'
|
||||
}`"
|
||||
@click="btn.action(row)"
|
||||
:disable="btn.disable ? btn.disable(row) : true"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -329,6 +329,7 @@ globals:
|
|||
medical: Mutual
|
||||
pit: IRPF
|
||||
wasteRecalc: Waste recaclulate
|
||||
translations: Translations
|
||||
operator: Operator
|
||||
parking: Parking
|
||||
unsavedPopup:
|
||||
|
|
|
@ -329,6 +329,7 @@ globals:
|
|||
medical: Mutua
|
||||
pit: IRPF
|
||||
wasteRecalc: Recalcular mermas
|
||||
translations: Traducciones
|
||||
operator: Operario
|
||||
parking: Parking
|
||||
unsavedPopup:
|
||||
|
|
|
@ -108,6 +108,7 @@ function onBeforeSave(formData, originalData) {
|
|||
:label="t('customer.extendedList.tableVisibleColumns.phone')"
|
||||
:rules="validate('client.phone')"
|
||||
clearable
|
||||
type="number"
|
||||
v-model="data.phone"
|
||||
data-cy="customerPhone"
|
||||
/>
|
||||
|
@ -115,6 +116,7 @@ function onBeforeSave(formData, originalData) {
|
|||
:label="t('customer.summary.mobile')"
|
||||
:rules="validate('client.mobile')"
|
||||
clearable
|
||||
type="number"
|
||||
v-model="data.mobile"
|
||||
/>
|
||||
</VnRow>
|
||||
|
|
|
@ -149,7 +149,7 @@ function sendPdfInvoice({ address }) {
|
|||
const createInvoiceInCorrection = async () => {
|
||||
const { data: correctingId } = await axios.post(
|
||||
'InvoiceIns/corrective',
|
||||
Object.assign(correctionFormData, { id: entityId.value })
|
||||
Object.assign(correctionFormData, { id: entityId.value }),
|
||||
);
|
||||
push({ path: `/invoice-in/${correctingId}/summary` });
|
||||
};
|
||||
|
@ -272,7 +272,6 @@ const createInvoiceInCorrection = async () => {
|
|||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
{{ console.log('opt: ', opt) }}
|
||||
<QItemSection>
|
||||
<QItemLabel
|
||||
>{{ opt.id }} -
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import axios from 'axios';
|
||||
useArrayData;
|
||||
|
||||
const { t } = useI18n();
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
name: 'id',
|
||||
label: t('id'),
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: primaryKey,
|
||||
label: primaryKey,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'en',
|
||||
label: t('defaultLang(en)'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: lang,
|
||||
label: lang,
|
||||
component: 'input',
|
||||
},
|
||||
]);
|
||||
|
||||
const tableRef = ref({});
|
||||
const langs = ref([]);
|
||||
const tables = ref([]);
|
||||
const lang = ref('ca');
|
||||
const table = ref();
|
||||
const originalData = ref([]);
|
||||
const selected = ref([]);
|
||||
const PRIMARY_LANG = 'en';
|
||||
|
||||
const primaryKey = computed(() => table.value?.primaryKey);
|
||||
const field = computed(() => table.value.field);
|
||||
const url = computed(() => {
|
||||
if (!table.value?.tableName) return;
|
||||
const arrayData = useArrayData('translations');
|
||||
if (arrayData) arrayData.reset(['skip', 'filter.skip', 'page']);
|
||||
|
||||
return table.value?.tableName + 's';
|
||||
});
|
||||
|
||||
async function loadTable(data) {
|
||||
if (data) originalData.value = data;
|
||||
if (!lang.value) return;
|
||||
const toFilter = JSON.parse(JSON.stringify(originalData.value));
|
||||
if (!toFilter) return;
|
||||
|
||||
const filtered = [];
|
||||
for (const row of toFilter) {
|
||||
if (row.lang != PRIMARY_LANG) continue;
|
||||
|
||||
row.en = row[field.value];
|
||||
const translation = originalData.value.find(
|
||||
(o) => o.lang == lang.value && o[primaryKey.value] == row[primaryKey.value],
|
||||
);
|
||||
|
||||
row[lang.value] = translation?.[field.value];
|
||||
row.id = translation?.id;
|
||||
filtered.push(row);
|
||||
}
|
||||
|
||||
tableRef.value.CrudModelRef.resetData(filtered);
|
||||
}
|
||||
|
||||
function resetOriginalData() {
|
||||
originalData.value = null;
|
||||
|
||||
}
|
||||
|
||||
async function save(data, changes) {
|
||||
const { deletes } = data;
|
||||
const { updates, creates } = changes();
|
||||
|
||||
for (const update of updates ?? []) {
|
||||
update.data[field.value] = update.data[lang.value];
|
||||
delete update.data[lang.value];
|
||||
}
|
||||
|
||||
for (const create of creates ?? []) {
|
||||
delete create['$index'];
|
||||
delete create[PRIMARY_LANG];
|
||||
create.lang = lang.value;
|
||||
create[field.value] = create[lang.value];
|
||||
delete create[lang.value];
|
||||
}
|
||||
|
||||
await axios.post(url.value + '/crud', { updates, creates, deletes });
|
||||
tableRef.value.reload();
|
||||
tableRef.value.CrudModelRef.hasChanges = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData url="Languages" @on-fetch="(data) => (langs = data)" auto-load />
|
||||
<FetchData
|
||||
url="Applications/get-i18n-tables"
|
||||
@on-fetch="(data) => (tables = data)"
|
||||
auto-load
|
||||
/>
|
||||
<VnSubToolbar>
|
||||
<template #st-data>
|
||||
<VnSelect
|
||||
:label="t('table')"
|
||||
v-model="table"
|
||||
:options="tables"
|
||||
option-label="tableName"
|
||||
option-value="tableName"
|
||||
@update:model-value="resetOriginalData()"
|
||||
:emit-value="false"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('lang')"
|
||||
v-model="lang"
|
||||
:options="langs"
|
||||
option-label="code"
|
||||
option-value="code"
|
||||
@update:model-value="loadTable()"
|
||||
/>
|
||||
</template>
|
||||
</VnSubToolbar>
|
||||
<VnTable
|
||||
v-if="url"
|
||||
ref="tableRef"
|
||||
data-key="translations"
|
||||
:url="url"
|
||||
:limit="0"
|
||||
:columns="columns"
|
||||
:create="{
|
||||
urlCreate: url,
|
||||
title: 'Create translation',
|
||||
onDataSaved: () => tableRef.reload(),
|
||||
formInitialData: { lang: 'en' },
|
||||
}"
|
||||
:right-search="false"
|
||||
@on-fetch="(data) => loadTable(data)"
|
||||
:search-url="false"
|
||||
:is-editable="true"
|
||||
:table="{
|
||||
'row-key': 'id',
|
||||
selection: 'multiple',
|
||||
}"
|
||||
v-model:selected="selected"
|
||||
:save-fn="save"
|
||||
auto-load
|
||||
>
|
||||
<template #more-create-dialog="{ data }">
|
||||
<VnInput v-model="data[field]" :label="field" />
|
||||
</template>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
primaryKey: Clave primaria
|
||||
defaultLang(en): Idioma por defecto(Eng)
|
||||
secondLang: Idioma secundario
|
||||
table: Tabla
|
||||
lang: Idioma
|
||||
en:
|
||||
primaryKey: Primary key
|
||||
defaultLang(en): Default language(Eng)
|
||||
secondLang: Second language
|
||||
table: Table
|
||||
lang: Language
|
||||
</i18n>
|
|
@ -17,6 +17,7 @@ import Agency from './agency';
|
|||
import Zone from './zone';
|
||||
import Account from './account';
|
||||
import Monitor from './monitor';
|
||||
import TranslationsVn from './translationsVn.js';
|
||||
|
||||
export default [
|
||||
Item,
|
||||
|
@ -38,4 +39,5 @@ export default [
|
|||
Zone,
|
||||
Account,
|
||||
Monitor,
|
||||
TranslationsVn,
|
||||
];
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { RouterView } from 'vue-router';
|
||||
|
||||
export default {
|
||||
path: '/translations',
|
||||
name: 'Translations',
|
||||
meta: {
|
||||
title: 'translations',
|
||||
icon: 'history_edu',
|
||||
moduleName: 'Translations',
|
||||
},
|
||||
component: RouterView,
|
||||
menus: {
|
||||
main: [],
|
||||
card: [],
|
||||
},
|
||||
};
|
|
@ -6,7 +6,14 @@ const workerCard = {
|
|||
component: () => import('src/pages/Worker/Card/WorkerCard.vue'),
|
||||
redirect: { name: 'WorkerSummary' },
|
||||
meta: {
|
||||
menu: [
|
||||
title: 'workers',
|
||||
icon: 'vn:worker',
|
||||
moduleName: 'Worker',
|
||||
keyBinding: 'w',
|
||||
},
|
||||
menus: {
|
||||
main: ['WorkerList', 'WorkerDepartment', 'TranslationsVn'],
|
||||
card: [
|
||||
'WorkerBasicData',
|
||||
'WorkerNotes',
|
||||
'WorkerPda',
|
||||
|
@ -226,7 +233,7 @@ export default {
|
|||
icon: 'vn:worker',
|
||||
moduleName: 'Worker',
|
||||
keyBinding: 'w',
|
||||
menu: ['WorkerList', 'WorkerDepartment'],
|
||||
menu: ['WorkerList', 'WorkerDepartment', 'TranslationsVn'],
|
||||
},
|
||||
component: RouterView,
|
||||
redirect: { name: 'WorkerMain' },
|
||||
|
@ -268,6 +275,15 @@ export default {
|
|||
departmentCard,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'translations',
|
||||
name: 'TranslationsVn',
|
||||
meta: {
|
||||
title: 'translations',
|
||||
icon: 'history_edu',
|
||||
},
|
||||
component: () => import('src/pages/Worker/TranslationsVn.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -15,7 +15,7 @@ import entry from 'src/router/modules/entry';
|
|||
import roadmap from 'src/router/modules/roadmap';
|
||||
import agency from 'src/router/modules/agency';
|
||||
import zone from 'src/router/modules/zone';
|
||||
import account from './modules/account';
|
||||
import account from 'src/router/modules/account';
|
||||
import monitor from 'src/router/modules/monitor';
|
||||
|
||||
const routes = [
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
describe('Translations', () => {
|
||||
const tableType = 'itemTypeI18n';
|
||||
const translationSelect = '[data-cy="Table_select"]';
|
||||
const firstRow = '.q-virtual-scroll__content > :nth-child(1) > :nth-child(4)';
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('buyer');
|
||||
cy.visit(`/#/worker/translations`);
|
||||
});
|
||||
|
||||
it('should load translations and modify', () => {
|
||||
cy.get('[data-cy="Table_select"]').click();
|
||||
cy.selectOption(translationSelect, tableType);
|
||||
cy.get(firstRow).type('test');
|
||||
cy.saveCard();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
tableRef.crudModel.resetData