Merge branch 'dev' into 6891-addToggleFilterPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Jorge Penadés 2024-06-06 08:45:12 +00:00
commit b27ae621f3
36 changed files with 1660 additions and 5179 deletions

View File

@ -1,6 +1,6 @@
{
"name": "salix-front",
"version": "24.24.3",
"version": "24.26.0",
"description": "Salix frontend",
"productName": "Salix",
"author": "Verdnatura",
@ -56,4 +56,4 @@
"vite": "^5.1.4",
"vitest": "^0.31.1"
}
}
}

View File

@ -196,13 +196,13 @@ async function save() {
if ($props.urlCreate) notify('globals.dataCreated', 'positive');
hasChanges.value = false;
isLoading.value = false;
updateAndEmit(response?.data, 'onDataSaved');
} catch (err) {
console.error(err);
notify('errors.writeRequest', 'negative');
} finally {
hasChanges.value = false;
isLoading.value = false;
}
}

View File

@ -20,7 +20,13 @@ const itemComputed = computed(() => {
});
</script>
<template>
<QItem active-class="bg-hover" :to="{ name: itemComputed.name }" clickable v-ripple>
<QItem
active-class="bg-hover"
class="min-height"
:to="{ name: itemComputed.name }"
clickable
v-ripple
>
<QItemSection avatar v-if="itemComputed.icon">
<QIcon :name="itemComputed.icon" />
</QItemSection>
@ -33,3 +39,9 @@ const itemComputed = computed(() => {
</QItemSection>
</QItem>
</template>
<style lang="scss" scoped>
.q-item {
min-height: 5vh;
}
</style>

View File

@ -242,6 +242,7 @@ const emit = defineEmits(['onFetch']);
width: 256px;
.header {
display: flex;
align-items: center;
}
.icons {
margin: 0 10px;

View File

@ -46,6 +46,10 @@ const props = defineProps({
type: Array,
default: () => [],
},
redirect: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['refresh', 'clear', 'search', 'init', 'remove']);
@ -93,7 +97,7 @@ async function search() {
isLoading.value = false;
emit('search');
navigate(store.data, {});
if (props.redirect) navigate(store.data, {});
}
async function reload() {
@ -104,7 +108,7 @@ async function reload() {
if (!props.showAll && !params.length) store.data = [];
isLoading.value = false;
emit('refresh');
navigate(store.data, {});
if (props.redirect) navigate(store.data, {});
}
async function clearFilters() {

View File

@ -76,7 +76,7 @@ select:-webkit-autofill {
}
.color-vn-label {
color: var(--vn-label);
color: var(--vn-label-color);
}
.color-vn-text {

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1,436 +1,438 @@
@font-face {
font-family: 'icon';
src: url('fonts/icon.eot?1om04h');
src: url('fonts/icon.eot?1om04h#iefix') format('embedded-opentype'),
url('fonts/icon.ttf?1om04h') format('truetype'),
url('fonts/icon.woff?1om04h') format('woff'),
url('fonts/icon.svg?1om04h#icon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
font-family: 'icon';
src: url('fonts/icon.eot?y0x93o');
src: url('fonts/icon.eot?y0x93o#iefix') format('embedded-opentype'),
url('fonts/icon.ttf?y0x93o') format('truetype'),
url('fonts/icon.woff?y0x93o') format('woff'),
url('fonts/icon.svg?y0x93o#icon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
[class^='icon-'],
[class*=' icon-'] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icon' !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icon' !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-entry_lastbuys:before {
content: "\e91a";
}
.icon-100:before {
content: '\e901';
content: "\e901";
}
.icon-Client_unpaid:before {
content: '\e98c';
content: "\e98c";
}
.icon-History:before {
content: '\e902';
content: "\e902";
}
.icon-Person:before {
content: '\e903';
content: "\e903";
}
.icon-accessory:before {
content: '\e904';
content: "\e904";
}
.icon-account:before {
content: '\e905';
content: "\e905";
}
.icon-actions:before {
content: '\e907';
content: "\e907";
}
.icon-addperson:before {
content: '\e908';
content: "\e908";
}
.icon-agency:before {
content: '\e92a';
content: "\e92a";
}
.icon-agency-term:before {
content: '\e909';
content: "\e909";
}
.icon-albaran:before {
content: '\e92c';
content: "\e92c";
}
.icon-anonymous:before {
content: '\e90b';
content: "\e90b";
}
.icon-apps:before {
content: '\e90c';
content: "\e90c";
}
.icon-artificial:before {
content: '\e90d';
content: "\e90d";
}
.icon-attach:before {
content: '\e90e';
content: "\e90e";
}
.icon-barcode:before {
content: '\e90f';
content: "\e90f";
}
.icon-basket:before {
content: '\e910';
content: "\e910";
}
.icon-basketadd:before {
content: '\e911';
content: "\e911";
}
.icon-bin:before {
content: '\e913';
content: "\e913";
}
.icon-botanical:before {
content: '\e914';
content: "\e914";
}
.icon-bucket:before {
content: '\e915';
content: "\e915";
}
.icon-buscaman:before {
content: '\e916';
content: "\e916";
}
.icon-buyrequest:before {
content: '\e917';
content: "\e917";
}
.icon-calc_volum .path1:before {
content: '\e918';
color: rgb(0, 0, 0);
content: "\e918";
color: rgb(0, 0, 0);
}
.icon-calc_volum .path2:before {
content: '\e919';
margin-left: -1em;
color: rgb(0, 0, 0);
content: "\e919";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path3:before {
content: '\e91c';
margin-left: -1em;
color: rgb(0, 0, 0);
content: "\e91c";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path4:before {
content: '\e91d';
margin-left: -1em;
color: rgb(0, 0, 0);
content: "\e91d";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path5:before {
content: '\e91e';
margin-left: -1em;
color: rgb(0, 0, 0);
content: "\e91e";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path6:before {
content: '\e91f';
margin-left: -1em;
color: rgb(255, 255, 255);
content: "\e91f";
margin-left: -1em;
color: rgb(255, 255, 255);
}
.icon-calendar:before {
content: '\e920';
content: "\e920";
}
.icon-catalog:before {
content: '\e921';
content: "\e921";
}
.icon-claims:before {
content: '\e922';
content: "\e922";
}
.icon-client:before {
content: '\e923';
content: "\e923";
}
.icon-clone:before {
content: '\e924';
content: "\e924";
}
.icon-columnadd:before {
content: '\e925';
content: "\e925";
}
.icon-columndelete:before {
content: '\e926';
content: "\e926";
}
.icon-components:before {
content: '\e927';
content: "\e927";
}
.icon-consignatarios:before {
content: '\e928';
content: "\e928";
}
.icon-control:before {
content: '\e929';
content: "\e929";
}
.icon-credit:before {
content: '\e92b';
content: "\e92b";
}
.icon-defaulter:before {
content: '\e92d';
content: "\e92d";
}
.icon-deletedTicket:before {
content: '\e92e';
content: "\e92e";
}
.icon-deleteline:before {
content: '\e92f';
content: "\e92f";
}
.icon-delivery:before {
content: '\e930';
content: "\e930";
}
.icon-deliveryprices:before {
content: '\e932';
content: "\e932";
}
.icon-details:before {
content: '\e933';
content: "\e933";
}
.icon-dfiscales:before {
content: '\e934';
content: "\e934";
}
.icon-disabled:before {
content: '\e935';
content: "\e935";
}
.icon-doc:before {
content: '\e936';
content: "\e936";
}
.icon-entry:before {
content: '\e937';
content: "\e937";
}
.icon-exit:before {
content: '\e938';
content: "\e938";
}
.icon-eye:before {
content: '\e939';
content: "\e939";
}
.icon-fixedPrice:before {
content: '\e93a';
content: "\e93a";
}
.icon-flower:before {
content: '\e93b';
content: "\e93b";
}
.icon-frozen:before {
content: '\e93c';
content: "\e93c";
}
.icon-fruit:before {
content: '\e93d';
content: "\e93d";
}
.icon-funeral:before {
content: '\e93e';
content: "\e93e";
}
.icon-grafana:before {
content: '\e906';
content: "\e906";
}
.icon-greenery:before {
content: '\e93f';
content: "\e93f";
}
.icon-greuge:before {
content: '\e940';
content: "\e940";
}
.icon-grid:before {
content: '\e941';
content: "\e941";
}
.icon-handmade:before {
content: '\e942';
content: "\e942";
}
.icon-handmadeArtificial:before {
content: '\e943';
content: "\e943";
}
.icon-headercol:before {
content: '\e945';
content: "\e945";
}
.icon-info:before {
content: '\e946';
content: "\e946";
}
.icon-inventory:before {
content: '\e947';
content: "\e947";
}
.icon-invoice:before {
content: '\e968';
color: #5f5f5f;
content: "\e968";
color: #5f5f5f;
}
.icon-invoice-in:before {
content: '\e949';
content: "\e949";
}
.icon-invoice-in-create:before {
content: '\e94a';
content: "\e94a";
}
.icon-invoice-out:before {
content: '\e94b';
content: "\e94b";
}
.icon-isTooLittle:before {
content: '\e94c';
content: "\e94c";
}
.icon-item:before {
content: '\e94d';
content: "\e94d";
}
.icon-languaje:before {
content: '\e970';
content: "\e970";
}
.icon-lines:before {
content: '\e94e';
content: "\e94e";
}
.icon-linesprepaired:before {
content: '\e94f';
content: "\e94f";
}
.icon-link-to-corrected:before {
content: '\e931';
content: "\e931";
}
.icon-link-to-correcting:before {
content: '\e944';
content: "\e944";
}
.icon-logout:before {
content: '\e973';
content: "\e973";
}
.icon-mana:before {
content: '\e950';
content: "\e950";
}
.icon-mandatory:before {
content: '\e951';
content: "\e951";
}
.icon-net:before {
content: '\e952';
content: "\e952";
}
.icon-newalbaran:before {
content: '\e954';
content: "\e954";
}
.icon-niche:before {
content: '\e955';
content: "\e955";
}
.icon-no036:before {
content: '\e956';
content: "\e956";
}
.icon-noPayMethod:before {
content: '\e958';
content: "\e958";
}
.icon-notes:before {
content: '\e959';
content: "\e959";
}
.icon-noweb:before {
content: '\e95a';
content: "\e95a";
}
.icon-onlinepayment:before {
content: '\e95b';
content: "\e95b";
}
.icon-package:before {
content: '\e95c';
content: "\e95c";
}
.icon-payment:before {
content: '\e95d';
content: "\e95d";
}
.icon-pbx:before {
content: '\e95e';
content: "\e95e";
}
.icon-pets:before {
content: '\e95f';
content: "\e95f";
}
.icon-photo:before {
content: '\e960';
content: "\e960";
}
.icon-plant:before {
content: '\e961';
content: "\e961";
}
.icon-polizon:before {
content: '\e962';
content: "\e962";
}
.icon-preserved:before {
content: '\e963';
content: "\e963";
}
.icon-recovery:before {
content: '\e964';
content: "\e964";
}
.icon-regentry:before {
content: '\e965';
content: "\e965";
}
.icon-reserva:before {
content: '\e966';
content: "\e966";
}
.icon-revision:before {
content: '\e967';
content: "\e967";
}
.icon-risk:before {
content: '\e969';
content: "\e969";
}
.icon-saysimple:before {
content: '\e912';
content: "\e912";
}
.icon-services:before {
content: '\e96a';
content: "\e96a";
}
.icon-settings:before {
content: '\e96b';
content: "\e96b";
}
.icon-shipment:before {
content: '\e96c';
content: "\e96c";
}
.icon-sign:before {
content: '\e90a';
content: "\e90a";
}
.icon-sms:before {
content: '\e96e';
content: "\e96e";
}
.icon-solclaim:before {
content: '\e96f';
content: "\e96f";
}
.icon-solunion:before {
content: '\e971';
content: "\e971";
}
.icon-splitline:before {
content: '\e972';
content: "\e972";
}
.icon-splur:before {
content: '\e974';
content: "\e974";
}
.icon-stowaway:before {
content: '\e975';
content: "\e975";
}
.icon-supplier:before {
content: '\e976';
content: "\e976";
}
.icon-supplierfalse:before {
content: '\e977';
content: "\e977";
}
.icon-tags:before {
content: '\e979';
content: "\e979";
}
.icon-tax:before {
content: '\e97a';
content: "\e97a";
}
.icon-thermometer:before {
content: '\e97b';
content: "\e97b";
}
.icon-ticket:before {
content: '\e97c';
content: "\e97c";
}
.icon-ticketAdd:before {
content: '\e97e';
content: "\e97e";
}
.icon-traceability:before {
content: '\e97f';
content: "\e97f";
}
.icon-transaction:before {
content: '\e91b';
content: "\e91b";
}
.icon-treatments:before {
content: '\e980';
content: "\e980";
}
.icon-trolley:before {
content: '\e900';
content: "\e900";
}
.icon-troncales:before {
content: '\e982';
content: "\e982";
}
.icon-unavailable:before {
content: '\e983';
content: "\e983";
}
.icon-visible_columns_Icono:before {
content: '\e984';
.icon-visible_columns:before {
content: "\e984";
}
.icon-volume:before {
content: '\e985';
content: "\e985";
}
.icon-wand:before {
content: '\e986';
content: "\e986";
}
.icon-web:before {
content: '\e987';
content: "\e987";
}
.icon-wiki:before {
content: '\e989';
content: "\e989";
}
.icon-worker:before {
content: '\e98a';
content: "\e98a";
}
.icon-zone:before {
content: '\e98b';
content: "\e98b";
}

View File

@ -17,6 +17,7 @@ globals:
date: Date
dataSaved: Data saved
dataDeleted: Data deleted
delete: Delete
search: Search
changes: Changes
dataCreated: Data created
@ -101,6 +102,9 @@ globals:
zonesList: Zones
deliveryList: Delivery days
upcomingList: Upcoming deliveries
role: Role
subRoles: Subroles
inheritedRoles: Inherited Roles
created: Created
worker: Worker
now: Now
@ -1254,6 +1258,13 @@ monitor:
pageTitles:
monitors: Monitors
list: List
zone:
pageTitles:
zones: Zones
zonesList: Zones
deliveryList: Delivery days
upcomingList: Upcoming deliveries
components:
topbar: {}
itemsFilterPanel:

View File

@ -17,6 +17,7 @@ globals:
date: Fecha
dataSaved: Datos guardados
dataDeleted: Datos eliminados
delete: Eliminar
search: Buscar
changes: Cambios
dataCreated: Datos creados
@ -101,6 +102,9 @@ globals:
zonesList: Zonas
deliveryList: Días de entrega
upcomingList: Próximos repartos
role: Role
subRoles: Subroles
inheritedRoles: Roles heredados
created: Fecha creación
worker: Trabajador
now: Ahora
@ -1241,8 +1245,14 @@ item/itemType:
summary: Resumen
zone:
pageTitles:
zones: Zona
zonesList: Zonas
zones: Zonas
list: Zonas
deliveryList: Días de entrega
upcomingList: Próximos repartos
role:
pageTitles:
zones: Zonas
list: Zonas
deliveryList: Días de entrega
upcomingList: Próximos repartos
monitor:

View File

@ -0,0 +1 @@
<template>account list view</template>

View File

@ -0,0 +1,17 @@
<script setup>
import { useStateStore } from 'stores/useStateStore';
import LeftMenu from 'components/LeftMenu.vue';
const stateStore = useStateStore();
</script>
<template>
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
<QScrollArea class="fit text-grey-8">
<LeftMenu />
</QScrollArea>
</QDrawer>
<QPageContainer>
<RouterView></RouterView>
</QPageContainer>
</template>

View File

@ -0,0 +1,256 @@
<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>

View File

@ -0,0 +1,131 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { ref } from 'vue';
import VnPaginate from 'src/components/ui/VnPaginate.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import CardList from 'src/components/ui/CardList.vue';
import RoleSummary from './Card/RoleSummary.vue';
import RoleForm from './Card/RoleForm.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
import AccountRolesFilter from './AccountRolesFilter.vue';
import { useStateStore } from 'stores/useStateStore';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
const stateStore = useStateStore();
const router = useRouter();
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
const roleCreateDialogRef = ref(null);
const exprBuilder = (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? { id: value }
: {
or: [
{ name: { like: `%${value}%` } },
{ nickname: { like: `%${value}%` } },
],
};
case 'name':
case 'description':
return { [param]: { like: `%${value}%` } };
}
};
const openCreateModal = () => roleCreateDialogRef.value.show();
const getApiUrl = () => new URL(window.location).origin;
const navigate = (event, id) => {
if (event.ctrlKey || event.metaKey)
return window.open(`${getApiUrl()}/#/account/role/${id}/summary`);
router.push({ name: 'RoleSummary', params: { id } });
};
</script>
<template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar">
<VnSearchbar
data-key="RolesList"
url="VnRoles"
:label="t('role.searchRoles')"
:info="t('role.searchInfo')"
/>
</Teleport>
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
</template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<AccountRolesFilter data-key="RolesList" :expr-builder="exprBuilder" />
</QScrollArea>
</QDrawer>
<QPage class="column items-center q-pa-md">
<div class="vn-card-list">
<VnPaginate data-key="RolesList" url="VnRoles">
<template #body="{ rows }">
<CardList
:id="row.id"
:key="row.id"
:title="row.name"
@click="navigate($event, row.id)"
v-for="row of rows"
>
<template #list-items>
<div style="flex-direction: column; width: 100%">
<VnLv :label="t('role.card.name')" :value="row.name">
</VnLv>
<VnLv
:label="t('role.card.description')"
:value="row.description"
>
</VnLv>
</div>
</template>
<template #actions>
<QBtn
:label="t('components.smartCard.openSummary')"
@click.stop="viewSummary(row.id, RoleSummary)"
color="primary"
style="margin-top: 15px"
/>
</template>
</CardList>
</template>
</VnPaginate>
</div>
<QDialog
ref="roleCreateDialogRef"
transition-show="scale"
transition-hide="scale"
>
<RoleForm />
</QDialog>
<QPageSticky :offset="[20, 20]">
<QBtn fab icon="add" color="primary" @click="openCreateModal()" />
<QTooltip>
{{ t('role.newRole') }}
</QTooltip>
</QPageSticky>
</QPage>
</template>

View File

@ -0,0 +1,52 @@
<script setup>
import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n();
const props = defineProps({
dataKey: {
type: String,
required: true,
},
});
</script>
<template>
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
:redirect="false"
>
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`role.${tag.label}`) }}: </strong>
<span>{{ formatFn(tag.value) }}</span>
</div>
</template>
<template #body="{ params }">
<QItem class="q-my-sm">
<QItemSection>
<VnInput
:label="t('role.name')"
v-model="params.name"
lazy-rules
is-outlined
/>
</QItemSection>
</QItem>
<QItem class="q-my-sm">
<QItemSection>
<VnInput
:label="t('role.description')"
v-model="params.description"
lazy-rules
is-outlined
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>

View File

@ -0,0 +1,96 @@
<script setup>
import { useRoute, useRouter } from 'vue-router';
import { computed, ref, watch } from 'vue';
import VnPaginate from 'components/ui/VnPaginate.vue';
import { useArrayData } from 'composables/useArrayData';
const route = useRoute();
const router = useRouter();
const paginateRef = ref(null);
const arrayData = useArrayData('InheritedRoles');
const store = arrayData.store;
const data = computed(() => {
const dataCopy = store.data;
return dataCopy.sort((a, b) => a.inherits?.name.localeCompare(b.inherits?.name));
});
const filter = computed(() => ({
where: { role: route.params.id },
include: {
relation: 'inherits',
scope: {
fields: ['id', 'name', 'description'],
},
},
}));
const urlPath = computed(() => 'RoleRoles');
const columns = computed(() => [
{
name: 'name',
},
]);
watch(
() => route.params.id,
() => {
store.url = urlPath.value;
store.filter = filter.value;
fetchSubRoles();
}
);
const fetchSubRoles = () => paginateRef.value.fetch();
const redirectToRoleSummary = (id) =>
router.push({ name: 'RoleSummary', params: { id } });
</script>
<template>
<QPage class="column items-center q-pa-md">
<div class="full-width" style="max-width: 400px">
<VnPaginate
ref="paginateRef"
data-key="InheritedRoles"
:filter="filter"
:url="urlPath"
:limit="0"
auto-load
>
<template #body>
<QTable :rows="data" :columns="columns" hide-header>
<template #body="{ row }">
<QTr
@click="redirectToRoleSummary(row.inherits?.id)"
class="cursor-pointer"
>
<QTd>
<div class="column">
<span>{{ row.inherits?.name }}</span>
<span class="color-vn-label">{{
row.inherits?.description
}}</span>
</div>
</QTd>
</QTr>
</template>
</QTable>
</template>
</VnPaginate>
</div>
</QPage>
</template>
<i18n>
es:
Role removed. Changes will take a while to fully propagate.: Rol eliminado. Los cambios tardaran un tiempo en propagarse completamente.
Role added! Changes will take a while to fully propagate.: ¡Rol añadido! Los cambios tardaran un tiempo en propagarse completamente.
El rol va a ser eliminado: Role will be removed
¿Seguro que quieres continuar?: Are you sure you want to continue?
</i18n>

View File

@ -0,0 +1,29 @@
<script setup>
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
const route = useRoute();
const { t } = useI18n();
</script>
<template>
<FormModel :url="`VnRoles/${route.params.id}`" model="VnRole" auto-load>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput v-model="data.name" :label="t('role.card.name')" />
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput
v-model="data.description"
:label="t('role.card.description')"
/>
</div>
</VnRow>
</template>
</FormModel>
</template>

View File

@ -0,0 +1,32 @@
<script setup>
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnCard from 'components/common/VnCard.vue';
import RoleDescriptor from './RoleDescriptor.vue';
const { t } = useI18n();
const route = useRoute();
const routeName = computed(() => route.name);
const customRouteRedirectName = computed(() => routeName.value);
const searchBarDataKeys = {
RoleSummary: 'RoleSummary',
RoleBasicData: 'RoleBasicData',
SubRoles: 'SubRoles',
InheritedRoles: 'InheritedRoles',
RoleLog: 'RoleLog',
};
</script>
<template>
<VnCard
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')"
/>
</template>

View File

@ -0,0 +1,93 @@
<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>

View File

@ -0,0 +1,44 @@
<script setup>
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import FormModelPopup from 'components/FormModelPopup.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
const router = useRouter();
const { t } = useI18n();
</script>
<template>
<FormModelPopup
:title="t('Create role')"
ref="formModelPopupRef"
url-create="VnRoles"
model="VnRole"
:form-initial-data="{}"
@on-data-saved="
(_, { id }) => router.push({ name: 'RoleBasicData', params: { id } })
"
>
<template #form-inputs="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput v-model="data.name" :label="t('role.card.name')" />
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput
v-model="data.description"
:label="t('role.card.description')"
/>
</div>
</VnRow>
</template>
</FormModelPopup>
</template>
<i18n>
es:
Create role: Crear role
</i18n>

View File

@ -0,0 +1,6 @@
<script setup>
import VnLog from 'src/components/common/VnLog.vue';
</script>
<template>
<VnLog model="Role" url="/RoleLogs"></VnLog>
</template>

View File

@ -0,0 +1,52 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import { useArrayData } from 'src/composables/useArrayData';
const route = useRoute();
const { t } = useI18n();
const $props = defineProps({
id: {
type: Number,
default: 0,
},
});
const { store } = useArrayData('Role');
const role = ref(store.data);
const entityId = computed(() => $props.id || route.params.id);
const filter = {
where: { id: entityId },
};
</script>
<template>
<CardSummary
ref="summary"
:url="`VnRoles`"
:filter="filter"
@on-fetch="(data) => (role = data)"
>
<template #header> {{ role.id }} - {{ role.name }} </template>
<template #body>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<a
class="header header-link"
:href="`#/VnUser/${entityId}/basic-data`"
>
{{ t('globals.pageTitles.basicData') }}
<QIcon name="open_in_new" />
</a>
</QCardSection>
<VnLv :label="t('role.card.id')" :value="role.id" />
<VnLv :label="t('role.card.name')" :value="role.name" />
<VnLv :label="t('role.card.description')" :value="role.description" />
</QCard>
</template>
</CardSummary>
</template>

View File

@ -0,0 +1,51 @@
<script setup>
import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import FormPopup from 'components/FormPopup.vue';
const emit = defineEmits(['onSubmitCreateSubrole']);
const { t } = useI18n();
const route = useRoute();
const subRoleFormData = reactive({
inheritsFrom: null,
role: route.params.id,
});
const rolesOptions = ref([]);
</script>
<template>
<FetchData
url="VnRoles"
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
auto-load
@on-fetch="(data) => (rolesOptions = data)"
/>
<FormPopup
model="ZoneWarehouse"
@on-submit="emit('onSubmitCreateSubrole', subRoleFormData)"
>
<template #form-inputs>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnSelect
:label="t('account.card.role')"
v-model="subRoleFormData.inheritsFrom"
:options="rolesOptions"
option-value="id"
option-label="name"
hide-selected
:required="true"
/>
</div>
</VnRow>
</template>
</FormPopup>
</template>

View File

@ -0,0 +1,162 @@
<script setup>
import { useRoute, useRouter } from 'vue-router';
import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import VnPaginate from 'components/ui/VnPaginate.vue';
import SubRoleCreateForm from './SubRoleCreateForm.vue';
import { useVnConfirm } from 'composables/useVnConfirm';
import { useArrayData } from 'composables/useArrayData';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const { openConfirmationModal } = useVnConfirm();
const { notify } = useNotify();
const paginateRef = ref(null);
const createSubRoleDialogRef = ref(null);
const arrayData = useArrayData('SubRoles');
const store = arrayData.store;
const data = computed(() => {
const dataCopy = store.data;
return dataCopy.sort((a, b) => a.inherits?.name.localeCompare(b.inherits?.name));
});
const filter = computed(() => ({
where: { role: route.params.id },
include: {
relation: 'inherits',
scope: {
fields: ['id', 'name', 'description'],
},
},
}));
const urlPath = computed(() => `RoleInherits`);
const columns = computed(() => [
{
name: 'name',
},
{
name: 'action',
},
]);
const deleteSubRole = async (row) => {
try {
await axios.delete(`${urlPath.value}/${row.id}`);
fetchSubRoles();
notify(
t('Role removed. Changes will take a while to fully propagate.'),
'positive'
);
} catch (error) {
console.error(error);
}
};
const createSubRole = async (subRoleFormData) => {
try {
await axios.post(urlPath.value, subRoleFormData);
notify(
t('Role added! Changes will take a while to fully propagate.'),
'positive'
);
fetchSubRoles();
} catch (error) {
console.error(error);
}
};
watch(
() => route.params.id,
() => {
store.url = urlPath.value;
store.filter = filter.value;
fetchSubRoles();
}
);
const fetchSubRoles = () => paginateRef.value.fetch();
const openCreateSubRoleForm = () => createSubRoleDialogRef.value.show();
const redirectToRoleSummary = (id) =>
router.push({ name: 'RoleSummary', params: { id } });
</script>
<template>
<QPage class="column items-center q-pa-md">
<div class="full-width" style="max-width: 400px">
<VnPaginate
ref="paginateRef"
data-key="SubRoles"
:filter="filter"
:url="urlPath"
auto-load
>
<template #body="{ rows }">
<QTable :rows="data" :columns="columns" hide-header>
<template #body="{ row, rowIndex }">
<QTr
@click="redirectToRoleSummary(row.inherits?.id)"
class="cursor-pointer"
>
<QTd>
<div class="column">
<span>{{ row.inherits?.name }}</span>
<span class="color-vn-label">{{
row.inherits?.description
}}</span>
</div>
</QTd>
<QTd style="width: 50px !important">
<QIcon
name="delete"
size="sm"
class="cursor-pointer"
color="primary"
@click.stop.prevent="
openConfirmationModal(
t('El rol va a ser eliminado'),
t('¿Seguro que quieres continuar?'),
() => deleteSubRole(row, rows, rowIndex)
)
"
>
<QTooltip>
{{ t('globals.delete') }}
</QTooltip>
</QIcon>
</QTd>
</QTr>
</template>
</QTable>
</template>
</VnPaginate>
</div>
<QDialog ref="createSubRoleDialogRef">
<SubRoleCreateForm @on-submit-create-subrole="createSubRole" />
</QDialog>
<QPageSticky position="bottom-right" :offset="[18, 18]">
<QBtn fab icon="add" color="primary" @click="openCreateSubRoleForm()">
<QTooltip>{{ t('warehouses.add') }}</QTooltip>
</QBtn>
</QPageSticky>
</QPage>
</template>
<i18n>
es:
Role removed. Changes will take a while to fully propagate.: Rol eliminado. Los cambios tardaran un tiempo en propagarse completamente.
Role added! Changes will take a while to fully propagate.: ¡Rol añadido! Los cambios tardaran un tiempo en propagarse completamente.
El rol va a ser eliminado: Role will be removed
¿Seguro que quieres continuar?: Are you sure you want to continue?
</i18n>

View File

@ -0,0 +1,67 @@
account:
pageTitles:
users: Users
list: Users
roles: Roles
alias: Mail aliasses
accounts: Accounts
ldap: LDAP
samba: Samba
acls: ACLs
connections: Connections
inheritedRoles: Inherited Roles
subRoles: Sub Roles
newRole: New role
privileges: Privileges
mailAlias: Mail Alias
mailForwarding: Mail Forwarding
card:
name: Name
nickname: User
role: Rol
email: Email
alias: Alias
lang: Language
actions:
setPassword: Set password
disableAccount:
name: Disable account
title: La cuenta será deshabilitada
subtitle: ¿Seguro que quieres continuar?
disableUser: Disable user
sync: Sync
delete: Delete
search: Search user
role:
pageTitles:
inheritedRoles: Inherited Roles
subRoles: Sub Roles
card:
description: Description
id: Id
name: Name
newRole: New role
searchRoles: Search role
searchInfo: Search role by id or name
name: Name
description: Description
ldap:
enableSync: Enable synchronization
server: Server
rdn: RDN
userDN: User DN
filter: Filter
groupDN: Group DN
testConnection: Test connection
success: LDAP connection established!
samba:
enableSync: Enable synchronization
domainController: Domain controller
domainAD: AD domain
userAD: AD user
groupDN: Group DN
passwordAD: AD password
domainPart: User DN (without domain part)
verifyCertificate: Verify certificate
testConnection: Test connection
success: Samba connection established!

View File

@ -0,0 +1,78 @@
account:
pageTitles:
users: Usuarios
list: Usuarios
roles: Roles
alias: Alias de correo
accounts: Cuentas
ldap: LDAP
samba: Samba
acls: ACLs
connections: Conexiones
inheritedRoles: Roles heredados
newRole: Nuevo rol
subRoles: Subroles
privileges: Privilegios
mailAlias: Alias de correo
mailForwarding: Reenvío de correo
card:
nickname: Usuario
name: Nombre
role: Rol
email: Mail
alias: Alias
lang: dioma
actions:
setPassword: Establecer contraseña
disableAccount:
name: Deshabilitar cuenta
title: La cuenta será deshabilitada
subtitle: ¿Seguro que quieres continuar?
disableUser:
name: Desactivar usuario
title: El usuario será deshabilitado
subtitle: ¿Seguro que quieres continuar?
sync:
name: Sincronizar
title: El usuario será sincronizado
subtitle: ¿Seguro que quieres continuar?
delete:
name: Eliminar
title: El usuario será eliminado
subtitle: ¿Seguro que quieres continuar?
search: Buscar usuario
role:
pageTitles:
inheritedRoles: Roles heredados
subRoles: Subroles
newRole: Nuevo rol
card:
description: Descripción
id: Id
name: Nombre
newRole: Nuevo rol
searchRoles: Buscar roles
searchInfo: Buscar rol por id o nombre
name: Nombre
description: Descripción
ldap:
enableSync: Habilitar sincronización
server: Servidor
rdn: RDN
userDN: DN usuarios
filter: Filtro
groupDN: DN grupos
testConnection: Probar conexión
success: ¡Conexión con LDAP establecida!
samba:
enableSync: Habilitar sincronización
domainController: Controlador de dominio
domainAD: Dominio AD
groupDN: DN grupos
userAD: Usuario AD
passwordAD: Contraseña AD
domainPart: DN usuarios (sin la parte del dominio)
Verify certificate: Verificar certificado
testConnection: Probar conexión
success: ¡Conexión con Samba establecida!

View File

@ -0,0 +1,185 @@
import { RouterView } from 'vue-router';
export default {
path: '/account',
name: 'Account',
meta: {
title: 'users',
icon: 'face',
moduleName: 'Account',
},
component: RouterView,
redirect: { name: 'AccountMain' },
menus: {
main: ['AccountRoles'],
card: [],
},
children: [
{
path: '',
name: 'AccountMain',
component: () => import('src/pages/Account/AccountMain.vue'),
redirect: { name: 'AccountList' },
children: [
{
path: 'list',
name: 'AccountList',
meta: {
title: 'list',
icon: 'view_list',
},
component: () => import('src/pages/Account/AccountList.vue'),
},
{
path: 'role-list',
name: 'AccountRoles',
meta: {
title: 'roles',
icon: 'group',
},
component: () => import('src/pages/Account/Role/AccountRoles.vue'),
},
{
path: 'alias',
name: 'AccountAlias',
meta: {
title: 'alias',
icon: 'email',
},
component: () => import('src/pages/Account/AccountAlias.vue'),
},
{
path: 'accounts',
name: 'AccountAccounts',
meta: {
title: 'accounts',
icon: 'accessibility',
},
component: () => import('src/pages/Account/AccountAccounts.vue'),
},
{
path: 'ldap',
name: 'AccountLdap',
meta: {
title: 'ldap',
icon: 'account_tree',
},
component: () => import('src/pages/Account/AccountLdap.vue'),
},
{
path: 'samba',
name: 'AccountSamba',
meta: {
title: 'samba',
icon: 'preview',
},
component: () => import('src/pages/Account/AccountSamba.vue'),
},
{
path: 'acls',
name: 'AccountAcls',
meta: {
title: 'acls',
icon: 'check',
},
component: () => import('src/pages/Account/AccountAcls.vue'),
},
{
path: 'connections',
name: 'AccountConnections',
meta: {
title: 'connections',
icon: 'check',
},
component: () => import('src/pages/Account/AccountConnections.vue'),
},
{
path: 'create',
name: 'AccountCreate',
meta: {
title: 'accountCreate',
icon: 'add',
},
component: () => import('src/pages/Account/AccountCreate.vue'),
},
],
},
{
name: 'AccountCard',
path: ':id',
component: () => import('src/pages/Account/Card/AccountCard.vue'),
redirect: { name: 'AccountSummary' },
children: [
{
name: 'AccountSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'launch',
},
component: () => import('src/pages/Account/Card/AccountSummary.vue'),
},
{
name: 'AccountBasicData',
path: 'basic-data',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () =>
import('src/pages/Account/Card/AccountBasicData.vue'),
},
{
name: 'AccountInheritedRoles',
path: 'inherited-oles',
meta: {
title: 'inheritedRoles',
icon: 'group',
},
component: () =>
import('src/pages/Account/Card/AccountInheritedRoles.vue'),
},
{
name: 'AccountMailForwarding',
path: 'mail-forwarding',
meta: {
title: 'mailForwarding',
icon: 'forward',
},
component: () =>
import('src/pages/Account/Card/AccountMailForwarding.vue'),
},
{
name: 'AccountMailAlias',
path: 'mail-alias',
meta: {
title: 'mailAlias',
icon: 'email',
},
component: () =>
import('src/pages/Account/Card/AccountMailAlias.vue'),
},
{
name: 'AccountPrivileges',
path: 'privileges',
meta: {
title: 'privileges',
icon: 'badge',
},
component: () =>
import('src/pages/Account/Card/AccountPrivileges.vue'),
},
{
name: 'AccountLog',
path: 'log',
meta: {
title: 'log',
icon: 'history',
},
component: () => import('src/pages/Account/Card/AccountLog.vue'),
},
],
},
],
};

View File

@ -12,12 +12,14 @@ import Supplier from './Supplier';
import Travel from './travel';
import Order from './order';
import Department from './department';
import Role from './role';
import Entry from './entry';
import roadmap from './roadmap';
import Parking from './parking';
import Agency from './agency';
import ItemType from './itemType';
import Zone from './zone';
import Account from './account';
import Monitor from './monitor';
export default [
@ -35,11 +37,13 @@ export default [
Order,
invoiceIn,
Department,
Role,
Entry,
roadmap,
Parking,
Agency,
ItemType,
Zone,
Account,
Monitor,
];

View File

@ -0,0 +1,76 @@
import { RouterView } from 'vue-router';
export default {
path: 'account/role',
name: 'Role',
meta: {
title: 'role',
icon: 'vn:greuge',
moduleName: 'Role',
},
component: RouterView,
redirect: { name: 'AccountRoles' },
menus: {
main: [],
card: ['RoleBasicData', 'SubRoles', 'InheritedRoles', 'RoleLog'],
},
children: [
{
name: 'RoleCard',
path: ':id',
component: () => import('src/pages/Account/Role/Card/RoleCard.vue'),
redirect: { name: 'RoleSummary' },
children: [
{
name: 'RoleSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'launch',
},
component: () =>
import('src/pages/Account/Role/Card/RoleSummary.vue'),
},
{
name: 'RoleBasicData',
path: 'basic-data',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () =>
import('src/pages/Account/Role/Card/RoleBasicData.vue'),
},
{
name: 'SubRoles',
path: 'sub-roles',
meta: {
title: 'subRoles',
icon: 'group',
},
component: () => import('src/pages/Account/Role/Card/SubRoles.vue'),
},
{
name: 'InheritedRoles',
path: 'inherited-roles',
meta: {
title: 'inheritedRoles',
icon: 'account_tree',
},
component: () =>
import('src/pages/Account/Role/Card/InheritedRoles.vue'),
},
{
name: 'RoleLog',
path: 'log',
meta: {
title: 'log',
icon: 'history',
},
component: () => import('src/pages/Account/Role/Card/RoleLog.vue'),
},
],
},
],
};

View File

@ -24,7 +24,6 @@ export default {
'WorkerTimeControl',
'WorkerLocker',
],
departmentCard: ['BasicData'],
},
children: [
{

View File

@ -10,6 +10,7 @@ import supplier from './modules/Supplier';
import route from './modules/route';
import travel from './modules/travel';
import department from './modules/department';
import role from './modules/role';
import ItemType from './modules/itemType';
import shelving from 'src/router/modules/shelving';
import order from 'src/router/modules/order';
@ -18,6 +19,7 @@ import roadmap from 'src/router/modules/roadmap';
import parking from 'src/router/modules/parking';
import agency from 'src/router/modules/agency';
import zone from 'src/router/modules/zone';
import account from './modules/account';
import monitor from 'src/router/modules/monitor';
const routes = [
@ -73,12 +75,14 @@ const routes = [
supplier,
travel,
department,
role,
roadmap,
entry,
parking,
agency,
ItemType,
zone,
account,
{
path: '/:catchAll(.*)*',
name: 'NotFound',

View File

@ -23,6 +23,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
'worker',
'wagon',
'zone',
'account',
];
const pinnedModules = ref([]);
const role = useRole();