refs #4834 @7h
gitea/salix-front/pipeline/head This commit looks good Details

This commit is contained in:
Pau 2022-11-17 14:03:50 +01:00
parent bd0335fa26
commit 4a39e73625
9 changed files with 577 additions and 0 deletions

View File

@ -249,6 +249,44 @@ export default {
returnOfMaterial: 'Return of material authorization (RMA)'
},
},
worker: {
pageTitles: {
workers: 'Workers',
list: 'List',
},
list: {
name: 'Name',
email: 'Email',
phone: 'Phone',
mobile: 'Mobile',
active: 'Active',
department: 'Department',
schedule: 'Schedule',
},
card: {
workerId: 'Worker ID',
name: 'Name',
email: 'Email',
phone: 'Phone',
mobile: 'Mobile',
active: 'Active',
warehouse: 'Warehouse',
agency: 'Agency',
salesPerson: 'Sales person',
},
summary: {
basicData: 'Basic data',
boss: 'Boss',
phoneExtension: 'Phone extension',
entPhone: 'Enterprise phone',
personalPhone: 'Personal phone',
noBoss: 'No boss',
userData: 'User data',
userId: 'User ID',
role: 'Role',
sipExtension: 'Extension',
},
},
components: {
topbar: {},
userPanel: {

View File

@ -247,6 +247,43 @@ export default {
picked: 'Recogida',
returnOfMaterial: 'Autorización de retorno de materiales (RMA)'
}
}, worker: {
pageTitles: {
workers: 'Trabajadores',
list: 'Listado',
},
list: {
name: 'Nombre',
email: 'Email',
phone: 'Teléfono',
mobile: 'Móvil',
active: 'Activo',
department: 'Departamento',
schedule: 'Horario',
},
card: {
workerId: 'ID Trabajador',
name: 'Nombre',
email: 'Email',
phone: 'Teléfono',
mobile: 'Móvil',
active: 'Activo',
warehouse: 'Almacén',
agency: 'Empresa',
salesPerson: 'Comercial',
},
summary: {
basicData: 'Datos básicos',
boss: 'Jefe',
phoneExtension: 'Extensión de teléfono',
entPhone: 'Teléfono de empresa',
personalPhone: 'Teléfono personal',
noBoss: 'Sin jefe',
userData: 'Datos de usuario',
userId: 'ID del usuario',
role: 'Rol',
sipExtension: 'Extensión',
},
},
components: {
topbar: {},

View File

@ -0,0 +1,43 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { useState } from 'src/composables/useState';
const state = useState();
const { t } = useI18n();
</script>
<template>
<q-drawer v-model="state.drawer.value" show-if-above :width="256" :breakpoint="500">
<q-scroll-area class="fit">
<q-separator />
<q-list>
<q-item :to="{ name: 'CustomerBasicData' }" clickable v-ripple>
<q-item-section avatar>
<q-icon name="vn:settings" />
</q-item-section>
<q-item-section>{{ t('customer.pageTitles.basicData') }}</q-item-section>
</q-item>
<!-- <q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="notes" />
</q-item-section>
<q-item-section>Notes</q-item-section>
</q-item>
<q-expansion-item icon="more" label="More options" expand-icon-toggle expand-separator>
<q-list>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="person" />
</q-item-section>
<q-item-section>Option</q-item-section>
</q-item>
</q-list>
</q-expansion-item> -->
</q-list>
</q-scroll-area>
</q-drawer>
<q-page-container>
<q-page class="q-pa-md">
<router-view></router-view>
</q-page>
</q-page-container>
</template>

View File

@ -0,0 +1,280 @@
<script setup>
import { ref, onMounted, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
onMounted(() => fetch());
const route = useRoute();
const { t } = useI18n();
t == t;
const $props = defineProps({
id: {
type: Number,
default: 0,
},
});
const entityId = computed(() => $props.id || route.params.id);
const worker = ref(null);
const filter = {
include: [
{
relation: 'user',
scope: {
fields: ['email', 'name', 'nickname', 'roleFk'],
include: {
relation: 'role',
scope: {
fields: ['name'],
},
},
},
},
{
relation: 'department',
scope: {
include: {
relation: 'department',
scope: {
fields: ['name'],
},
},
},
},
{
relation: 'boss',
},
{
relation: 'client',
},
{
relation: 'sip',
},
],
};
function fetch() {
const id = entityId.value;
axios.get(`/Workers/${id}`, { params: { filter } }).then((response) => {
worker.value = response.data;
});
}
function sipExtension() {
if (worker.value.sip) return worker.value.sip.extension;
return '-';
}
</script>
<template>
<div class="summary container">
<q-card>
<skeleton-summary v-if="!worker" />
<template v-if="worker">
<div class="header bg-primary q-pa-sm q-mb-md">{{ worker.id }} - {{ worker.firstName }}</div>
<div class="row q-pa-md q-col-gutter-md q-mb-md">
<div class="col">
<q-list>
<q-item-label header class="text-h6">
{{ t('worker.summary.basicData') }}
</q-item-label>
<q-item>
<q-item-section side>
<q-icon name="grid_3x3" />
</q-item-section>
<q-item-section>
<q-item-label caption> ID </q-item-label>
<q-item-label>{{ worker.id }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="person" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.card.name') }} </q-item-label>
<q-item-label>{{ worker.user.nickname }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="group" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.list.department') }} </q-item-label>
<q-item-label>{{ worker.department.department.name }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="email" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.list.email') }} </q-item-label>
<q-item-label>{{ worker.user.email }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="person" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.summary.boss') }} </q-item-label>
<q-item-label>
<router-link
v-if="worker.boss"
:to="{ name: 'WorkerSummary', params: { id: worker.boss.id } }"
target="_blank"
>
{{ worker.boss.name == '' ? t('worker.summary.noBoss') : worker.boss.name }}
<q-icon name="open_in_new" />
</router-link>
</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="grid_3x3" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.summary.phoneExtension') }} </q-item-label>
<q-item-label>
{{ worker.mobileExtension == '' ? worker.mobileExtension : '-' }}
</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="phone" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.summary.entPhone') }} </q-item-label>
<q-item-label>{{ worker.phone }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="phone_android" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.summary.personalPhone') }} </q-item-label>
<q-item-label>{{ worker.client.phone }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</div>
<div class="col">
<q-list>
<q-item-label header class="text-h6">
{{ t('worker.summary.userData') }}
</q-item-label>
<q-item>
<q-item-section side>
<q-icon name="grid_3x3" />
</q-item-section>
<q-item-section>
<q-item-label caption> {{ t('worker.summary.userId') }} </q-item-label>
<q-item-label>{{ worker.user.id }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="person" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.card.name') }} </q-item-label>
<q-item-label>{{ worker.user.nickname }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="group" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.summary.role') }} </q-item-label>
<q-item-label>{{ worker.user.role.name }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section side>
<q-icon name="extension" />
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('worker.summary.sipExtension') }} </q-item-label>
<q-item-label>{{ sipExtension() }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</template>
</q-card>
</div>
</template>
<style lang="scss" scoped>
.container {
display: flex;
justify-content: center;
}
.q-card {
width: 100%;
max-width: 1200px;
}
.negative {
color: red;
}
.summary {
.q-list {
.q-item__label--header {
display: flex;
justify-content: space-between;
a {
color: $primary;
}
}
}
.row {
flex-wrap: wrap;
.col {
min-width: 250px;
}
}
.header {
text-align: center;
font-size: 18px;
}
#slider-container {
max-width: 80%;
margin: 0 auto;
.q-slider {
.q-slider__marker-labels:nth-child(1) {
transform: none;
}
.q-slider__marker-labels:nth-child(2) {
transform: none;
left: auto !important;
right: 0%;
}
}
}
}
.q-dialog .summary {
max-width: 1200px;
}
</style>

View File

@ -0,0 +1,21 @@
<script setup>
import { useDialogPluginComponent } from 'quasar';
import WorkerSummary from './WorkerSummary.vue';
const $props = defineProps({
id: {
type: Number,
required: true,
},
});
defineEmits([...useDialogPluginComponent.emits]);
const { dialogRef, onDialogHide } = useDialogPluginComponent();
</script>
<template>
<q-dialog ref="dialogRef" @hide="onDialogHide">
<worker-summary v-if="$props.id" :id="$props.id" />
</q-dialog>
</template>

View File

@ -0,0 +1,92 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
import Paginate from 'src/components/Paginate.vue';
import WorkerSummaryDialog from './Card/WorkerSummaryDialog.vue';
const router = useRouter();
const { t } = useI18n();
const quasar = useQuasar();
const filter = {
include: [
{
relation: 'user',
scope: {
fields: ['email', 'name', 'nickname'],
},
},
{
relation: 'department',
scope: {
include: {
relation: 'department',
scope: {
fields: ['name'],
},
},
},
},
],
};
function navigate(id) {
router.push({ path: `/worker/${id}` });
}
function viewSummary(id) {
quasar.dialog({
component: WorkerSummaryDialog,
componentProps: {
id,
},
});
}
</script>
<template>
<q-page class="q-pa-md">
<paginate url="/Workers" :filter="filter" sort-by="id DESC" auto-load>
<template #body="{ rows }">
<q-card class="card" v-for="row in rows" :key="row.id">
<q-item class="q-pa-none items-start cursor-pointer q-hoverable" v-ripple clickable>
<q-item-section class="q-pa-md" @click="navigate(row.id)">
<q-item-label caption>#{{ row.id }}</q-item-label>
<q-item-label class="text-h6">{{ row.user.nickname }}</q-item-label>
<q-list>
<q-item class="q-pa-none">
<q-item-section class="q-pa-md">
<q-item-label caption>{{ t('worker.list.name') }}</q-item-label>
<q-item-label>{{ row.user.name }}</q-item-label>
</q-item-section>
<q-item-section class="q-pa-md">
<q-item-label caption>{{ t('worker.list.email') }}</q-item-label>
<q-item-label>{{ row.user.email }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section class="q-pa-md">
<q-item-label caption>{{ t('worker.list.department') }}</q-item-label>
<q-item-label>{{ row.department.department.name }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-item-section>
<q-separator vertical />
<q-card-actions vertical class="justify-between">
<q-item-section side class="q-pa-md">
<q-btn flat round color="orange" icon="preview" @click="viewSummary(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="schedule" @click="navigate(row.id)">
<q-tooltip>{{ t('worker.list.schedule') }}</q-tooltip>
</q-btn>
</q-item-section>
</q-card-actions>
</q-item>
</q-card>
</template>
</paginate>
</q-page>
</template>

View File

@ -0,0 +1,17 @@
<script setup>
import { useState } from 'src/composables/useState';
import LeftMenu from 'src/components/LeftMenu.vue';
const state = useState();
</script>
<template>
<q-drawer v-model="state.drawer.value" show-if-above :width="256" :breakpoint="500">
<q-scroll-area class="fit text-grey-8">
<LeftMenu />
</q-scroll-area>
</q-drawer>
<q-page-container>
<router-view></router-view>
</q-page-container>
</template>

View File

@ -0,0 +1,47 @@
import { RouterView } from 'vue-router';
export default {
name: 'Worker',
path: '/worker',
meta: {
title: 'workers',
icon: 'vn:worker'
},
component: RouterView,
redirect: { name: 'WorkerMain' },
children: [
{
name: 'WorkerMain',
path: '',
component: () => import('src/pages/Worker/WorkerMain.vue'),
redirect: { name: 'WorkerList' },
children: [
{
name: 'WorkerList',
path: 'list',
meta: {
title: 'list',
icon: 'view_list',
},
component: () => import('src/pages/Worker/WorkerList.vue'),
},
]
},
{
name: 'WorkerCard',
path: ':id',
component: () => import('src/pages/Worker/Card/WorkerCard.vue'),
redirect: { name: 'WorkerSummary' },
children: [
{
name: 'WorkerSummary',
path: 'summary',
meta: {
title: 'summary'
},
component: () => import('src/pages/Worker/Card/WorkerSummary.vue'),
},
]
},
]
};

View File

@ -1,6 +1,7 @@
import customer from './modules/customer';
import ticket from './modules/ticket';
import claim from './modules/claim';
import worker from './modules/worker';
const routes = [
{
@ -25,6 +26,7 @@ const routes = [
customer,
ticket,
claim,
worker,
{
path: '/:pathMatch(.*)*',
name: 'NotFound',