Merge pull request 'Account ACLs' (!422) from hyervoni/salix-front-mindshore:feature/AccountAcls into dev
gitea/salix-front/pipeline/head This commit looks good
Details
gitea/salix-front/pipeline/head This commit looks good
Details
Reviewed-on: #422 Reviewed-by: Javier Segarra <jsegarra@verdnatura.es> Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
commit
f01d83cfe5
|
@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
|
|
||||||
const emit = defineEmits(['onDataSaved']);
|
const emit = defineEmits(['onDataSaved', 'onDataCanceled']);
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
title: {
|
title: {
|
||||||
|
@ -15,26 +15,6 @@ defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
url: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
type: Object,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
urlCreate: {
|
|
||||||
type: String,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
formInitialData: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -43,8 +23,8 @@ const formModelRef = ref(null);
|
||||||
const closeButton = ref(null);
|
const closeButton = ref(null);
|
||||||
|
|
||||||
const onDataSaved = (formData, requestResponse) => {
|
const onDataSaved = (formData, requestResponse) => {
|
||||||
emit('onDataSaved', formData, requestResponse);
|
|
||||||
closeForm();
|
closeForm();
|
||||||
|
emit('onDataSaved', formData, requestResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoading = computed(() => formModelRef.value?.isLoading);
|
const isLoading = computed(() => formModelRef.value?.isLoading);
|
||||||
|
@ -61,11 +41,9 @@ defineExpose({
|
||||||
<template>
|
<template>
|
||||||
<FormModel
|
<FormModel
|
||||||
ref="formModelRef"
|
ref="formModelRef"
|
||||||
:form-initial-data="formInitialData"
|
|
||||||
:observe-form-changes="false"
|
:observe-form-changes="false"
|
||||||
:default-actions="false"
|
:default-actions="false"
|
||||||
:url-create="urlCreate"
|
v-bind="$attrs"
|
||||||
:model="model"
|
|
||||||
@on-data-saved="onDataSaved"
|
@on-data-saved="onDataSaved"
|
||||||
>
|
>
|
||||||
<template #form="{ data, validate }">
|
<template #form="{ data, validate }">
|
||||||
|
@ -84,6 +62,7 @@ defineExpose({
|
||||||
flat
|
flat
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
|
@click="emit('onDataCanceled')"
|
||||||
v-close-popup
|
v-close-popup
|
||||||
/>
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import isValidDate from 'filters/isValidDate';
|
import isValidDate from 'filters/isValidDate';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
|
|
|
@ -103,6 +103,8 @@ globals:
|
||||||
deliveryList: Delivery days
|
deliveryList: Delivery days
|
||||||
upcomingList: Upcoming deliveries
|
upcomingList: Upcoming deliveries
|
||||||
role: Role
|
role: Role
|
||||||
|
alias: Alias
|
||||||
|
aliasUsers: Users
|
||||||
subRoles: Subroles
|
subRoles: Subroles
|
||||||
inheritedRoles: Inherited Roles
|
inheritedRoles: Inherited Roles
|
||||||
created: Created
|
created: Created
|
||||||
|
|
|
@ -103,6 +103,8 @@ globals:
|
||||||
deliveryList: Días de entrega
|
deliveryList: Días de entrega
|
||||||
upcomingList: Próximos repartos
|
upcomingList: Próximos repartos
|
||||||
role: Role
|
role: Role
|
||||||
|
alias: Alias
|
||||||
|
aliasUsers: Usuarios
|
||||||
subRoles: Subroles
|
subRoles: Subroles
|
||||||
inheritedRoles: Roles heredados
|
inheritedRoles: Roles heredados
|
||||||
created: Fecha creación
|
created: Fecha creación
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
|
import CardList from 'src/components/ui/CardList.vue';
|
||||||
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
|
import AclFilter from './Acls/AclFilter.vue';
|
||||||
|
|
||||||
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import axios from 'axios';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
import AclFormView from './Acls/AclFormView.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
|
||||||
|
const paginateRef = ref();
|
||||||
|
const formDialog = ref(false);
|
||||||
|
const rolesOptions = ref([]);
|
||||||
|
|
||||||
|
const exprBuilder = (param, value) => {
|
||||||
|
switch (param) {
|
||||||
|
case 'search':
|
||||||
|
return { model: { like: `%${value}%` } };
|
||||||
|
default:
|
||||||
|
return { [param]: value };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteAcl = async (id) => {
|
||||||
|
try {
|
||||||
|
await axios.delete(`ACLs/${id}`);
|
||||||
|
paginateRef.value.fetch();
|
||||||
|
notify('ACL removed', 'positive');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting Acl: ', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function showFormDialog(data) {
|
||||||
|
formDialog.value = {
|
||||||
|
show: true,
|
||||||
|
formInitialData: { ...data },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
url="VnRoles"
|
||||||
|
:filter="{ fields: ['name'], order: 'name ASC' }"
|
||||||
|
@on-fetch="(data) => (rolesOptions = data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<template v-if="stateStore.isHeaderMounted()">
|
||||||
|
<Teleport to="#searchbar">
|
||||||
|
<VnSearchbar
|
||||||
|
data-key="AccountAcls"
|
||||||
|
url="ACLs"
|
||||||
|
:expr-builder="exprBuilder"
|
||||||
|
:label="t('acls.search')"
|
||||||
|
:info="t('acls.searchInfo')"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||||
|
<QScrollArea class="fit text-grey-8">
|
||||||
|
<AclFilter data-key="AccountAcls" />
|
||||||
|
</QScrollArea>
|
||||||
|
</QDrawer>
|
||||||
|
|
||||||
|
<QPage class="flex justify-center q-pa-md">
|
||||||
|
<div class="vn-card-list">
|
||||||
|
<VnPaginate
|
||||||
|
ref="paginateRef"
|
||||||
|
data-key="AccountAcls"
|
||||||
|
url="ACLs"
|
||||||
|
:expr-builder="exprBuilder"
|
||||||
|
>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<CardList
|
||||||
|
v-for="row of rows"
|
||||||
|
:id="row.id"
|
||||||
|
:key="row.id"
|
||||||
|
:title="`${row.model}.${row.property}`"
|
||||||
|
@click="showFormDialog(row)"
|
||||||
|
>
|
||||||
|
<template #list-items>
|
||||||
|
<VnLv :label="t('acls.role')" :value="row.principalId" />
|
||||||
|
<VnLv :label="t('acls.accessType')" :value="row.accessType" />
|
||||||
|
<VnLv
|
||||||
|
:label="t('acls.permissions')"
|
||||||
|
:value="row.permission"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.delete')"
|
||||||
|
@click.stop="
|
||||||
|
openConfirmationModal(
|
||||||
|
t('ACL will be removed'),
|
||||||
|
t('Are you sure you want to continue?'),
|
||||||
|
() => deleteAcl(row.id)
|
||||||
|
)
|
||||||
|
"
|
||||||
|
color="primary"
|
||||||
|
style="margin-top: 15px"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</CardList>
|
||||||
|
</template>
|
||||||
|
</VnPaginate>
|
||||||
|
</div>
|
||||||
|
<QDialog
|
||||||
|
v-model="formDialog.show"
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
>
|
||||||
|
<AclFormView
|
||||||
|
:form-initial-data="formDialog.formInitialData"
|
||||||
|
@on-data-change="paginateRef.fetch()"
|
||||||
|
:roles-options="rolesOptions"
|
||||||
|
/>
|
||||||
|
</QDialog>
|
||||||
|
<QPageSticky position="bottom-right" :offset="[18, 18]">
|
||||||
|
<QBtn fab icon="add" color="primary" @click="showFormDialog()">
|
||||||
|
<QTooltip class="text-no-wrap">{{ t('New ACL') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</QPageSticky>
|
||||||
|
</QPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
New ACL: Nuevo ACL
|
||||||
|
ACL removed: ACL eliminado
|
||||||
|
ACL will be removed: El ACL será eliminado
|
||||||
|
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
||||||
|
</i18n>
|
|
@ -1 +1 @@
|
||||||
<template>account list view</template>
|
<template>Account list</template>
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, onBeforeMount } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
dataKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const validationsStore = useValidator();
|
||||||
|
const { models } = validationsStore;
|
||||||
|
|
||||||
|
const validations = ref([]);
|
||||||
|
const accessTypes = [{ name: '*' }, { name: 'READ' }, { name: 'WRITE' }];
|
||||||
|
const permissions = [{ name: 'ALLOW' }, { name: 'DENY' }];
|
||||||
|
const rolesOptions = ref([]);
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
for (let model in models) validations.value.push({ name: model });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
url="VnRoles"
|
||||||
|
:filter="{ fields: ['name'], order: 'name ASC' }"
|
||||||
|
@on-fetch="(data) => (rolesOptions = data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<VnFilterPanel
|
||||||
|
:data-key="props.dataKey"
|
||||||
|
:search-button="true"
|
||||||
|
:hidden-tags="['search']"
|
||||||
|
>
|
||||||
|
<template #tags="{ tag, formatFn }">
|
||||||
|
<div class="q-gutter-x-xs">
|
||||||
|
<strong>{{ t(`acls.aclFilter.${tag.label}`) }}: </strong>
|
||||||
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #body="{ params, searchFn }">
|
||||||
|
<QItem class="q-mb-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.principalId')"
|
||||||
|
v-model="params.principalId"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
:options="rolesOptions"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-mb-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.model')"
|
||||||
|
v-model="params.model"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
:options="validations"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-mb-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('acls.aclFilter.property')"
|
||||||
|
v-model="params.property"
|
||||||
|
lazy-rules
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-mb-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.accessType')"
|
||||||
|
v-model="params.accessType"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
:options="accessTypes"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-mb-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.permission')"
|
||||||
|
v-model="params.permission"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
:options="permissions"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnFilterPanel>
|
||||||
|
</template>
|
|
@ -0,0 +1,126 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { ref, onBeforeMount, onMounted } from 'vue';
|
||||||
|
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
|
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
|
||||||
|
const emit = defineEmits(['onDataChange']);
|
||||||
|
const { t } = useI18n();
|
||||||
|
const validationsStore = useValidator();
|
||||||
|
const { models } = validationsStore;
|
||||||
|
const arrayData = useArrayData('aclCreate');
|
||||||
|
const { store } = arrayData;
|
||||||
|
|
||||||
|
const accessTypes = [{ name: '*' }, { name: 'READ' }, { name: 'WRITE' }];
|
||||||
|
const permissions = [{ name: 'ALLOW' }, { name: 'DENY' }];
|
||||||
|
const validations = ref([]);
|
||||||
|
|
||||||
|
const url = ref();
|
||||||
|
const urlCreate = ref('ACLs');
|
||||||
|
const urlUpdate = ref();
|
||||||
|
const action = ref('New');
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
formInitialData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
property: '*',
|
||||||
|
principalType: 'ROLE',
|
||||||
|
accessType: 'READ',
|
||||||
|
permission: 'ALLOW',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rolesOptions: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
for (let model in models) validations.value.push({ name: model });
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
store.data = $props.formInitialData;
|
||||||
|
if ($props.formInitialData.id) {
|
||||||
|
urlCreate.value = null;
|
||||||
|
urlUpdate.value = 'ACLs';
|
||||||
|
action.value = 'Edit';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormModelPopup
|
||||||
|
v-if="urlCreate || urlUpdate"
|
||||||
|
:title="t(`${action} ACL`)"
|
||||||
|
:url="url"
|
||||||
|
:url-update="urlUpdate"
|
||||||
|
:url-create="urlCreate"
|
||||||
|
:form-initial-data="formInitialData"
|
||||||
|
auto-load
|
||||||
|
model="aclCreate"
|
||||||
|
@on-data-saved="emit('onDataChange')"
|
||||||
|
@on-data-canceled="emit('onDataChange')"
|
||||||
|
>
|
||||||
|
<template #form-inputs="{ data }">
|
||||||
|
<div class="column q-gutter-y-md">
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.principalId')"
|
||||||
|
v-model="data.principalId"
|
||||||
|
:options="$props.rolesOptions"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.model')"
|
||||||
|
v-model="data.model"
|
||||||
|
:options="validations"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VnInput
|
||||||
|
:label="t('acls.aclFilter.property')"
|
||||||
|
v-model="data.property"
|
||||||
|
lazy-rules
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
<QTooltip>{{ t('acls.tooltip') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</template></VnInput
|
||||||
|
>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.accessType')"
|
||||||
|
v-model="data.accessType"
|
||||||
|
:options="accessTypes"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('acls.aclFilter.permission')"
|
||||||
|
v-model="data.permission"
|
||||||
|
:options="permissions"
|
||||||
|
option-value="name"
|
||||||
|
option-label="name"
|
||||||
|
use-input
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</FormModelPopup>
|
||||||
|
</template>
|
|
@ -1,256 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import CrudModel from 'components/CrudModel.vue';
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
|
||||||
import { tMobile } from 'composables/tMobile';
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const accountDevelopmentForm = ref();
|
|
||||||
const accountReasons = ref([]);
|
|
||||||
const accountResults = ref([]);
|
|
||||||
const accountResponsibles = ref([]);
|
|
||||||
const accountRedeliveries = ref([]);
|
|
||||||
const workers = ref([]);
|
|
||||||
const selected = ref([]);
|
|
||||||
const saveButtonRef = ref();
|
|
||||||
|
|
||||||
const developmentsFilter = {
|
|
||||||
fields: [
|
|
||||||
'id',
|
|
||||||
'accountFk',
|
|
||||||
'accountReasonFk',
|
|
||||||
'accountResultFk',
|
|
||||||
'accountResponsibleFk',
|
|
||||||
'workerFk',
|
|
||||||
'accountRedeliveryFk',
|
|
||||||
],
|
|
||||||
where: {
|
|
||||||
accountFk: route.params.id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
|
||||||
{
|
|
||||||
name: 'accountReason',
|
|
||||||
label: t('Reason'),
|
|
||||||
field: (row) => row.accountReasonFk,
|
|
||||||
sortable: true,
|
|
||||||
options: accountReasons.value,
|
|
||||||
required: true,
|
|
||||||
model: 'accountReasonFk',
|
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'description',
|
|
||||||
tabIndex: 1,
|
|
||||||
align: 'left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'accountResult',
|
|
||||||
label: t('Result'),
|
|
||||||
field: (row) => row.accountResultFk,
|
|
||||||
sortable: true,
|
|
||||||
options: accountResults.value,
|
|
||||||
required: true,
|
|
||||||
model: 'accountResultFk',
|
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'description',
|
|
||||||
tabIndex: 2,
|
|
||||||
align: 'left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'accountResponsible',
|
|
||||||
label: t('Responsible'),
|
|
||||||
field: (row) => row.accountResponsibleFk,
|
|
||||||
sortable: true,
|
|
||||||
options: accountResponsibles.value,
|
|
||||||
required: true,
|
|
||||||
model: 'accountResponsibleFk',
|
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'description',
|
|
||||||
tabIndex: 3,
|
|
||||||
align: 'left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'worker',
|
|
||||||
label: t('Worker'),
|
|
||||||
field: (row) => row.workerFk,
|
|
||||||
sortable: true,
|
|
||||||
options: workers.value,
|
|
||||||
model: 'workerFk',
|
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'nickname',
|
|
||||||
tabIndex: 4,
|
|
||||||
align: 'left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'accountRedelivery',
|
|
||||||
label: t('Redelivery'),
|
|
||||||
field: (row) => row.accountRedeliveryFk,
|
|
||||||
sortable: true,
|
|
||||||
options: accountRedeliveries.value,
|
|
||||||
required: true,
|
|
||||||
model: 'accountRedeliveryFk',
|
|
||||||
optionValue: 'id',
|
|
||||||
optionLabel: 'description',
|
|
||||||
tabIndex: 5,
|
|
||||||
align: 'left',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<FetchData
|
|
||||||
url="AccountReasons"
|
|
||||||
order="description"
|
|
||||||
@on-fetch="(data) => (accountReasons = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="AccountResults"
|
|
||||||
order="description"
|
|
||||||
@on-fetch="(data) => (accountResults = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="AccountResponsibles"
|
|
||||||
order="description"
|
|
||||||
@on-fetch="(data) => (accountResponsibles = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="AccountRedeliveries"
|
|
||||||
order="description"
|
|
||||||
@on-fetch="(data) => (accountRedeliveries = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="Workers/search"
|
|
||||||
:where="{ active: 1 }"
|
|
||||||
order="name ASC"
|
|
||||||
@on-fetch="(data) => (workers = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<CrudModel
|
|
||||||
data-key="AccountDevelopments"
|
|
||||||
url="AccountDevelopments"
|
|
||||||
model="accountDevelopment"
|
|
||||||
:filter="developmentsFilter"
|
|
||||||
ref="accountDevelopmentForm"
|
|
||||||
:data-required="{ accountFk: route.params.id }"
|
|
||||||
v-model:selected="selected"
|
|
||||||
auto-load
|
|
||||||
@save-changes="$router.push(`/account/${route.params.id}/action`)"
|
|
||||||
:default-save="false"
|
|
||||||
>
|
|
||||||
<template #body="{ rows }">
|
|
||||||
<QTable
|
|
||||||
:columns="columns"
|
|
||||||
:rows="rows"
|
|
||||||
row-key="$index"
|
|
||||||
selection="multiple"
|
|
||||||
v-model:selected="selected"
|
|
||||||
:grid="$q.screen.lt.md"
|
|
||||||
table-header-class="text-left"
|
|
||||||
>
|
|
||||||
<template #body-cell="{ row, col }">
|
|
||||||
<QTd
|
|
||||||
auto-width
|
|
||||||
@keyup.ctrl.enter.stop="accountDevelopmentForm.saveChanges()"
|
|
||||||
>
|
|
||||||
<VnSelect
|
|
||||||
v-model="row[col.model]"
|
|
||||||
:options="col.options"
|
|
||||||
:option-value="col.optionValue"
|
|
||||||
:option-label="col.optionLabel"
|
|
||||||
:autofocus="col.tabIndex == 1"
|
|
||||||
input-debounce="0"
|
|
||||||
hide-selected
|
|
||||||
>
|
|
||||||
<template #option="scope" v-if="col.name == 'worker'">
|
|
||||||
<QItem v-bind="scope.itemProps">
|
|
||||||
<QItemSection>
|
|
||||||
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
|
|
||||||
<QItemLabel caption>
|
|
||||||
{{ scope.opt?.nickname }}
|
|
||||||
{{ scope.opt?.code }}
|
|
||||||
</QItemLabel>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
</template>
|
|
||||||
</VnSelect>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #item="props">
|
|
||||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
|
||||||
<QCard
|
|
||||||
bordered
|
|
||||||
flat
|
|
||||||
@keyup.ctrl.enter.stop="accountDevelopmentForm?.saveChanges()"
|
|
||||||
>
|
|
||||||
<QCardSection>
|
|
||||||
<QCheckbox v-model="props.selected" dense />
|
|
||||||
</QCardSection>
|
|
||||||
<QSeparator />
|
|
||||||
<QList dense>
|
|
||||||
<QItem v-for="col in props.cols" :key="col.name">
|
|
||||||
<QItemSection>
|
|
||||||
<VnSelect
|
|
||||||
:label="col.label"
|
|
||||||
v-model="props.row[col.model]"
|
|
||||||
:options="col.options"
|
|
||||||
:option-value="col.optionValue"
|
|
||||||
:option-label="col.optionLabel"
|
|
||||||
dense
|
|
||||||
input-debounce="0"
|
|
||||||
:autofocus="col.tabIndex == 1"
|
|
||||||
hide-selected
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
</QList>
|
|
||||||
</QCard>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
</template>
|
|
||||||
<template #moreAfterActions>
|
|
||||||
<QBtn
|
|
||||||
:label="tMobile('globals.save')"
|
|
||||||
ref="saveButtonRef"
|
|
||||||
color="primary"
|
|
||||||
icon="save"
|
|
||||||
:disable="!accountDevelopmentForm?.hasChanges"
|
|
||||||
@click="accountDevelopmentForm?.onSubmit"
|
|
||||||
:title="t('globals.save')"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</CrudModel>
|
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
|
||||||
<QBtn
|
|
||||||
fab
|
|
||||||
color="primary"
|
|
||||||
icon="add"
|
|
||||||
@keydown.tab.prevent="saveButtonRef.$el.focus()"
|
|
||||||
@click="accountDevelopmentForm.insert()"
|
|
||||||
/>
|
|
||||||
</QPageSticky>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.grid-style-transition {
|
|
||||||
transition: transform 0.28s, background-color 0.28s;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Reason: Motivo
|
|
||||||
Result: Consecuencia
|
|
||||||
Responsible: Responsable
|
|
||||||
Worker: Trabajador
|
|
||||||
Redelivery: Devolución
|
|
||||||
</i18n>
|
|
|
@ -1,93 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue';
|
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useState } from 'src/composables/useState';
|
|
||||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
|
||||||
import useCardDescription from 'src/composables/useCardDescription';
|
|
||||||
import { useQuasar } from 'quasar';
|
|
||||||
|
|
||||||
import axios from 'axios';
|
|
||||||
import useNotify from 'src/composables/useNotify.js';
|
|
||||||
const $props = defineProps({
|
|
||||||
id: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
const quasar = useQuasar();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const { notify } = useNotify();
|
|
||||||
const { t } = useI18n();
|
|
||||||
const entityId = computed(() => {
|
|
||||||
return $props.id || route.params.id;
|
|
||||||
});
|
|
||||||
const data = ref(useCardDescription());
|
|
||||||
const setData = (entity) => (data.value = useCardDescription(entity.name, entity.id));
|
|
||||||
const filter = {
|
|
||||||
where: { id: entityId },
|
|
||||||
};
|
|
||||||
const removeRole = () => {
|
|
||||||
quasar
|
|
||||||
.dialog({
|
|
||||||
title: 'Are you sure you want to delete it?',
|
|
||||||
message: 'Delete department',
|
|
||||||
ok: {
|
|
||||||
push: true,
|
|
||||||
color: 'primary',
|
|
||||||
},
|
|
||||||
cancel: true,
|
|
||||||
})
|
|
||||||
.onOk(async () => {
|
|
||||||
try {
|
|
||||||
await axios.post(
|
|
||||||
`/Departments/${entityId.value}/removeChild`,
|
|
||||||
entityId.value
|
|
||||||
);
|
|
||||||
router.push({ name: 'WorkerDepartment' });
|
|
||||||
notify('department.departmentRemoved', 'positive');
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error removing department');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<CardDescriptor
|
|
||||||
ref="descriptor"
|
|
||||||
:url="`VnRoles`"
|
|
||||||
:filter="filter"
|
|
||||||
module="Account"
|
|
||||||
@on-fetch="setData"
|
|
||||||
data-key="accountData"
|
|
||||||
:title="data.title"
|
|
||||||
:subtitle="data.subtitle"
|
|
||||||
>
|
|
||||||
<template #menu>
|
|
||||||
<QItem v-ripple clickable @click="removeRole()">
|
|
||||||
<QItemSection>{{ t('Delete') }}</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
</template>
|
|
||||||
<template #body="{ entity }">
|
|
||||||
<VnLv :label="t('role.card.description')" :value="entity.description" />
|
|
||||||
</template>
|
|
||||||
</CardDescriptor>
|
|
||||||
</template>
|
|
||||||
<style scoped>
|
|
||||||
.q-item__label {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<i18n>
|
|
||||||
en:
|
|
||||||
accountRate: Claming rate
|
|
||||||
es:
|
|
||||||
accountRate: Ratio de reclamación
|
|
||||||
</i18n>
|
|
|
@ -15,6 +15,7 @@ account:
|
||||||
privileges: Privileges
|
privileges: Privileges
|
||||||
mailAlias: Mail Alias
|
mailAlias: Mail Alias
|
||||||
mailForwarding: Mail Forwarding
|
mailForwarding: Mail Forwarding
|
||||||
|
aliasUsers: Users
|
||||||
card:
|
card:
|
||||||
name: Name
|
name: Name
|
||||||
nickname: User
|
nickname: User
|
||||||
|
@ -65,3 +66,16 @@ samba:
|
||||||
verifyCertificate: Verify certificate
|
verifyCertificate: Verify certificate
|
||||||
testConnection: Test connection
|
testConnection: Test connection
|
||||||
success: Samba connection established!
|
success: Samba connection established!
|
||||||
|
acls:
|
||||||
|
role: Role
|
||||||
|
accessType: Access type
|
||||||
|
permissions: Permission
|
||||||
|
search: Search acls
|
||||||
|
searchInfo: Search acls by model name
|
||||||
|
tooltip: Use * to match all properties
|
||||||
|
aclFilter:
|
||||||
|
principalId: Role
|
||||||
|
model: Model
|
||||||
|
property: Property
|
||||||
|
accessType: Access type
|
||||||
|
permission: Permission
|
||||||
|
|
|
@ -15,6 +15,7 @@ account:
|
||||||
privileges: Privilegios
|
privileges: Privilegios
|
||||||
mailAlias: Alias de correo
|
mailAlias: Alias de correo
|
||||||
mailForwarding: Reenvío de correo
|
mailForwarding: Reenvío de correo
|
||||||
|
aliasUsers: Usuarios
|
||||||
card:
|
card:
|
||||||
nickname: Usuario
|
nickname: Usuario
|
||||||
name: Nombre
|
name: Nombre
|
||||||
|
@ -76,3 +77,16 @@ samba:
|
||||||
Verify certificate: Verificar certificado
|
Verify certificate: Verificar certificado
|
||||||
testConnection: Probar conexión
|
testConnection: Probar conexión
|
||||||
success: ¡Conexión con Samba establecida!
|
success: ¡Conexión con Samba establecida!
|
||||||
|
acls:
|
||||||
|
role: Rol
|
||||||
|
accessType: Tipo de acceso
|
||||||
|
permissions: Permiso
|
||||||
|
search: Buscar acls
|
||||||
|
searchInfo: Buscar acls por nombre
|
||||||
|
tooltip: Usa * para marcar todas las propiedades
|
||||||
|
aclFilter:
|
||||||
|
principalId: Rol
|
||||||
|
model: Modelo
|
||||||
|
property: Propiedad
|
||||||
|
accessType: Tipo de acceso
|
||||||
|
permission: Permiso
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
|
||||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
|
import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
|
||||||
|
@ -23,7 +22,6 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const quasar = useQuasar();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { useRoute } from 'vue-router';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { toDateFormat, toTimeFormat } from 'src/filters/date.js';
|
import { toDateFormat, toTimeFormat } from 'src/filters/date.js';
|
||||||
import { dashOrCurrency, toCurrency } from 'filters/index';
|
import { dashOrCurrency } from 'filters/index';
|
||||||
import { dashIfEmpty } from 'src/filters';
|
import { dashIfEmpty } from 'src/filters';
|
||||||
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
||||||
component: RouterView,
|
component: RouterView,
|
||||||
redirect: { name: 'AccountMain' },
|
redirect: { name: 'AccountMain' },
|
||||||
menus: {
|
menus: {
|
||||||
main: ['AccountRoles'],
|
main: ['AccountRoles', 'AccountAcls'],
|
||||||
card: [],
|
card: [],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
@ -30,6 +30,20 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Account/AccountList.vue'),
|
component: () => import('src/pages/Account/AccountList.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'acls',
|
||||||
|
name: 'AccountAcls',
|
||||||
|
meta: {
|
||||||
|
title: 'acls',
|
||||||
|
icon: 'check',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Account/AccountAcls.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'acl-form',
|
||||||
|
name: 'AccountAclForm',
|
||||||
|
component: () => import('src/pages/Account/Acls/AclFormView.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'role-list',
|
path: 'role-list',
|
||||||
name: 'AccountRoles',
|
name: 'AccountRoles',
|
||||||
|
|
|
@ -12,7 +12,6 @@ import Supplier from './Supplier';
|
||||||
import Travel from './travel';
|
import Travel from './travel';
|
||||||
import Order from './order';
|
import Order from './order';
|
||||||
import Department from './department';
|
import Department from './department';
|
||||||
import Role from './role';
|
|
||||||
import Entry from './entry';
|
import Entry from './entry';
|
||||||
import roadmap from './roadmap';
|
import roadmap from './roadmap';
|
||||||
import Parking from './parking';
|
import Parking from './parking';
|
||||||
|
@ -37,7 +36,6 @@ export default [
|
||||||
Order,
|
Order,
|
||||||
invoiceIn,
|
invoiceIn,
|
||||||
Department,
|
Department,
|
||||||
Role,
|
|
||||||
Entry,
|
Entry,
|
||||||
roadmap,
|
roadmap,
|
||||||
Parking,
|
Parking,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import supplier from './modules/Supplier';
|
||||||
import route from './modules/route';
|
import route from './modules/route';
|
||||||
import travel from './modules/travel';
|
import travel from './modules/travel';
|
||||||
import department from './modules/department';
|
import department from './modules/department';
|
||||||
import role from './modules/role';
|
|
||||||
import ItemType from './modules/itemType';
|
import ItemType from './modules/itemType';
|
||||||
import shelving from 'src/router/modules/shelving';
|
import shelving from 'src/router/modules/shelving';
|
||||||
import order from 'src/router/modules/order';
|
import order from 'src/router/modules/order';
|
||||||
|
@ -75,7 +74,6 @@ const routes = [
|
||||||
supplier,
|
supplier,
|
||||||
travel,
|
travel,
|
||||||
department,
|
department,
|
||||||
role,
|
|
||||||
roadmap,
|
roadmap,
|
||||||
entry,
|
entry,
|
||||||
parking,
|
parking,
|
||||||
|
|
Loading…
Reference in New Issue