forked from verdnatura/salix-front
Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 7283-itemSectionsMigration
This commit is contained in:
commit
7a2170e7c3
|
@ -0,0 +1,33 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function getCurrentBranchName(p = process.cwd()) {
|
||||
if (!fs.existsSync(p)) return false;
|
||||
|
||||
const gitHeadPath = path.join(p, '.git', 'HEAD');
|
||||
|
||||
if (!fs.existsSync(gitHeadPath))
|
||||
return getCurrentBranchName(path.resolve(p, '..'));
|
||||
|
||||
const headContent = fs.readFileSync(gitHeadPath, 'utf-8');
|
||||
return headContent.trim().split('/')[2];
|
||||
}
|
||||
|
||||
const branchName = getCurrentBranchName();
|
||||
|
||||
if (branchName) {
|
||||
const msgPath = `.git/COMMIT_EDITMSG`;
|
||||
const msg = fs.readFileSync(msgPath, 'utf-8');
|
||||
const reference = branchName.match(/^\d+/);
|
||||
|
||||
const referenceTag = `refs #${reference}`;
|
||||
if (!msg.includes(referenceTag) && reference) {
|
||||
const splitedMsg = msg.split(':');
|
||||
|
||||
if (splitedMsg.length > 1) {
|
||||
const finalMsg = splitedMsg[0] + ': ' + referenceTag + splitedMsg.slice(1).join(':');
|
||||
fs.writeFileSync(msgPath, finalMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
echo "Running husky commit-msg hook"
|
||||
npx --no-install commitlint --edit
|
||||
echo "Adding reference tag to commit message"
|
||||
node .husky/addReferenceTag.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
module.exports = { extends: ['@commitlint/config-conventional'] };
|
|
@ -13,7 +13,10 @@
|
|||
"test:e2e:ci": "cd ../salix && gulp docker && cd ../salix-front && cypress run",
|
||||
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
||||
"test:unit": "vitest",
|
||||
"test:unit:ci": "vitest run"
|
||||
"test:unit:ci": "vitest run",
|
||||
"commitlint": "commitlint --edit",
|
||||
"prepare": "npx husky install",
|
||||
"addReferenceTag": "node .husky/addReferenceTag.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@quasar/cli": "^2.3.0",
|
||||
|
@ -29,6 +32,8 @@
|
|||
"vue-router": "^4.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^19.2.1",
|
||||
"@commitlint/config-conventional": "^19.1.0",
|
||||
"@intlify/unplugin-vue-i18n": "^0.8.1",
|
||||
"@pinia/testing": "^0.1.2",
|
||||
"@quasar/app-vite": "^1.7.3",
|
||||
|
@ -41,6 +46,7 @@
|
|||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-cypress": "^2.13.3",
|
||||
"eslint-plugin-vue": "^9.14.1",
|
||||
"husky": "^8.0.0",
|
||||
"postcss": "^8.4.23",
|
||||
"prettier": "^2.8.8",
|
||||
"vitest": "^0.31.1"
|
||||
|
|
15114
pnpm-lock.yaml
15114
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -100,7 +100,6 @@ const isResetting = ref(false);
|
|||
const hasChanges = ref(!$props.observeFormChanges);
|
||||
const originalData = ref({});
|
||||
const formData = computed(() => state.get(modelValue));
|
||||
const formUrl = computed(() => $props.url);
|
||||
const defaultButtons = computed(() => ({
|
||||
save: {
|
||||
color: 'primary',
|
||||
|
@ -148,11 +147,14 @@ if (!$props.url)
|
|||
(val) => updateAndEmit('onFetch', val)
|
||||
);
|
||||
|
||||
watch(formUrl, async () => {
|
||||
originalData.value = null;
|
||||
reset();
|
||||
await fetch();
|
||||
});
|
||||
watch(
|
||||
() => [$props.url, $props.filter],
|
||||
async () => {
|
||||
originalData.value = null;
|
||||
reset();
|
||||
await fetch();
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeRouteLeave((to, from, next) => {
|
||||
if (hasChanges.value && $props.observeFormChanges)
|
||||
|
|
|
@ -46,7 +46,7 @@ const stateStore = useStateStore();
|
|||
</div>
|
||||
</Teleport>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||
<QScrollArea class="fit text-grey-8">
|
||||
<QScrollArea class="fit">
|
||||
<div id="right-panel"></div>
|
||||
<slot v-if="!hasContent" name="right-panel" />
|
||||
</QScrollArea>
|
||||
|
|
|
@ -17,13 +17,7 @@ const props = defineProps({
|
|||
descriptor: { type: Object, required: true },
|
||||
filterPanel: { type: Object, default: undefined },
|
||||
searchDataKey: { type: String, default: undefined },
|
||||
searchUrl: { type: String, default: undefined },
|
||||
searchbarLabel: { type: String, default: '' },
|
||||
searchbarInfo: { type: String, default: '' },
|
||||
searchCustomRouteRedirect: { type: String, default: undefined },
|
||||
searchRedirect: { type: Boolean, default: true },
|
||||
searchMakeFetch: { type: Boolean, default: true },
|
||||
searchUrlQuery: { type: String, default: undefined },
|
||||
searchbarProps: { type: Object, default: undefined },
|
||||
});
|
||||
|
||||
const stateStore = useStateStore();
|
||||
|
@ -66,15 +60,7 @@ if (props.baseUrl) {
|
|||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<slot name="searchbar" v-if="props.searchDataKey">
|
||||
<VnSearchbar
|
||||
:data-key="props.searchDataKey"
|
||||
:url="props.searchUrl"
|
||||
:label="props.searchbarLabel"
|
||||
:info="props.searchbarInfo"
|
||||
:search-url="props.searchUrlQuery"
|
||||
:custom-route-redirect-name="searchCustomRouteRedirect"
|
||||
:redirect="searchRedirect"
|
||||
/>
|
||||
<VnSearchbar :data-key="props.searchDataKey" v-bind="props.searchbarProps" />
|
||||
</slot>
|
||||
<slot v-else name="searchbar" />
|
||||
<RightMenu>
|
||||
|
|
|
@ -73,8 +73,7 @@ const containerClasses = computed(() => {
|
|||
.q-calendar-month__head--workweek,
|
||||
.q-calendar-month__head--weekday,
|
||||
// .q-calendar-month__workweek.q-past-day,
|
||||
.q-calendar-month__week :nth-child(6),
|
||||
:nth-child(7) {
|
||||
.q-calendar-month__week :nth-child(n+6):nth-child(-n+7) {
|
||||
color: var(--vn-label-color);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { onBeforeMount } from 'vue';
|
||||
import { watch, computed } from 'vue';
|
||||
import { date } from 'quasar';
|
||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
import VnAvatar from '../ui/VnAvatar.vue';
|
||||
|
@ -10,31 +10,32 @@ const $props = defineProps({
|
|||
where: { type: Object, default: () => {} },
|
||||
});
|
||||
|
||||
const filter = {
|
||||
fields: ['smsFk'],
|
||||
include: {
|
||||
relation: 'sms',
|
||||
scope: {
|
||||
fields: [
|
||||
'senderFk',
|
||||
'sender',
|
||||
'destination',
|
||||
'message',
|
||||
'statusCode',
|
||||
'status',
|
||||
'created',
|
||||
],
|
||||
include: {
|
||||
relation: 'sender',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
const filter = computed(() => {
|
||||
return {
|
||||
fields: ['smsFk'],
|
||||
include: {
|
||||
relation: 'sms',
|
||||
scope: {
|
||||
fields: [
|
||||
'senderFk',
|
||||
'sender',
|
||||
'destination',
|
||||
'message',
|
||||
'statusCode',
|
||||
'status',
|
||||
'created',
|
||||
],
|
||||
include: {
|
||||
relation: 'sender',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
onBeforeMount(() => (filter.where = $props.where));
|
||||
...{ where: $props.where },
|
||||
};
|
||||
});
|
||||
|
||||
function formatNumber(number) {
|
||||
if (number.length <= 10) return number;
|
||||
|
|
|
@ -3,12 +3,14 @@ import { useRole } from './useRole';
|
|||
import { useAcl } from './useAcl';
|
||||
import { useUserConfig } from './useUserConfig';
|
||||
import axios from 'axios';
|
||||
import { useRouter } from 'vue-router';
|
||||
import useNotify from './useNotify';
|
||||
import { useTokenConfig } from './useTokenConfig';
|
||||
const TOKEN_MULTIMEDIA = 'tokenMultimedia';
|
||||
const TOKEN = 'token';
|
||||
|
||||
export function useSession() {
|
||||
const router = useRouter();
|
||||
const { notify } = useNotify();
|
||||
let isCheckingToken = false;
|
||||
let intervalId = null;
|
||||
|
@ -102,6 +104,31 @@ export function useSession() {
|
|||
startInterval();
|
||||
}
|
||||
|
||||
async function setLogin(data) {
|
||||
const {
|
||||
data: { multimediaToken },
|
||||
} = await axios.get('VnUsers/ShareToken', {
|
||||
headers: { Authorization: data.token },
|
||||
});
|
||||
|
||||
if (!multimediaToken) return;
|
||||
|
||||
await login({
|
||||
...data,
|
||||
created: Date.now(),
|
||||
tokenMultimedia: multimediaToken.id,
|
||||
});
|
||||
|
||||
notify('login.loginSuccess', 'positive');
|
||||
|
||||
const currentRoute = router.currentRoute.value;
|
||||
if (currentRoute.query?.redirect) {
|
||||
router.push(currentRoute.query.redirect);
|
||||
} else {
|
||||
router.push({ name: 'Dashboard' });
|
||||
}
|
||||
}
|
||||
|
||||
function isLoggedIn() {
|
||||
const localToken = localStorage.getItem(TOKEN);
|
||||
const sessionToken = sessionStorage.getItem(TOKEN);
|
||||
|
@ -163,6 +190,7 @@ export function useSession() {
|
|||
setToken,
|
||||
destroy,
|
||||
login,
|
||||
setLogin,
|
||||
isLoggedIn,
|
||||
checkValidity,
|
||||
setSession,
|
||||
|
|
|
@ -90,6 +90,9 @@ globals:
|
|||
salesPerson: SalesPerson
|
||||
send: Send
|
||||
code: Code
|
||||
since: Since
|
||||
from: From
|
||||
to: To
|
||||
pageTitles:
|
||||
logIn: Login
|
||||
summary: Summary
|
||||
|
|
|
@ -90,6 +90,9 @@ globals:
|
|||
salesPerson: Comercial
|
||||
send: Enviar
|
||||
code: Código
|
||||
since: Desde
|
||||
from: Desde
|
||||
to: Hasta
|
||||
pageTitles:
|
||||
logIn: Inicio de sesión
|
||||
summary: Resumen
|
||||
|
@ -697,8 +700,6 @@ invoiceOut:
|
|||
percentageText: '{getPercentage}% {getAddressNumber} de {getNAddresses}'
|
||||
pdfsNumberText: '{nPdfs} de {totalPdfs} PDFs'
|
||||
negativeBases:
|
||||
from: Desde
|
||||
to: Hasta
|
||||
company: Empresa
|
||||
country: País
|
||||
clientId: Id cliente
|
||||
|
@ -1240,8 +1241,6 @@ components:
|
|||
# LatestBuysFilter
|
||||
salesPersonFk: Comprador
|
||||
supplierFk: Proveedor
|
||||
from: Desde
|
||||
to: Hasta
|
||||
active: Activo
|
||||
visible: Visible
|
||||
floramondo: Floramondo
|
||||
|
|
|
@ -25,9 +25,11 @@ const searchBarDataKeys = {
|
|||
base-url="MailAliases"
|
||||
:descriptor="AliasDescriptor"
|
||||
:search-data-key="searchBarDataKeys[routeName]"
|
||||
:search-custom-route-redirect="customRouteRedirectName"
|
||||
:search-redirect="!!customRouteRedirectName"
|
||||
:searchbar-label="t('mailAlias.search')"
|
||||
:searchbar-info="t('mailAlias.searchInfo')"
|
||||
:searchbar-props="{
|
||||
redirect: !!customRouteRedirectName,
|
||||
customRouteRedirectName,
|
||||
info: t('mailAlias.searchInfo'),
|
||||
label: t('mailAlias.search'),
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -26,9 +26,11 @@ const searchBarDataKeys = {
|
|||
data-key="Account"
|
||||
:descriptor="AccountDescriptor"
|
||||
:search-data-key="searchBarDataKeys[routeName]"
|
||||
:search-custom-route-redirect="customRouteRedirectName"
|
||||
:search-redirect="!!customRouteRedirectName"
|
||||
:searchbar-label="t('account.search')"
|
||||
:searchbar-info="t('account.searchInfo')"
|
||||
:searchbar-props="{
|
||||
redirect: !!customRouteRedirectName,
|
||||
customRouteRedirectName,
|
||||
label: t('account.search'),
|
||||
info: t('account.searchInfo'),
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -85,7 +85,7 @@ const fetchMailAliases = async () => {
|
|||
paginateRef.value.fetch();
|
||||
};
|
||||
|
||||
const getAccountData = async () => {
|
||||
const getAccountData = async (reload = true) => {
|
||||
loading.value = true;
|
||||
hasAccount.value = await fetchAccountExistence();
|
||||
if (!hasAccount.value) {
|
||||
|
@ -93,7 +93,7 @@ const getAccountData = async () => {
|
|||
store.data = [];
|
||||
return;
|
||||
}
|
||||
await fetchMailAliases();
|
||||
reload && (await fetchMailAliases());
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
|
@ -102,13 +102,11 @@ const openCreateMailAliasForm = () => createMailAliasDialogRef.value.show();
|
|||
watch(
|
||||
() => route.params.id,
|
||||
() => {
|
||||
store.url = urlPath;
|
||||
store.filter = filter.value;
|
||||
getAccountData();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => await getAccountData());
|
||||
onMounted(async () => await getAccountData(false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -23,9 +23,11 @@ const searchBarDataKeys = {
|
|||
data-key="Role"
|
||||
:descriptor="RoleDescriptor"
|
||||
:search-data-key="searchBarDataKeys[routeName]"
|
||||
:search-custom-route-redirect="customRouteRedirectName"
|
||||
:search-redirect="!!customRouteRedirectName"
|
||||
:searchbar-label="t('role.searchRoles')"
|
||||
:searchbar-info="t('role.searchInfo')"
|
||||
:searchbar-props="{
|
||||
redirect: !!customRouteRedirectName,
|
||||
customRouteRedirectName,
|
||||
label: t('role.searchRoles'),
|
||||
info: t('role.searchInfo'),
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -11,9 +11,11 @@ import filter from './ClaimFilter.js';
|
|||
:descriptor="ClaimDescriptor"
|
||||
:filter-panel="ClaimFilter"
|
||||
search-data-key="ClaimList"
|
||||
search-url="Claims/filter"
|
||||
searchbar-label="Search claim"
|
||||
searchbar-info="You can search by claim id or customer name"
|
||||
:filter="filter"
|
||||
:searchbar-props="{
|
||||
url: 'Claims/filter',
|
||||
label: 'Search claim',
|
||||
info: 'You can search by claim id or customer name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,8 +10,10 @@ import CustomerFilter from '../CustomerFilter.vue';
|
|||
:descriptor="CustomerDescriptor"
|
||||
:filter-panel="CustomerFilter"
|
||||
search-data-key="CustomerList"
|
||||
search-url="Clients/extendedListFilter"
|
||||
searchbar-label="Search customer"
|
||||
searchbar-info="You can search by customer id or name"
|
||||
:searchbar-props="{
|
||||
url: 'Clients/extendedListFilter',
|
||||
label: 'Search customer',
|
||||
info: 'You can search by customer id or name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -1,262 +1,6 @@
|
|||
<script setup>
|
||||
import { onBeforeMount, ref } from '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);
|
||||
}
|
||||
};
|
||||
import VnLog from 'src/components/common/VnLog.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
: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>
|
||||
<VnLog model="Client" />
|
||||
</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>
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import VnNotes from 'src/components/ui/VnNotes.vue';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const noteFilter = {
|
||||
order: 'created DESC',
|
||||
where: {
|
||||
clientFk: `${route.params.id}`,
|
||||
},
|
||||
};
|
||||
const noteFilter = computed(() => {
|
||||
return {
|
||||
order: 'created DESC',
|
||||
where: {
|
||||
clientFk: `${route.params.id}`,
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,146 +1,107 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { useRoute } from 'vue-router';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnTable from 'components/VnTable/VnTable.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const rows = ref([]);
|
||||
|
||||
const filter = {
|
||||
where: { clientFk: route.params.id },
|
||||
order: ['started DESC'],
|
||||
limit: 20,
|
||||
const tableRef = ref();
|
||||
const filter = computed(() => {
|
||||
return {
|
||||
where: { clientFk: route.params.id },
|
||||
};
|
||||
});
|
||||
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(() => [
|
||||
{
|
||||
align: 'left',
|
||||
field: 'started',
|
||||
label: t('Since'),
|
||||
name: 'since',
|
||||
format: (value) => toDate(value),
|
||||
label: t('globals.since'),
|
||||
name: 'started',
|
||||
format: ({ started }) => toDate(started),
|
||||
create: true,
|
||||
...componentColumn('date'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'finished',
|
||||
label: t('To'),
|
||||
name: 'to',
|
||||
format: (value) => toDate(value),
|
||||
name: 'finished',
|
||||
label: t('globals.to'),
|
||||
format: ({ finished }) => toDate(finished),
|
||||
create: true,
|
||||
...componentColumn('date'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'amount',
|
||||
label: t('Amount'),
|
||||
name: 'amount',
|
||||
format: (value) => toCurrency(value),
|
||||
label: t('globals.amount'),
|
||||
format: ({ amount }) => toCurrency(amount),
|
||||
create: true,
|
||||
...componentColumn('number'),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'period',
|
||||
label: t('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 = () => {
|
||||
router.push({ name: 'CustomerRecoverieCreate' });
|
||||
};
|
||||
function setFinished(id) {
|
||||
axios.patch(`Recoveries/${id}`, { finished: Date.vnNow() });
|
||||
tableRef.value.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
:filter="filter"
|
||||
@on-fetch="(data) => (rows = data)"
|
||||
auto-load
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="Recoveries"
|
||||
url="Recoveries"
|
||||
search-url="recoveries"
|
||||
:filter="filter"
|
||||
order="started DESC"
|
||||
:columns="columns"
|
||||
:use-model="true"
|
||||
:right-search="false"
|
||||
:create="{
|
||||
urlCreate: 'Recoveries',
|
||||
title: 'New recovery',
|
||||
onDataSaved: () => tableRef.reload(),
|
||||
formInitialData: { clientFk: route.params.id, started: Date.vnNew() },
|
||||
}"
|
||||
auto-load
|
||||
/>
|
||||
|
||||
<div class="full-width flex justify-center">
|
||||
<QPage class="card-width q-pa-lg">
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:no-data-label="t('globals.noResults')"
|
||||
:pagination="{ rowsPerPage: 12 }"
|
||||
:rows="rows"
|
||||
class="full-width q-mt-md"
|
||||
row-key="id"
|
||||
>
|
||||
<template #body-cell="props">
|
||||
<QTd :props="props">
|
||||
<QTr :props="props" class="cursor-pointer">
|
||||
<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>
|
||||
|
||||
<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>
|
||||
es:
|
||||
Since: Desde
|
||||
To: Hasta
|
||||
Amount: Importe
|
||||
Period: Periodo
|
||||
New recoverie: Nuevo recobro
|
||||
New recovery: Nuevo recobro
|
||||
Finish that recovery period: Terminar recobro
|
||||
</i18n>
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import VnSms from 'src/components/ui/VnSms.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const id = route.params.id;
|
||||
|
||||
const where = {
|
||||
clientFk: id,
|
||||
ticketFk: null,
|
||||
};
|
||||
const where = computed(() => {
|
||||
return {
|
||||
clientFk: route.params.id,
|
||||
ticketFk: null,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="column items-center">
|
||||
<VnSms url="clientSms" :where="where" />
|
||||
</div>
|
||||
<VnSms url="clientSms" :where="where" />
|
||||
</template>
|
||||
|
|
|
@ -2,164 +2,81 @@
|
|||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import axios from 'axios';
|
||||
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 CustomerChangePassword from 'src/pages/Customer/components/CustomerChangePassword.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
|
||||
const { notify } = useNotify();
|
||||
const { t } = useI18n();
|
||||
const { validate } = useValidator();
|
||||
const quasar = useQuasar();
|
||||
const route = useRoute();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const active = ref(false);
|
||||
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(() => {
|
||||
return (
|
||||
user.value.active !== active.value ||
|
||||
user.value.email !== email.value ||
|
||||
user.value.name !== name.value
|
||||
);
|
||||
const filter = computed(() => {
|
||||
return {
|
||||
fields: ['active', 'email', 'name'],
|
||||
where: { id: route.params.id },
|
||||
};
|
||||
});
|
||||
|
||||
const filter = { where: { id: `${route.params.id}` } };
|
||||
|
||||
const showChangePasswordDialog = () => {
|
||||
quasar.dialog({
|
||||
component: CustomerChangePassword,
|
||||
componentProps: {
|
||||
id: route.params.id,
|
||||
promise: usersPreviewRef.value.fetch(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const setInitialData = () => {
|
||||
if (user.value.length) {
|
||||
active.value = user.value[0].active;
|
||||
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;
|
||||
}
|
||||
};
|
||||
async function hasCustomerRole() {
|
||||
const { data } = await axios(`Clients/${route.params.id}/hasCustomerRole`);
|
||||
canChangePassword.value = data;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
<FormModel
|
||||
url="VnUsers/preview"
|
||||
:url-update="`Clients/${route.params.id}/updateUser`"
|
||||
:filter="filter"
|
||||
@on-fetch="
|
||||
(data) => {
|
||||
user = data;
|
||||
setInitialData();
|
||||
model="webAccess"
|
||||
:mapper="
|
||||
({ active, name, email }) => {
|
||||
return {
|
||||
active,
|
||||
name,
|
||||
email,
|
||||
};
|
||||
}
|
||||
"
|
||||
@on-fetch="hasCustomerRole()"
|
||||
auto-load
|
||||
ref="usersPreviewRef"
|
||||
url="VnUsers/preview"
|
||||
/>
|
||||
<FetchData
|
||||
: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"
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<QCheckbox :label="t('Enable web access')" v-model="data.active" />
|
||||
<VnInput :label="t('User')" clearable v-model="data.name" />
|
||||
<VnInput
|
||||
:label="t('Recovery email')"
|
||||
:rules="validate('client.email')"
|
||||
clearable
|
||||
type="email"
|
||||
v-model="data.email"
|
||||
class="q-mt-sm"
|
||||
:info="t('This email is used for user to regain access their account')"
|
||||
/>
|
||||
</template>
|
||||
<template #moreActions>
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('Change password')"
|
||||
:loading="isLoading"
|
||||
@click.stop="showChangePasswordDialog()"
|
||||
color="primary"
|
||||
flat
|
||||
icon="edit"
|
||||
v-if="canChangePassword"
|
||||
:disable="!canChangePassword"
|
||||
@click="showChangePasswordDialog()"
|
||||
/>
|
||||
<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
|
||||
:label="t('Recovery email')"
|
||||
:rules="validate('client.email')"
|
||||
clearable
|
||||
type="email"
|
||||
v-model="email"
|
||||
class="q-mt-sm"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{
|
||||
t(
|
||||
'This email is used for user to regain access their account'
|
||||
)
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</VnInput>
|
||||
</div>
|
||||
</QForm>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</FormModel>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -10,8 +10,10 @@ import EntryFilter from '../EntryFilter.vue';
|
|||
:descriptor="EntryDescriptor"
|
||||
:filter-panel="EntryFilter"
|
||||
search-data-key="EntryList"
|
||||
search-url="Entries/filter"
|
||||
searchbar-label="Search entries"
|
||||
searchbar-info="You can search by entry reference"
|
||||
:searchbar-props="{
|
||||
url: 'Entries/filter',
|
||||
label: 'Search entries',
|
||||
info: 'You can search by entry reference',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,8 +10,10 @@ import InvoiceOutFilter from '../InvoiceOutFilter.vue';
|
|||
:descriptor="InvoiceOutDescriptor"
|
||||
:filter-panel="InvoiceOutFilter"
|
||||
search-data-key="InvoiceOutList"
|
||||
search-url="InvoiceOuts/filter"
|
||||
searchbar-label="Search invoice"
|
||||
searchbar-info="You can search by invoice reference"
|
||||
:searchbar-props="{
|
||||
url: 'InvoiceOuts/filter',
|
||||
label: 'Search invoice',
|
||||
info: 'You can search by invoice reference',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,8 +10,10 @@ import ItemListFilter from '../ItemListFilter.vue';
|
|||
:descriptor="ItemDescriptor"
|
||||
:filter-panel="ItemListFilter"
|
||||
search-data-key="ItemList"
|
||||
search-url="Items/filter"
|
||||
searchbar-label="searchbar.label"
|
||||
searchbar-info="searchbar.info"
|
||||
:searchbar-props="{
|
||||
url: 'Items/filter',
|
||||
label: 'searchbar.labelr',
|
||||
info: 'searchbar.info',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -28,35 +28,10 @@ async function onSubmit() {
|
|||
};
|
||||
try {
|
||||
const { data } = await axios.post('Accounts/login', params);
|
||||
|
||||
if (!data) return;
|
||||
const {
|
||||
data: { multimediaToken },
|
||||
} = await axios.get('VnUsers/ShareToken', {
|
||||
headers: { Authorization: data.token },
|
||||
});
|
||||
|
||||
if (!multimediaToken) return;
|
||||
|
||||
const login = {
|
||||
...data,
|
||||
created: Date.now(),
|
||||
tokenMultimedia: multimediaToken.id,
|
||||
keepLogin: keepLogin.value,
|
||||
};
|
||||
await session.login(login);
|
||||
|
||||
quasar.notify({
|
||||
message: t('login.loginSuccess'),
|
||||
type: 'positive',
|
||||
});
|
||||
|
||||
const currentRoute = router.currentRoute.value;
|
||||
if (currentRoute.query && currentRoute.query.redirect) {
|
||||
router.push(currentRoute.query.redirect);
|
||||
} else {
|
||||
router.push({ name: 'Dashboard' });
|
||||
}
|
||||
data.keepLogin = keepLogin.value;
|
||||
await session.setLogin(data);
|
||||
} catch (res) {
|
||||
if (res.response?.data?.error?.code === 'REQUIRES_2FA') {
|
||||
Notify.create({
|
||||
|
|
|
@ -25,21 +25,10 @@ async function onSubmit() {
|
|||
try {
|
||||
params.code = code.value;
|
||||
const { data } = await axios.post('VnUsers/validate-auth', params);
|
||||
|
||||
if (!data) return;
|
||||
|
||||
await session.login(data.token, params.keepLogin);
|
||||
quasar.notify({
|
||||
message: t('login.loginSuccess'),
|
||||
type: 'positive',
|
||||
});
|
||||
|
||||
const currentRoute = router.currentRoute.value;
|
||||
if (currentRoute.query && currentRoute.query.redirect) {
|
||||
router.push(currentRoute.query.redirect);
|
||||
} else {
|
||||
router.push({ name: 'Dashboard' });
|
||||
}
|
||||
data.keepLogin = params.keepLogin;
|
||||
await session.setLogin(data);
|
||||
} catch (e) {
|
||||
quasar.notify({
|
||||
message: e.response?.data?.error.message,
|
||||
|
|
|
@ -16,8 +16,10 @@ const filter = {
|
|||
:descriptor="ParkingDescriptor"
|
||||
:filter-panel="ParkingFilter"
|
||||
search-data-key="ParkingList"
|
||||
search-url="Parkings"
|
||||
searchbar-label="parking.searchBar.label"
|
||||
searchbar-info="parking.searchBar.info"
|
||||
:searchbar-props="{
|
||||
url: 'Parkings',
|
||||
label: 'parking.searchBar.label',
|
||||
info: 'parking.searchBar.info',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -8,8 +8,10 @@ import VnCard from 'components/common/VnCard.vue';
|
|||
base-url="Agencies"
|
||||
:descriptor="AgencyDescriptor"
|
||||
search-data-key="AgencyList"
|
||||
search-url="Agencies"
|
||||
searchbar-label="agency.searchBar.label"
|
||||
searchbar-info="agency.searchBar.info"
|
||||
:searchbar-props="{
|
||||
url: 'Agencies',
|
||||
label: 'agency.searchBar.label',
|
||||
info: 'agency.searchBar.info',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,8 +10,10 @@ import RoadmapFilter from 'pages/Route/Roadmap/RoadmapFilter.vue';
|
|||
:descriptor="RoadmapDescriptor"
|
||||
:filter-panel="RoadmapFilter"
|
||||
search-data-key="RoadmapList"
|
||||
search-url="Roadmaps"
|
||||
searchbar-label="Search roadmap"
|
||||
searchbar-info="You can search by roadmap id or customer name"
|
||||
:searchbar-props="{
|
||||
url: 'Roadmaps',
|
||||
label: 'Search roadmap',
|
||||
info: 'You can search by roadmap id or customer name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,8 +10,10 @@ import SupplierListFilter from '../SupplierListFilter.vue';
|
|||
:descriptor="SupplierDescriptor"
|
||||
:filter-panel="SupplierListFilter"
|
||||
search-data-key="SupplierList"
|
||||
search-url="Suppliers/filter"
|
||||
searchbar-label="Search suppliers"
|
||||
search-url-query="table"
|
||||
:searchbar-props="{
|
||||
url: 'Suppliers/filter',
|
||||
searchUrl: 'table',
|
||||
label: 'Search suppliers',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -11,6 +11,7 @@ const { t } = useI18n();
|
|||
const route = useRoute();
|
||||
|
||||
const routeName = computed(() => route.name);
|
||||
const customRouteRedirectName = computed(() => routeName.value);
|
||||
</script>
|
||||
<template>
|
||||
<VnCard
|
||||
|
@ -19,8 +20,10 @@ const routeName = computed(() => route.name);
|
|||
:filter-panel="TicketFilter"
|
||||
:descriptor="TicketDescriptor"
|
||||
search-data-key="TicketList"
|
||||
:search-custom-route-redirect="routeName"
|
||||
:searchbar-label="t('card.search')"
|
||||
:searchbar-info="t('card.searchInfo')"
|
||||
:searchbar-props="{
|
||||
customRouteRedirectName,
|
||||
label: t('card.search'),
|
||||
info: t('card.searchInfo'),
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -35,10 +35,12 @@ const filter = {
|
|||
data-key="Travel"
|
||||
base-url="Travels"
|
||||
search-data-key="TravelList"
|
||||
searchbar-label="Search travel"
|
||||
searchbar-info="You can search by travel id or name"
|
||||
search-url="Travels"
|
||||
:filter="filter"
|
||||
:descriptor="TravelDescriptor"
|
||||
:searchbar-props="{
|
||||
url: 'Travels',
|
||||
label: 'Search travel',
|
||||
info: 'You can search by travel id or name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -139,23 +139,19 @@ const maritalStatus = [
|
|||
|
||||
<VnRow>
|
||||
<VnInput v-model="data.SSN" :label="t('SSN')" clearable />
|
||||
<VnInput
|
||||
v-model="data.locker"
|
||||
type="number"
|
||||
:label="t('Locker')"
|
||||
clearable
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputDate :label="t('fiDueDate')" v-model="data.fiDueDate" />
|
||||
|
||||
<VnInput v-model="data.sex" :label="t('sex')" clearable />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('sex')"
|
||||
:options="['M', 'F']"
|
||||
hide-selected
|
||||
v-model="data.sex"
|
||||
/>
|
||||
<VnInputDate :label="t('seniority')" v-model="data.seniority" />
|
||||
<VnInput v-model="data.fi" :label="t('fi')" />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInput v-model="data.fi" :label="t('fi')" />
|
||||
<VnInputDate :label="t('birth')" v-model="data.birth" />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
|
|
|
@ -171,18 +171,16 @@ watch([year, businessFk], () => refreshData());
|
|||
ref="WorkerFreelanceRef"
|
||||
auto-load
|
||||
/>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||
<QScrollArea class="fit text-grey-8">
|
||||
<WorkerCalendarFilter
|
||||
ref="workerCalendarFilterRef"
|
||||
v-model:business-fk="businessFk"
|
||||
v-model:year="year"
|
||||
v-model:absence-type="absenceType"
|
||||
:contract-holidays="contractHolidays"
|
||||
:year-holidays="yearHolidays"
|
||||
/>
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()">
|
||||
<WorkerCalendarFilter
|
||||
ref="workerCalendarFilterRef"
|
||||
v-model:business-fk="businessFk"
|
||||
v-model:year="year"
|
||||
v-model:absence-type="absenceType"
|
||||
:contract-holidays="contractHolidays"
|
||||
:year-holidays="yearHolidays"
|
||||
/>
|
||||
</Teleport>
|
||||
<QPage class="column items-center">
|
||||
<QCard v-if="workerIsFreelance">
|
||||
<QCardSection class="text-center">
|
||||
|
|
|
@ -5,13 +5,15 @@ import WorkerFilter from '../WorkerFilter.vue';
|
|||
</script>
|
||||
<template>
|
||||
<VnCard
|
||||
data-key="Workers"
|
||||
data-key="Worker"
|
||||
base-url="Workers"
|
||||
:descriptor="WorkerDescriptor"
|
||||
:filter-panel="WorkerFilter"
|
||||
search-data-key="WorkerList"
|
||||
search-url="Workers/filter"
|
||||
searchbar-label="Search worker"
|
||||
searchbar-info="You can search by worker id or name"
|
||||
:searchbar-props="{
|
||||
url: 'Workers/filter',
|
||||
label: 'Search worker',
|
||||
info: 'You can search by worker id or name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -11,6 +11,7 @@ import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
|||
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||
import RoleDescriptorProxy from 'src/pages/Account/Role/Card/RoleDescriptorProxy.vue';
|
||||
import VnRow from 'src/components/ui/VnRow.vue';
|
||||
import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -84,10 +85,14 @@ const filter = {
|
|||
:text="t('worker.summary.basicData')"
|
||||
/>
|
||||
<VnLv :label="t('worker.card.name')" :value="worker.user?.nickname" />
|
||||
<VnLv
|
||||
:label="t('worker.list.department')"
|
||||
:value="worker.department?.department?.name"
|
||||
/>
|
||||
<VnLv :label="t('worker.list.department')">
|
||||
<template #value>
|
||||
<span class="link" v-text="worker.department?.department?.name" />
|
||||
<DepartmentDescriptorProxy
|
||||
:id="worker.department?.department?.id"
|
||||
/>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv :label="t('worker.list.email')" :value="worker.user.email" copy />
|
||||
<VnLv :label="t('worker.summary.boss')" link>
|
||||
<template #value>
|
||||
|
|
|
@ -489,7 +489,7 @@ onMounted(async () => {
|
|||
</QBtnGroup>
|
||||
</div>
|
||||
</Teleport>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="260" class="q-pa-md">
|
||||
<Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()">
|
||||
<div class="q-pa-md q-mb-md" style="border: 2px solid #222">
|
||||
<QCardSection horizontal>
|
||||
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||
|
@ -515,7 +515,7 @@ onMounted(async () => {
|
|||
@click-date="onInputChange"
|
||||
@on-moved="getMailStates"
|
||||
/>
|
||||
</QDrawer>
|
||||
</Teleport>
|
||||
<QPage class="column items-center">
|
||||
<QTable :columns="columns" :rows="['']" hide-bottom class="full-width">
|
||||
<template #header="props">
|
||||
|
|
|
@ -28,11 +28,12 @@ const searchBarDataKeys = {
|
|||
data-key="Zone"
|
||||
:descriptor="ZoneDescriptor"
|
||||
:search-data-key="searchBarDataKeys[routeName]"
|
||||
:search-custom-route-redirect="customRouteRedirectName"
|
||||
:search-redirect="!!customRouteRedirectName"
|
||||
:search-make-fetch="searchbarMakeFetch"
|
||||
:searchbar-label="t('list.searchZone')"
|
||||
:searchbar-info="t('list.searchInfo')"
|
||||
:filter-panel="ZoneFilterPanel"
|
||||
:searchbar-props="{
|
||||
url: 'Zones',
|
||||
label: t('list.searchZone'),
|
||||
info: t('list.searchInfo'),
|
||||
}"
|
||||
>
|
||||
<template #searchbar>
|
||||
<ZoneSearchbar />
|
||||
|
|
|
@ -226,31 +226,13 @@ export default {
|
|||
},
|
||||
{
|
||||
path: 'recoveries',
|
||||
name: 'RecoveriesCard',
|
||||
redirect: { name: 'CustomerRecoveries' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'CustomerRecoveries',
|
||||
meta: {
|
||||
title: 'recoveries',
|
||||
icon: 'vn:recovery',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/Customer/Card/CustomerRecoveries.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerRecoverieCreate',
|
||||
meta: {
|
||||
title: 'recoverie-create',
|
||||
},
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/components/CustomerRecoverieCreate.vue'
|
||||
),
|
||||
},
|
||||
],
|
||||
name: 'CustomerRecoveries',
|
||||
meta: {
|
||||
title: 'recoveries',
|
||||
icon: 'vn:recovery',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/Customer/Card/CustomerRecoveries.vue'),
|
||||
},
|
||||
{
|
||||
path: 'web-access',
|
||||
|
|
|
@ -2,7 +2,7 @@ describe('WorkerLocker', () => {
|
|||
const workerId = 1109;
|
||||
const lockerCode = '2F';
|
||||
const input = '.q-card input';
|
||||
const thirdOpt = '[role="listbox"] .q-item:nth-child(3)';
|
||||
const thirdOpt = '[role="listbox"] .q-item:nth-child(1)';
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('productionBoss');
|
||||
|
|
|
@ -25,18 +25,20 @@ describe('Login', () => {
|
|||
vi.spyOn(axios, 'post').mockResolvedValueOnce({ data: { token: 'token' } });
|
||||
vi.spyOn(axios, 'get').mockImplementation((url) => {
|
||||
if (url === 'VnUsers/acls') return Promise.resolve({ data: [] });
|
||||
return Promise.resolve({data: { roles: [], user: expectedUser , multimediaToken: {id:'multimediaToken' }}});
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
roles: [],
|
||||
user: expectedUser,
|
||||
multimediaToken: { id: 'multimediaToken' },
|
||||
},
|
||||
});
|
||||
});
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
expect(vm.session.getToken()).toEqual('');
|
||||
|
||||
await vm.onSubmit();
|
||||
|
||||
expect(vm.session.getToken()).toEqual('token');
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ type: 'positive' })
|
||||
);
|
||||
await vm.session.destroy();
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue