Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 7355-accountMigration2

This commit is contained in:
Carlos Satorres 2024-08-07 12:23:22 +02:00
commit df1b63da98
20 changed files with 230 additions and 629 deletions

View File

@ -100,7 +100,6 @@ const isResetting = ref(false);
const hasChanges = ref(!$props.observeFormChanges); const hasChanges = ref(!$props.observeFormChanges);
const originalData = ref({}); const originalData = ref({});
const formData = computed(() => state.get(modelValue)); const formData = computed(() => state.get(modelValue));
const formUrl = computed(() => $props.url);
const defaultButtons = computed(() => ({ const defaultButtons = computed(() => ({
save: { save: {
color: 'primary', color: 'primary',
@ -148,11 +147,14 @@ if (!$props.url)
(val) => updateAndEmit('onFetch', val) (val) => updateAndEmit('onFetch', val)
); );
watch(formUrl, async () => { watch(
() => [$props.url, $props.filter],
async () => {
originalData.value = null; originalData.value = null;
reset(); reset();
await fetch(); await fetch();
}); }
);
onBeforeRouteLeave((to, from, next) => { onBeforeRouteLeave((to, from, next) => {
if (hasChanges.value && $props.observeFormChanges) if (hasChanges.value && $props.observeFormChanges)

View File

@ -50,7 +50,7 @@ const formattedTime = computed({
} }
if (!props.timeOnly) { if (!props.timeOnly) {
const [hh, mm] = time.split(':'); const [hh, mm] = time.split(':');
const date = model.value ?? Date.vnNew(); const date = new Date(model.value ? model.value : null);
date.setHours(hh, mm, 0); date.setHours(hh, mm, 0);
time = date?.toISOString(); time = date?.toISOString();
} }
@ -62,7 +62,7 @@ const formattedTime = computed({
function dateToTime(newDate) { function dateToTime(newDate) {
return date.formatDate(new Date(newDate), dateFormat); return date.formatDate(new Date(newDate), dateFormat);
} }
const timeField = ref();
watch( watch(
() => model.value, () => model.value,
(val) => (formattedTime.value = val), (val) => (formattedTime.value = val),
@ -153,4 +153,3 @@ watch(
es: es:
Open time: Abrir tiempo Open time: Abrir tiempo
</i18n> </i18n>
, nextTick

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { onBeforeMount } from 'vue'; import { watch, computed } from 'vue';
import { date } from 'quasar'; import { date } from 'quasar';
import VnPaginate from 'src/components/ui/VnPaginate.vue'; import VnPaginate from 'src/components/ui/VnPaginate.vue';
import VnAvatar from '../ui/VnAvatar.vue'; import VnAvatar from '../ui/VnAvatar.vue';
@ -10,7 +10,8 @@ const $props = defineProps({
where: { type: Object, default: () => {} }, where: { type: Object, default: () => {} },
}); });
const filter = { const filter = computed(() => {
return {
fields: ['smsFk'], fields: ['smsFk'],
include: { include: {
relation: 'sms', relation: 'sms',
@ -32,9 +33,9 @@ const filter = {
}, },
}, },
}, },
}; ...{ where: $props.where },
};
onBeforeMount(() => (filter.where = $props.where)); });
function formatNumber(number) { function formatNumber(number) {
if (number.length <= 10) return number; if (number.length <= 10) return number;

View File

@ -28,7 +28,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
delete params.filter; delete params.filter;
store.userParams = { ...params, ...store.userParams }; store.userParams = { ...params, ...store.userParams };
store.userFilter = { ...filter, ...store.userFilter }; store.userFilter = { ...filter, ...store.userFilter };
if (filter.order) store.order = filter.order; if (filter?.order) store.order = filter.order;
} }
}); });

View File

@ -90,6 +90,9 @@ globals:
salesPerson: SalesPerson salesPerson: SalesPerson
send: Send send: Send
code: Code code: Code
since: Since
from: From
to: To
pageTitles: pageTitles:
logIn: Login logIn: Login
summary: Summary summary: Summary

View File

@ -90,6 +90,9 @@ globals:
salesPerson: Comercial salesPerson: Comercial
send: Enviar send: Enviar
code: Código code: Código
since: Desde
from: Desde
to: Hasta
pageTitles: pageTitles:
logIn: Inicio de sesión logIn: Inicio de sesión
summary: Resumen summary: Resumen
@ -697,8 +700,6 @@ invoiceOut:
percentageText: '{getPercentage}% {getAddressNumber} de {getNAddresses}' percentageText: '{getPercentage}% {getAddressNumber} de {getNAddresses}'
pdfsNumberText: '{nPdfs} de {totalPdfs} PDFs' pdfsNumberText: '{nPdfs} de {totalPdfs} PDFs'
negativeBases: negativeBases:
from: Desde
to: Hasta
company: Empresa company: Empresa
country: País country: País
clientId: Id cliente clientId: Id cliente
@ -1240,8 +1241,6 @@ components:
# LatestBuysFilter # LatestBuysFilter
salesPersonFk: Comprador salesPersonFk: Comprador
supplierFk: Proveedor supplierFk: Proveedor
from: Desde
to: Hasta
active: Activo active: Activo
visible: Visible visible: Visible
floramondo: Floramondo floramondo: Floramondo

View File

@ -85,7 +85,7 @@ const fetchMailAliases = async () => {
paginateRef.value.fetch(); paginateRef.value.fetch();
}; };
const getAccountData = async () => { const getAccountData = async (reload = true) => {
loading.value = true; loading.value = true;
hasAccount.value = await fetchAccountExistence(); hasAccount.value = await fetchAccountExistence();
if (!hasAccount.value) { if (!hasAccount.value) {
@ -93,7 +93,7 @@ const getAccountData = async () => {
store.data = []; store.data = [];
return; return;
} }
await fetchMailAliases(); reload && (await fetchMailAliases());
loading.value = false; loading.value = false;
}; };
@ -102,13 +102,11 @@ const openCreateMailAliasForm = () => createMailAliasDialogRef.value.show();
watch( watch(
() => route.params.id, () => route.params.id,
() => { () => {
store.url = urlPath;
store.filter = filter.value;
getAccountData(); getAccountData();
} }
); );
onMounted(async () => await getAccountData()); onMounted(async () => await getAccountData(false));
</script> </script>
<template> <template>

View File

@ -1,262 +1,6 @@
<script setup> <script setup>
import { onBeforeMount, ref } from 'vue'; import VnLog from 'src/components/common/VnLog.vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { useStateStore } from 'stores/useStateStore';
import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
const { t } = useI18n();
const route = useRoute();
const stateStore = useStateStore();
const clientLogs = ref(null);
const urlClientLogsEditors = ref(null);
const urlClientLogsModels = ref(null);
const clientLogsModelsOptions = ref([]);
const clientLogsOptions = ref([]);
const clientLogsEditorsOptions = ref([]);
const radioButtonValue = ref('all');
const insert = ref(false);
const update = ref(false);
const deletes = ref(false);
const select = ref(false);
const neq = ref(null);
const inq = ref([]);
const filterClientLogs = {
fields: [
'id',
'originFk',
'userFk',
'action',
'changedModel',
'oldInstance',
'newInstance',
'creationDate',
'changedModel',
'changedModelId',
'changedModelValue',
'description',
],
include: [
{
relation: 'user',
scope: {
fields: ['nickname', 'name', 'image'],
include: { relation: 'worker', scope: { fields: ['id'] } },
},
},
],
order: ['creationDate DESC', 'id DESC'],
limit: 20,
};
const filterClientLogsEditors = {
fields: ['id', 'nickname', 'name', 'image'],
order: 'nickname',
limit: 30,
};
const filterClientLogsModels = { order: ['changedModel'] };
const urlBase = `ClientLogs/${route.params.id}`;
onBeforeMount(() => {
stateStore.rightDrawer = true;
filterClientLogs.where = {
and: [
{ originFk: `${route.params.id}` },
{ userFk: { neq: radioButtonValue.value } },
{ action: { inq: inq.value } },
],
};
urlClientLogsEditors.value = `${urlBase}/editors`;
urlClientLogsModels.value = `${urlBase}/models`;
});
const getClientLogs = async (value, status) => {
if (status === 'neq') {
neq.value = value;
} else {
setInq(value, status);
}
filterClientLogs.where = {
and: [
{ originFk: `${route.params.id}` },
{ userFk: { neq: neq.value } },
{ action: { inq: inq.value } },
],
};
clientLogs.value?.fetch();
};
const setInq = (value, status) => {
if (status) {
if (!inq.value.includes(value)) {
inq.value.push(value);
}
} else {
inq.value = inq.value.filter((item) => item !== value);
}
};
</script> </script>
<template> <template>
<FetchData <VnLog model="Client" />
:filter="filterClientLogs"
@on-fetch="(data) => (clientLogsOptions = data)"
auto-load
url="ClientLogs"
ref="clientLogs"
/>
<FetchData
:filter="filterClientLogsEditors"
@on-fetch="(data) => (clientLogsEditorsOptions = data)"
auto-load
:url="urlClientLogsEditors"
/>
<FetchData
:filter="filterClientLogsModels"
@on-fetch="(data) => (clientLogsModelsOptions = data)"
auto-load
:url="urlClientLogsModels"
/>
<h5 class="flex justify-center color-vn-label">
{{ t('globals.noResults') }}
</h5>
<QDrawer :width="256" show-if-above side="right" v-model="stateStore.rightDrawer">
<div class="q-mt-sm q-px-md">
<VnInput :label="t('Search')" clearable>
<template #append>
<QIcon name="info" class="cursor-pointer">
<QTooltip>
{{ t('Search by id or concept') }}
</QTooltip>
</QIcon>
</template>
</VnInput>
<VnSelect
:label="t('Entity')"
:options="[]"
class="q-mt-md"
hide-selected
option-label="name"
option-value="id"
/>
<div class="q-mt-lg">
<QRadio
:dark="true"
:label="t('All')"
@update:model-value="getClientLogs($event, 'neq')"
dense
v-model="radioButtonValue"
val="all"
/>
</div>
<div class="q-mt-md">
<QRadio
:dark="true"
:label="t('User')"
@update:model-value="getClientLogs($event, 'neq')"
dense
v-model="radioButtonValue"
val="user"
/>
</div>
<div class="q-mt-md">
<QRadio
:dark="true"
:label="t('System')"
@update:model-value="getClientLogs($event, 'neq')"
dense
v-model="radioButtonValue"
val="system"
/>
</div>
<VnSelect
:label="t('User')"
:options="[]"
class="q-mt-sm"
hide-selected
option-label="name"
option-value="id"
/>
<VnInput :label="t('Changes')" clearable class="q-mt-sm">
<template #append>
<QIcon name="info" class="cursor-pointer">
<QTooltip>
{{ t('Search by changes') }}
</QTooltip>
</QIcon>
</template>
</VnInput>
<div class="q-mt-md">
<QCheckbox
:label="t('Creates')"
@update:model-value="getClientLogs('insert', $event)"
v-model="insert"
/>
</div>
<div>
<QCheckbox
:label="t('Edits')"
@update:model-value="getClientLogs('update', $event)"
v-model="update"
/>
</div>
<div>
<QCheckbox
:label="t('Deletes')"
@update:model-value="getClientLogs('delete', $event)"
v-model="deletes"
/>
</div>
<div>
<QCheckbox
:label="t('Accesses')"
@update:model-value="getClientLogs('select', $event)"
v-model="select"
/>
</div>
<VnInputDate :label="t('Date')" class="q-mt-sm" />
<VnInput :label="t('To')" clearable class="q-mt-md" />
</div>
</QDrawer>
<QPageSticky
:offset="[18, 18]"
v-if="radioButtonValue !== 'all' || insert || update || deletes || select"
>
<QBtn color="primary" fab icon="filter_alt_off" />
<QTooltip>
{{ t('Quit filter') }}
</QTooltip>
</QPageSticky>
</template> </template>
<i18n>
es:
Search: Buscar
Search by id or concept: xxx
Entity: Entidad
All: Todo
User: Usuario
System: Sistema
Changes: Cambios
Search by changes: xxx
Creates: Crea
Edits: Modifica
Deletes: Elimina
Accesses: Accede
Date: Fecha
To: Hasta
Quit filter: Quitar filtro
</i18n>

View File

@ -1,15 +1,18 @@
<script setup> <script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import VnNotes from 'src/components/ui/VnNotes.vue'; import VnNotes from 'src/components/ui/VnNotes.vue';
const route = useRoute(); const route = useRoute();
const noteFilter = { const noteFilter = computed(() => {
return {
order: 'created DESC', order: 'created DESC',
where: { where: {
clientFk: `${route.params.id}`, clientFk: `${route.params.id}`,
}, },
}; };
});
</script> </script>
<template> <template>

View File

@ -1,146 +1,107 @@
<script setup> <script setup>
import axios from 'axios';
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router'; import { useRoute } from 'vue-router';
import { toCurrency, toDate } from 'src/filters'; import { toCurrency, toDate } from 'src/filters';
import FetchData from 'components/FetchData.vue'; import VnTable from 'components/VnTable/VnTable.vue';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const tableRef = ref();
const rows = ref([]); const filter = computed(() => {
return {
const filter = {
where: { clientFk: route.params.id }, where: { clientFk: route.params.id },
order: ['started DESC'], };
limit: 20, });
const componentColumn = (type) => {
return {
columnFilter: {
component: type,
},
columnCreate: {
component: type,
},
};
}; };
const tableColumnComponents = {
since: {
component: 'span',
props: () => {},
event: () => {},
},
to: {
component: 'span',
props: () => {},
event: () => {},
},
amount: {
component: 'span',
props: () => {},
event: () => {},
},
period: {
component: 'span',
props: () => {},
event: () => {},
},
};
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'left', align: 'left',
field: 'started', label: t('globals.since'),
label: t('Since'), name: 'started',
name: 'since', format: ({ started }) => toDate(started),
format: (value) => toDate(value), create: true,
...componentColumn('date'),
}, },
{ {
align: 'left', align: 'left',
field: 'finished', name: 'finished',
label: t('To'), label: t('globals.to'),
name: 'to', format: ({ finished }) => toDate(finished),
format: (value) => toDate(value), create: true,
...componentColumn('date'),
}, },
{ {
align: 'left', align: 'left',
field: 'amount',
label: t('Amount'),
name: 'amount', name: 'amount',
format: (value) => toCurrency(value), label: t('globals.amount'),
format: ({ amount }) => toCurrency(amount),
create: true,
...componentColumn('number'),
}, },
{ {
align: 'left', align: 'left',
field: 'period',
label: t('Period'),
name: 'period', name: 'period',
label: t('Period'),
create: true,
...componentColumn('number'),
},
{
align: 'left',
name: 'tableActions',
actions: [
{
title: t('Finish that recovery period'),
icon: 'lock',
show: (row) => !row.finished,
action: ({ id }) => setFinished(id),
isPrimary: true,
},
],
}, },
]); ]);
const toCustomerRecoverieCreate = () => { function setFinished(id) {
router.push({ name: 'CustomerRecoverieCreate' }); axios.patch(`Recoveries/${id}`, { finished: Date.vnNow() });
}; tableRef.value.reload();
}
</script> </script>
<template> <template>
<FetchData <VnTable
:filter="filter" ref="tableRef"
@on-fetch="(data) => (rows = data)" data-key="Recoveries"
auto-load
url="Recoveries" url="Recoveries"
/> search-url="recoveries"
:filter="filter"
<div class="full-width flex justify-center"> order="started DESC"
<QPage class="card-width q-pa-lg">
<QTable
:columns="columns" :columns="columns"
:no-data-label="t('globals.noResults')" :use-model="true"
:pagination="{ rowsPerPage: 12 }" :right-search="false"
:rows="rows" :create="{
class="full-width q-mt-md" urlCreate: 'Recoveries',
row-key="id" title: 'New recovery',
> onDataSaved: () => tableRef.reload(),
<template #body-cell="props"> formInitialData: { clientFk: route.params.id, started: Date.vnNew() },
<QTd :props="props"> }"
<QTr :props="props" class="cursor-pointer"> auto-load
<component />
:is="tableColumnComponents[props.col.name].component"
class="col-content"
v-bind="
tableColumnComponents[props.col.name].props(props)
"
@click="
tableColumnComponents[props.col.name].event(props)
"
>
{{ props.value }}
</component>
</QTr>
</QTd>
</template>
</QTable>
</QPage>
</div>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="toCustomerRecoverieCreate()" color="primary" fab icon="add" />
<QTooltip>
{{ t('New recoverie') }}
</QTooltip>
</QPageSticky>
</template> </template>
<style lang="scss">
.consignees-card {
border: 2px solid var(--vn-accent-color);
border-radius: 10px;
padding: 10px;
}
.label-color {
color: var(--vn-label-color);
}
</style>
<i18n> <i18n>
es: es:
Since: Desde
To: Hasta
Amount: Importe
Period: Periodo Period: Periodo
New recoverie: Nuevo recobro New recovery: Nuevo recobro
Finish that recovery period: Terminar recobro
</i18n> </i18n>

View File

@ -1,17 +1,16 @@
<script setup> <script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import VnSms from 'src/components/ui/VnSms.vue'; import VnSms from 'src/components/ui/VnSms.vue';
const route = useRoute(); const route = useRoute();
const id = route.params.id; const where = computed(() => {
return {
const where = { clientFk: route.params.id,
clientFk: id,
ticketFk: null, ticketFk: null,
}; };
});
</script> </script>
<template> <template>
<div class="column items-center">
<VnSms url="clientSms" :where="where" /> <VnSms url="clientSms" :where="where" />
</div>
</template> </template>

View File

@ -2,164 +2,81 @@
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import axios from 'axios'; import axios from 'axios';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useValidator } from 'src/composables/useValidator';
import useNotify from 'src/composables/useNotify';
import { useStateStore } from 'stores/useStateStore';
import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import CustomerChangePassword from 'src/pages/Customer/components/CustomerChangePassword.vue'; import CustomerChangePassword from 'src/pages/Customer/components/CustomerChangePassword.vue';
import FormModel from 'components/FormModel.vue';
const { notify } = useNotify();
const { t } = useI18n(); const { t } = useI18n();
const { validate } = useValidator();
const quasar = useQuasar(); const quasar = useQuasar();
const route = useRoute(); const route = useRoute();
const stateStore = useStateStore();
const active = ref(false);
const canChangePassword = ref(0); const canChangePassword = ref(0);
const email = ref(null);
const isLoading = ref(false);
const name = ref(null);
const usersPreviewRef = ref(null);
const user = ref([]);
const dataChanges = computed(() => { const filter = computed(() => {
return ( return {
user.value.active !== active.value || fields: ['active', 'email', 'name'],
user.value.email !== email.value || where: { id: route.params.id },
user.value.name !== name.value };
);
}); });
const filter = { where: { id: `${route.params.id}` } };
const showChangePasswordDialog = () => { const showChangePasswordDialog = () => {
quasar.dialog({ quasar.dialog({
component: CustomerChangePassword, component: CustomerChangePassword,
componentProps: { componentProps: {
id: route.params.id, id: route.params.id,
promise: usersPreviewRef.value.fetch(),
}, },
}); });
}; };
const setInitialData = () => { async function hasCustomerRole() {
if (user.value.length) { const { data } = await axios(`Clients/${route.params.id}/hasCustomerRole`);
active.value = user.value[0].active; canChangePassword.value = data;
email.value = user.value[0].email; }
name.value = user.value[0].name;
}
};
const onSubmit = async () => {
isLoading.value = true;
const payload = {
active: active.value,
email: email.value,
name: name.value,
};
try {
await axios.patch(`Clients/${route.params.id}/updateUser`, payload);
notify('globals.dataSaved', 'positive');
if (usersPreviewRef.value) usersPreviewRef.value.fetch();
} catch (error) {
notify('errors.create', 'negative');
} finally {
isLoading.value = false;
}
};
</script> </script>
<template> <template>
<FetchData <FormModel
url="VnUsers/preview"
:url-update="`Clients/${route.params.id}/updateUser`"
:filter="filter" :filter="filter"
@on-fetch=" model="webAccess"
(data) => { :mapper="
user = data; ({ active, name, email }) => {
setInitialData(); return {
active,
name,
email,
};
} }
" "
@on-fetch="hasCustomerRole()"
auto-load auto-load
ref="usersPreviewRef" >
url="VnUsers/preview" <template #form="{ data, validate }">
/> <QCheckbox :label="t('Enable web access')" v-model="data.active" />
<FetchData <VnInput :label="t('User')" clearable v-model="data.name" />
:url="`Clients/${route.params.id}/hasCustomerRole`"
@on-fetch="(data) => (canChangePassword = data)"
auto-load
/>
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
<QBtnGroup push class="q-gutter-x-sm">
<QBtn
:disabled="isLoading"
:label="t('globals.reset')"
:loading="isLoading"
@click="setInitialData"
color="primary"
flat
icon="restart_alt"
type="reset"
/>
<QBtn
:disabled="isLoading"
:label="t('Change password')"
:loading="isLoading"
@click.stop="showChangePasswordDialog()"
color="primary"
flat
icon="edit"
v-if="canChangePassword"
/>
<QBtn
:disabled="isLoading || !dataChanges"
:label="t('globals.save')"
:loading="isLoading"
@click="onSubmit"
color="primary"
icon="save"
/>
</QBtnGroup>
</Teleport>
<div class="full-width flex justify-center">
<QCard class="card-width q-pa-lg">
<QCardSection>
<QForm>
<QCheckbox :label="t('Enable web access')" v-model="active" />
<div class="q-px-sm">
<VnInput :label="t('User')" clearable v-model="name" />
<VnInput <VnInput
:label="t('Recovery email')" :label="t('Recovery email')"
:rules="validate('client.email')" :rules="validate('client.email')"
clearable clearable
type="email" type="email"
v-model="email" v-model="data.email"
class="q-mt-sm" class="q-mt-sm"
> :info="t('This email is used for user to regain access their account')"
<template #append> />
<QIcon name="info" class="cursor-pointer">
<QTooltip>{{
t(
'This email is used for user to regain access their account'
)
}}</QTooltip>
</QIcon>
</template> </template>
</VnInput> <template #moreActions>
</div> <QBtn
</QForm> :label="t('Change password')"
</QCardSection> color="primary"
</QCard> icon="edit"
</div> :disable="!canChangePassword"
@click="showChangePasswordDialog()"
/>
</template>
</FormModel>
</template> </template>
<i18n> <i18n>

View File

@ -100,7 +100,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
color="primary" color="primary"
:to="{ :to="{
name: 'TicketList', name: 'TicketList',
query: { q: ticketFilter(entity) }, query: { table: ticketFilter(entity) },
}" }"
> >
<QTooltip>{{ t('invoiceOut.card.ticketList') }}</QTooltip> <QTooltip>{{ t('invoiceOut.card.ticketList') }}</QTooltip>

View File

@ -13,6 +13,7 @@ import { toCurrency, toDate } from 'src/filters/index';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { QBtn } from 'quasar'; import { QBtn } from 'quasar';
import { watchEffect } from 'vue'; import { watchEffect } from 'vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore(); const stateStore = useStateStore();
@ -214,6 +215,12 @@ watchEffect(selectedRows);
selection: 'multiple', selection: 'multiple',
}" }"
> >
<template #column-clientSocialName="{ row }">
<span class="link" @click.stop>
{{ row.clientSocialName }}
<CustomerDescriptorProxy :id="row.clientFk" />
</span>
</template>
<template #more-create-dialog="{ data }"> <template #more-create-dialog="{ data }">
<VnSelect <VnSelect
url="Tickets" url="Tickets"

View File

@ -6,6 +6,9 @@ import { toCurrency } from 'src/filters';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js'; import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
const { t } = useI18n(); const { t } = useI18n();
const tableRef = ref(); const tableRef = ref();
@ -168,6 +171,24 @@ const downloadCSV = async () => {
:is-editable="false" :is-editable="false"
:use-model="true" :use-model="true"
> >
<template #column-clientId="{ row }">
<span class="link" @click.stop>
{{ row.clientId }}
<CustomerDescriptorProxy :id="row.clientId" />
</span>
</template>
<template #column-ticketFk="{ row }">
<span class="link" @click.stop>
{{ row.ticketFk }}
<TicketDescriptorProxy :id="row.ticketFk" />
</span>
</template>
<template #column-workerName="{ row }">
<span class="link" @click.stop>
{{ row.workerName }}
<WorkerDescriptorProxy :id="row.comercialId" />
</span>
</template>
</VnTable> </VnTable>
</template> </template>

View File

@ -1,7 +1,5 @@
<script setup> <script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnFilterPanel from 'components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
@ -16,39 +14,9 @@ const props = defineProps({
}); });
const emit = defineEmits(['search']); const emit = defineEmits(['search']);
const workerList = ref([]);
const agencyList = ref([]);
const vehicleList = ref([]);
const warehouseList = ref([]);
</script> </script>
<template> <template>
<FetchData
url="Workers/search"
:filter="{ fields: ['id', 'nickname'] }"
sort-by="nickname ASC"
limit="30"
@on-fetch="(data) => (workerList = data)"
auto-load
/>
<FetchData
url="AgencyModes/isActive"
:filter="{ fields: ['id', 'name'] }"
sort-by="name ASC"
limit="30"
@on-fetch="(data) => (agencyList = data)"
auto-load
/>
<FetchData
url="Vehicles"
:filter="{ fields: ['id', 'numberPlate'] }"
sort-by="numberPlate ASC"
limit="30"
@on-fetch="(data) => (vehicleList = data)"
auto-load
/>
<FetchData url="Warehouses" @on-fetch="(data) => (warehouseList = data)" auto-load />
<VnFilterPanel <VnFilterPanel
:data-key="props.dataKey" :data-key="props.dataKey"
:search-button="true" :search-button="true"
@ -62,19 +30,17 @@ const warehouseList = ref([]);
</template> </template>
<template #body="{ params }"> <template #body="{ params }">
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection v-if="workerList"> <QItemSection>
<VnSelect <VnSelect
:label="t('Worker')" :label="t('Worker')"
v-model="params.workerFk" v-model="params.workerFk"
:options="workerList" url="Workers/search"
sort-by="nickname ASC"
option-value="id" option-value="id"
option-label="nickname" option-label="nickname"
dense dense
outlined outlined
rounded rounded
emit-value
map-options
use-input
:input-debounce="0" :input-debounce="0"
> >
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
@ -91,19 +57,17 @@ const warehouseList = ref([]);
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection v-if="agencyList"> <QItemSection>
<VnSelect <VnSelect
:label="t('Agency')" :label="t('Agency')"
v-model="params.agencyModeFk" v-model="params.agencyModeFk"
:options="agencyList" url="AgencyModes/isActive"
sort-by="name ASC"
option-value="id" option-value="id"
option-label="name" option-label="name"
dense dense
outlined outlined
rounded rounded
emit-value
map-options
use-input
:input-debounce="0" :input-debounce="0"
/> />
</QItemSection> </QItemSection>
@ -147,19 +111,17 @@ const warehouseList = ref([]);
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection v-if="vehicleList"> <QItemSection>
<VnSelect <VnSelect
:label="t('Vehicle')" :label="t('Vehicle')"
v-model="params.vehicleFk" v-model="params.vehicleFk"
:options="vehicleList" url="Vehicles"
sort-by="numberPlate ASC"
option-value="id" option-value="id"
option-label="numberPlate" option-label="numberPlate"
dense dense
outlined outlined
rounded rounded
emit-value
map-options
use-input
:input-debounce="0" :input-debounce="0"
/> />
</QItemSection> </QItemSection>
@ -170,19 +132,16 @@ const warehouseList = ref([]);
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection v-if="vehicleList"> <QItemSection>
<VnSelect <VnSelect
:label="t('Warehouse')" :label="t('Warehouse')"
v-model="params.warehouseFk" v-model="params.warehouseFk"
:options="warehouseList" url="Warehouses"
option-value="id" option-value="id"
option-label="name" option-label="name"
dense dense
outlined outlined
rounded rounded
emit-value
map-options
use-input
:input-debounce="0" :input-debounce="0"
/> />
</QItemSection> </QItemSection>

View File

@ -9,10 +9,9 @@ const { t } = useI18n();
data-key="RouteList" data-key="RouteList"
:label="t('Search route')" :label="t('Search route')"
:info="t('You can search by route reference')" :info="t('You can search by route reference')"
url="Routes/filter"
/> />
</template> </template>
<style scoped lang="scss"></style>
<i18n> <i18n>
es: es:
Search route: Buscar rutas Search route: Buscar rutas

View File

@ -11,6 +11,8 @@ import axios from 'axios';
import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue'; import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
import RouteListTicketsDialog from 'pages/Route/Card/RouteListTicketsDialog.vue'; import RouteListTicketsDialog from 'pages/Route/Card/RouteListTicketsDialog.vue';
import RouteSummary from 'pages/Route/Card/RouteSummary.vue'; import RouteSummary from 'pages/Route/Card/RouteSummary.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import RouteFilter from 'pages/Route/Card/RouteFilter.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
@ -271,13 +273,18 @@ const openTicketsDialog = (id) => {
</QCard> </QCard>
</QDialog> </QDialog>
<VnSubToolbar /> <VnSubToolbar />
<RightMenu>
<template #right-panel>
<RouteFilter data-key="RouteList" />
</template>
</RightMenu>
<VnTable <VnTable
class="route-list" class="route-list"
ref="tableRef" ref="tableRef"
data-key="RouteList" data-key="RouteList"
url="Routes/filter" url="Routes/filter"
:columns="columns" :columns="columns"
:right-search="true" :right-search="false"
:is-editable="true" :is-editable="true"
:filter="routeFilter" :filter="routeFilter"
redirect="route" redirect="route"

View File

@ -181,7 +181,7 @@ async function changeState(value) {
<span :class="{ link: ticket.refFk }"> <span :class="{ link: ticket.refFk }">
{{ dashIfEmpty(ticket.refFk) }} {{ dashIfEmpty(ticket.refFk) }}
<InvoiceOutDescriptorProxy <InvoiceOutDescriptorProxy
:id="ticket.id" :id="ticket.invoiceOut.id"
v-if="ticket.refFk" v-if="ticket.refFk"
/> />
</span> </span>

View File

@ -226,11 +226,6 @@ export default {
}, },
{ {
path: 'recoveries', path: 'recoveries',
name: 'RecoveriesCard',
redirect: { name: 'CustomerRecoveries' },
children: [
{
path: '',
name: 'CustomerRecoveries', name: 'CustomerRecoveries',
meta: { meta: {
title: 'recoveries', title: 'recoveries',
@ -239,19 +234,6 @@ export default {
component: () => component: () =>
import('src/pages/Customer/Card/CustomerRecoveries.vue'), import('src/pages/Customer/Card/CustomerRecoveries.vue'),
}, },
{
path: 'create',
name: 'CustomerRecoverieCreate',
meta: {
title: 'recoverie-create',
},
component: () =>
import(
'src/pages/Customer/components/CustomerRecoverieCreate.vue'
),
},
],
},
{ {
path: 'web-access', path: 'web-access',
name: 'CustomerWebAccess', name: 'CustomerWebAccess',