fix: refs #7310 clean warning #840

Merged
carlossa merged 4 commits from 7310-warningTravelTermographs into dev 2024-11-15 11:10:29 +00:00
20 changed files with 146 additions and 100 deletions
Showing only changes of commit 95291d4d4e - Show all commits

View File

@ -34,18 +34,26 @@ const search = ref(null);
const filteredItems = computed(() => { const filteredItems = computed(() => {
if (!search.value) return items.value; if (!search.value) return items.value;
const normalizedSearch = normalize(search.value);
return items.value.filter((item) => { return items.value.filter((item) => {
const locale = t(item.title).toLowerCase(); const locale = normalize(t(item.title));
return locale.includes(search.value.toLowerCase()); return locale.includes(normalizedSearch);
}); });
}); });
const filteredPinnedModules = computed(() => { const filteredPinnedModules = computed(() => {
if (!search.value) return pinnedModules.value; if (!search.value) return pinnedModules.value;
const normalizedSearch = search.value
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase();
const map = new Map(); const map = new Map();
for (const [key, pinnedModule] of pinnedModules.value) { for (const [key, pinnedModule] of pinnedModules.value) {
const locale = t(pinnedModule.title).toLowerCase(); const locale = t(pinnedModule.title)
if (locale.includes(search.value.toLowerCase())) map.set(key, pinnedModule); .normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase();
if (locale.includes(normalizedSearch)) map.set(key, pinnedModule);
} }
return map; return map;
}); });
@ -147,6 +155,13 @@ async function togglePinned(item, event) {
const handleItemExpansion = (itemName) => { const handleItemExpansion = (itemName) => {
expansionItemElements[itemName].scrollToLastElement(); expansionItemElements[itemName].scrollToLastElement();
}; };
function normalize(text) {
return text
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase();
}
</script> </script>
<template> <template>

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue'; import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'src/components/FetchData.vue'; import { useArrayData } from 'src/composables/useArrayData';
import { useRequired } from 'src/composables/useRequired'; import { useRequired } from 'src/composables/useRequired';
import dataByOrder from 'src/utils/dataByOrder'; import dataByOrder from 'src/utils/dataByOrder';
@ -90,6 +90,10 @@ const $props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
dataKey: {
type: String,
default: null,
},
}); });
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])]; const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
@ -98,14 +102,14 @@ const { optionLabel, optionValue, optionFilter, optionFilterValue, options, mode
const myOptions = ref([]); const myOptions = ref([]);
const myOptionsOriginal = ref([]); const myOptionsOriginal = ref([]);
const vnSelectRef = ref(); const vnSelectRef = ref();
const dataRef = ref();
const lastVal = ref(); const lastVal = ref();
const noOneText = t('globals.noOne'); const noOneText = t('globals.noOne');
const noOneOpt = ref({ const noOneOpt = ref({
[optionValue.value]: false, [optionValue.value]: false,
[optionLabel.value]: noOneText, [optionLabel.value]: noOneText,
}); });
const isLoading = ref(false);
const useURL = computed(() => $props.url);
const value = computed({ const value = computed({
get() { get() {
return $props.modelValue; return $props.modelValue;
@ -129,11 +133,18 @@ watch(modelValue, async (newValue) => {
onMounted(() => { onMounted(() => {
setOptions(options.value); setOptions(options.value);
if ($props.url && $props.modelValue && !findKeyInOptions()) if (useURL.value && $props.modelValue && !findKeyInOptions())
fetchFilter($props.modelValue); fetchFilter($props.modelValue);
if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300); if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300);
}); });
defineExpose({ opts: myOptions });
const arrayDataKey =
$props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label);
const arrayData = useArrayData(arrayDataKey, { url: $props.url, searchUrl: false });
function findKeyInOptions() { function findKeyInOptions() {
if (!$props.options) return; if (!$props.options) return;
return filter($props.modelValue, $props.options)?.length; return filter($props.modelValue, $props.options)?.length;
@ -168,7 +179,7 @@ function filter(val, options) {
} }
async function fetchFilter(val) { async function fetchFilter(val) {
if (!$props.url || !dataRef.value) return; if (!$props.url) return;
const { fields, include, sortBy, limit } = $props; const { fields, include, sortBy, limit } = $props;
const key = const key =
@ -190,8 +201,8 @@ async function fetchFilter(val) {
const fetchOptions = { where, include, limit }; const fetchOptions = { where, include, limit };
if (fields) fetchOptions.fields = fields; if (fields) fetchOptions.fields = fields;
if (sortBy) fetchOptions.order = sortBy; if (sortBy) fetchOptions.order = sortBy;
arrayData.reset(['skip', 'filter.skip', 'page']);
return dataRef.value.fetch(fetchOptions); return (await arrayData.applyFilter({ filter: fetchOptions }))?.data;
} }
async function filterHandler(val, update) { async function filterHandler(val, update) {
@ -231,20 +242,23 @@ function nullishToTrue(value) {
const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val); const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val);
defineExpose({ opts: myOptions }); async function onScroll({ to, direction, from, index }) {
const lastIndex = myOptions.value.length - 1;
if (from === 0 && index === 0) return;
if (!useURL.value && !$props.fetchRef) return;
if (direction === 'decrease') return;
if (to === lastIndex && arrayData.store.hasMoreData && !isLoading.value) {
isLoading.value = true;
await arrayData.loadMore();
setOptions(arrayData.store.data);
vnSelectRef.value.scrollTo(lastIndex);
isLoading.value = false;
}
}
</script> </script>
<template> <template>
<FetchData
ref="dataRef"
:url="$props.url"
@on-fetch="(data) => setOptions(data)"
:where="where || { [optionValue]: value }"
:limit="limit"
:sort-by="sortBy"
:fields="fields"
:params="params"
/>
<QSelect <QSelect
v-model="value" v-model="value"
:options="myOptions" :options="myOptions"
@ -263,6 +277,9 @@ defineExpose({ opts: myOptions });
:rules="mixinRules" :rules="mixinRules"
virtual-scroll-slice-size="options.length" virtual-scroll-slice-size="options.length"
hide-bottom-space hide-bottom-space
:input-debounce="useURL ? '300' : '0'"
:loading="isLoading"
@virtual-scroll="onScroll"
> >
<template v-if="isClearable" #append> <template v-if="isClearable" #append>
<QIcon <QIcon

View File

@ -17,19 +17,12 @@ const config = reactive({
const type = Object.keys(config).find((key) => key in useAttrs()) || 'sip'; const type = Object.keys(config).find((key) => key in useAttrs()) || 'sip';
onBeforeMount(async () => { onBeforeMount(async () => {
let url;
let { channel } = config[type]; let { channel } = config[type];
if (type === 'say-simple') { if (type === 'say-simple') {
url = (await axios.get('SaySimpleConfigs/findOne')).data.url; const { url, defaultChannel } = (await axios.get('SaySimpleConfigs/findOne'))
if (!channel) .data;
channel = ( if (!channel) channel = defaultChannel;
await axios.get('SaySimpleCountries/findOne', {
params: {
filter: { fields: ['channel'], where: { countryFk: 0 } },
},
})
).data?.channel;
config[ config[
type type

View File

@ -65,13 +65,9 @@ onBeforeRouteLeave((to, from, next) => {
auto-load auto-load
@on-fetch="(data) => (observationTypes = data)" @on-fetch="(data) => (observationTypes = data)"
/> />
<QCard class="q-pa-xs q-mb-xl full-width" v-if="$props.addNote"> <QCard class="q-pa-xs q-mb-lg full-width" v-if="$props.addNote">
<QCardSection horizontal> <QCardSection horizontal>
<VnAvatar :worker-id="currentUser.id" size="md" /> {{ t('New note') }}
<div class="full-width row justify-between q-pa-xs">
<VnUserLink :name="t('New note')" :worker-id="currentUser.id" />
{{ t('globals.now') }}
</div>
</QCardSection> </QCardSection>
<QCardSection class="q-px-xs q-my-none q-py-none"> <QCardSection class="q-px-xs q-my-none q-py-none">
<VnRow class="full-width"> <VnRow class="full-width">
@ -144,7 +140,7 @@ onBeforeRouteLeave((to, from, next) => {
<div class="full-width row justify-between q-pa-xs"> <div class="full-width row justify-between q-pa-xs">
<div> <div>
<VnUserLink <VnUserLink
:name="`${note.worker.user.nickname}`" :name="`${note.worker.user.name}`"
:worker-id="note.worker.id" :worker-id="note.worker.id"
/> />
<QBadge <QBadge

View File

@ -247,6 +247,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
} }
function updateStateParams() { function updateStateParams() {
if (!route?.path) return;
const newUrl = { path: route.path, query: { ...(route.query ?? {}) } }; const newUrl = { path: route.path, query: { ...(route.query ?? {}) } };
if (store?.searchUrl) if (store?.searchUrl)
newUrl.query[store.searchUrl] = JSON.stringify(store.currentFilter); newUrl.query[store.searchUrl] = JSON.stringify(store.currentFilter);

View File

@ -0,0 +1,8 @@
import { openURL } from 'quasar';
const defaultWindowFeatures = {
noopener: true,
noreferrer: true,
};
export default function (url, windowFeatures = defaultWindowFeatures, fn = undefined) {
openURL(url, fn, windowFeatures);
}

View File

@ -174,23 +174,6 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
> >
<QTooltip>{{ t('Customer ticket list') }}</QTooltip> <QTooltip>{{ t('Customer ticket list') }}</QTooltip>
</QBtn> </QBtn>
<QBtn
:to="{
name: 'TicketList',
query: {
table: JSON.stringify({
clientFk: entity.id,
}),
createForm: JSON.stringify({ clientId: entity.id }),
},
}"
size="md"
color="primary"
target="_blank"
icon="vn:ticketAdd"
>
<QTooltip>{{ t('New ticket') }}</QTooltip>
</QBtn>
<QBtn <QBtn
:to="{ :to="{
name: 'InvoiceOutList', name: 'InvoiceOutList',
@ -202,23 +185,6 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
> >
<QTooltip>{{ t('Customer invoice out list') }}</QTooltip> <QTooltip>{{ t('Customer invoice out list') }}</QTooltip>
</QBtn> </QBtn>
<QBtn
:to="{
name: 'OrderList',
query: {
table: JSON.stringify({
clientFk: entity.id,
}),
createForm: JSON.stringify({ clientFk: entity.id }),
},
}"
size="md"
target="_blank"
icon="vn:basketadd"
color="primary"
>
<QTooltip>{{ t('New order') }}</QTooltip>
</QBtn>
<QBtn <QBtn
:to="{ :to="{
name: 'AccountSummary', name: 'AccountSummary',

View File

@ -6,8 +6,8 @@ import axios from 'axios';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import useNotify from 'src/composables/useNotify'; import useNotify from 'src/composables/useNotify';
import VnSmsDialog from 'src/components/common/VnSmsDialog.vue'; import VnSmsDialog from 'src/components/common/VnSmsDialog.vue';
import useOpenURL from 'src/composables/useOpenURL';
const $props = defineProps({ const $props = defineProps({
customer: { customer: {
@ -15,7 +15,6 @@ const $props = defineProps({
required: true, required: true,
}, },
}); });
const { notify } = useNotify(); const { notify } = useNotify();
const { t } = useI18n(); const { t } = useI18n();
const quasar = useQuasar(); const quasar = useQuasar();
@ -40,9 +39,42 @@ const sendSms = async (payload) => {
notify(error.message, 'positive'); notify(error.message, 'positive');
} }
}; };
const openCreateForm = (type) => {
const query = {
table: {
clientFk: $props.customer.id,
},
createForm: {
addressId: $props.customer.defaultAddressFk,
},
};
const clientFk = {
ticket: 'clientId',
order: 'clientFk',
};
const key = clientFk[type];
if (!key) return;
query.createForm[key] = $props.customer.id;
const params = Object.entries(query)
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
.join('&');
useOpenURL(`/#/${type}/list?${params}`);
};
</script> </script>
<template> <template>
<QItem v-ripple clickable @click="openCreateForm('ticket')">
<QItemSection>
{{ t('globals.pageTitles.createTicket') }}
</QItemSection>
</QItem>
<QItem v-ripple clickable @click="openCreateForm('order')">
<QItemSection>
{{ t('globals.pageTitles.createOrder') }}
</QItemSection>
</QItem>
<QItem v-ripple clickable> <QItem v-ripple clickable>
<QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection> <QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection>
</QItem> </QItem>

View File

@ -2,10 +2,9 @@
import { computed, onBeforeMount, ref, watch, nextTick } from 'vue'; import { computed, onBeforeMount, ref, watch, nextTick } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnRow from 'components/ui/VnRow.vue';
import axios from 'axios'; import axios from 'axios';
import useNotify from 'src/composables/useNotify'; import useNotify from 'src/composables/useNotify';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';

View File

@ -53,7 +53,7 @@ defineProps({
<QItemSection> <QItemSection>
<VnSelect <VnSelect
url="Workers/activeWithInheritedRole" url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }" :where="{ role: 'salesPerson' }"
auto-load auto-load
:label="t('Salesperson')" :label="t('Salesperson')"
v-model="params.salesPersonFk" v-model="params.salesPersonFk"
@ -67,7 +67,6 @@ defineProps({
dense dense
outlined outlined
rounded rounded
:input-debounce="0"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>

View File

@ -194,14 +194,14 @@ const getItemPackagingType = (ticketSales) => {
redirect="ticket" redirect="ticket"
> >
<template #column-nickname="{ row }"> <template #column-nickname="{ row }">
<span class="link"> <span class="link" @click.stop>
{{ row.nickname }} {{ row.nickname }}
<CustomerDescriptorProxy :id="row.clientFk" /> <CustomerDescriptorProxy :id="row.clientFk" />
</span> </span>
</template> </template>
<template #column-routeFk="{ row }"> <template #column-routeFk="{ row }">
<span class="link"> <span class="link" @click.stop>
{{ row.routeFk }} {{ row.routeFk }}
<RouteDescriptorProxy :id="row.routeFk" /> <RouteDescriptorProxy :id="row.routeFk" />
</span> </span>
@ -218,7 +218,7 @@ const getItemPackagingType = (ticketSales) => {
<span v-else> {{ toCurrency(row.totalWithVat) }}</span> <span v-else> {{ toCurrency(row.totalWithVat) }}</span>
</template> </template>
<template #column-state="{ row }"> <template #column-state="{ row }">
<span v-if="row.invoiceOut"> <span v-if="row.invoiceOut" @click.stop>
<span :class="{ link: row.invoiceOut.ref }"> <span :class="{ link: row.invoiceOut.ref }">
{{ row.invoiceOut.ref }} {{ row.invoiceOut.ref }}
<InvoiceOutDescriptorProxy :id="row.invoiceOut.id" /> <InvoiceOutDescriptorProxy :id="row.invoiceOut.id" />

View File

@ -99,7 +99,7 @@ const travelDialogRef = ref(false);
const tableRef = ref(); const tableRef = ref();
const travel = ref(null); const travel = ref(null);
const userParams = ref({ const userParams = ref({
dated: Date.vnNew(), dated: Date.vnNew().toJSON(),
}); });
const filter = ref({ const filter = ref({
@ -219,6 +219,7 @@ function round(value) {
data-key="StockBoughts" data-key="StockBoughts"
url="StockBoughts/getStockBought" url="StockBoughts/getStockBought"
save-url="StockBoughts/crud" save-url="StockBoughts/crud"
search-url="StockBoughts"
order="reserve DESC" order="reserve DESC"
:right-search="false" :right-search="false"
:is-editable="true" :is-editable="true"

View File

@ -18,7 +18,7 @@ const $props = defineProps({
required: true, required: true,
}, },
}); });
const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&date=${$props.dated}`; const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&dated=${$props.dated}`;
const columns = [ const columns = [
{ {
align: 'left', align: 'left',

View File

@ -27,7 +27,7 @@ onMounted(async () => {
<VnFilterPanel <VnFilterPanel
:data-key="props.dataKey" :data-key="props.dataKey"
:search-button="true" :search-button="true"
search-url="table" search-url="StockBoughts"
@set-user-params="setUserParams" @set-user-params="setUserParams"
> >
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
@ -36,12 +36,19 @@ onMounted(async () => {
<span>{{ formatFn(tag.value) }}</span> <span>{{ formatFn(tag.value) }}</span>
</div> </div>
</template> </template>
<template #body="{ params }"> <template #body="{ params, searchFn }">
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate
id="date" id="date"
v-model="params.dated" v-model="params.dated"
@update:model-value="
(value) => {
params.dated = value;
setUserParams(params);
searchFn();
}
"
:label="t('Date')" :label="t('Date')"
is-outlined is-outlined
/> />

View File

@ -116,7 +116,7 @@ function getApiUrl() {
return new URL(window.location).origin; return new URL(window.location).origin;
} }
function getCmrUrl(value) { function getCmrUrl(value) {
return `${getApiUrl()}/api/Routes/${value}/cmr?access_token=${token}`; return `${getApiUrl()}/api/Cmrs/${value}/print?access_token=${token}`;
} }
function downloadPdfs() { function downloadPdfs() {
if (!selectedRows.value.length) { if (!selectedRows.value.length) {
@ -129,7 +129,7 @@ function downloadPdfs() {
let cmrs = []; let cmrs = [];
for (let value of selectedRows.value) cmrs.push(value.cmrFk); for (let value of selectedRows.value) cmrs.push(value.cmrFk);
// prettier-ignore // prettier-ignore
return window.open(`${getApiUrl()}/api/Routes/downloadCmrsZip?ids=${cmrs.join(',')}&access_token=${token}`); return window.open(`${getApiUrl()}/api/Cmrs/downloadZip?ids=${cmrs.join(',')}&access_token=${token}`);
} }
</script> </script>
<template> <template>
@ -149,7 +149,7 @@ function downloadPdfs() {
<VnTable <VnTable
ref="tableRef" ref="tableRef"
data-key="CmrList" data-key="CmrList"
url="Routes/cmrs" url="Cmrs/filter"
:columns="columns" :columns="columns"
:right-search="true" :right-search="true"
default-mode="table" default-mode="table"

View File

@ -268,6 +268,7 @@ onMounted(() => (stateStore.rightDrawer = false));
:label="t('basicData.price')" :label="t('basicData.price')"
type="number" type="number"
min="0" min="0"
step="any"
/> />
</template> </template>
</VnTable> </VnTable>

View File

@ -45,6 +45,13 @@ const userParams = {
from: null, from: null,
to: null, to: null,
}; };
onMounted(() => {
initializeFromQuery();
stateStore.rightDrawer = true;
if (!route.query.createForm) return;
onClientSelected(JSON.parse(route.query.createForm));
});
// Método para inicializar las variables desde la query string // Método para inicializar las variables desde la query string
const initializeFromQuery = () => { const initializeFromQuery = () => {
const query = route.query.table ? JSON.parse(route.query.table) : {}; const query = route.query.table ? JSON.parse(route.query.table) : {};
@ -301,11 +308,6 @@ const getDateColor = (date) => {
if (comparation < 0) return 'bg-success'; if (comparation < 0) return 'bg-success';
}; };
onMounted(() => {
initializeFromQuery();
stateStore.rightDrawer = true;
});
async function makeInvoice(ticket) { async function makeInvoice(ticket) {
const ticketsIds = ticket.map((item) => item.id); const ticketsIds = ticket.map((item) => item.id);
const { data } = await axios.post(`Tickets/invoiceTicketsAndPdf`, { ticketsIds }); const { data } = await axios.post(`Tickets/invoiceTicketsAndPdf`, { ticketsIds });

View File

@ -105,11 +105,14 @@ watch(
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
<QItemSection v-if="opt.code"> <QItemSection v-if="opt.code">
<QItemLabel>{{ opt.code }}</QItemLabel> <QItemLabel>
<QItemLabel caption {{ `${opt.code}, ${opt.town?.name}` }}
>{{ opt.town?.province?.name }}, </QItemLabel>
{{ opt.town?.province?.country?.name }}</QItemLabel <QItemLabel caption>
> {{
`${opt.town?.province?.name}, ${opt.town?.province?.country?.name}`
}}
</QItemLabel>
</QItemSection> </QItemSection>
</QItem> </QItem>
</template> </template>

View File

@ -22,7 +22,12 @@ const agencies = ref([]);
</script> </script>
<template> <template>
<FetchData url="agencies" @on-fetch="(data) => (agencies = data)" auto-load /> <FetchData
url="AgencyModes"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (agencies = data)"
auto-load
/>
<VnFilterPanel <VnFilterPanel
:data-key="props.dataKey" :data-key="props.dataKey"
:search-button="true" :search-button="true"

View File

@ -73,6 +73,7 @@ const columns = computed(() => [
inWhere: true, inWhere: true,
attrs: { attrs: {
url: 'AgencyModes', url: 'AgencyModes',
fields: ['id', 'name'],
}, },
}, },
columnField: { columnField: {