Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 4673-claim_module

This commit is contained in:
Joan Sanchez 2022-10-25 14:40:26 +02:00
commit 32ec3c7118
12 changed files with 317 additions and 25 deletions

14
Jenkinsfile vendored
View File

@ -13,13 +13,13 @@ pipeline {
steps {
script {
switch (env.BRANCH_NAME) {
// case 'master':
// env.NODE_ENV = 'production'
// env.BACK_REPLICAS = 1
// break
case 'master':
env.NODE_ENV = 'production'
env.FRONT_REPLICAS = 2
break
case 'test':
env.NODE_ENV = 'test'
env.BACK_REPLICAS = 1
env.FRONT_REPLICAS = 1
break
}
}
@ -58,7 +58,7 @@ pipeline {
stage('Build') {
when { anyOf {
branch 'test'
// branch 'master'
branch 'master'
}}
environment {
CREDENTIALS = credentials('docker-registry')
@ -73,7 +73,7 @@ pipeline {
stage('Deploy') {
when { anyOf {
branch 'test'
// branch 'master'
branch 'master'
}}
environment {
DOCKER_HOST = "${env.SWARM_HOST}"

View File

@ -8,7 +8,7 @@ services:
ports:
- 4000
deploy:
replicas: 2
replicas: ${FRONT_REPLICAS:?}
placement:
constraints:
- node.role == worker

View File

@ -168,6 +168,15 @@ export default {
shipped: 'Shipped',
warehouse: 'Warehouse',
customerCard: 'Customer card'
},
boxing: {
expedition: 'Expedition',
item: 'Item',
created: 'Created',
worker: 'Worker',
selectTime: 'Select time:',
selectVideo: 'Select video:',
notFound: 'No videos available'
}
},
claim: {

View File

@ -167,6 +167,15 @@ export default {
shipped: 'Enviado',
warehouse: 'Almacén',
customerCard: 'Ficha del cliente'
},
boxing: {
expedition: 'Expedición',
item: 'Artículo',
created: 'Creado',
worker: 'Trabajador',
selectTime: 'Seleccionar hora:',
selectVideo: 'Seleccionar vídeo:',
notFound: 'No hay vídeos disponibles'
}
},
claim: {
@ -202,15 +211,6 @@ export default {
customerSummary: 'Resumen del cliente',
claimedTicket: 'Ticket reclamado'
},
basicData: {
customer: 'Cliente',
assignedTo: 'Asignada a',
created: 'Creada',
state: 'Estado',
packages: 'Bultos',
picked: 'Recogida',
returnOfMaterial: 'Autorización de retorno de materiales (RMA)'
},
summary: {
customer: 'Cliente',
assignedTo: 'Asignada a',
@ -225,6 +225,15 @@ export default {
quantity: 'Cantidad'
}
},
},
basicData: {
customer: 'Cliente',
assignedTo: 'Asignada a',
created: 'Creada',
state: 'Estado',
packages: 'Bultos',
picked: 'Recogida',
returnOfMaterial: 'Autorización de retorno de materiales (RMA)'
}
},
components: {

View File

@ -1,6 +1,6 @@
<script setup>
import { useState } from 'src/composables/useState';
import LeftMenu from 'src/components/LeftMenu.vue';
//import LeftMenu from 'src/components/LeftMenu.vue';
const state = useState();
</script>

View File

@ -33,7 +33,7 @@ describe('Login', () => {
}
jest.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } });
jest.spyOn(axios, 'get').mockResolvedValue({ data: { roles: [], user: expectedUser } });
jest.spyOn(vm.quasar, 'notify')
jest.spyOn(vm.quasar, 'notify');
expect(vm.session.getToken()).toEqual('');

View File

@ -0,0 +1,159 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { computed, ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import axios from 'axios';
import { date, useQuasar } from 'quasar';
const router = useRouter();
const { t } = useI18n();
const quasar = useQuasar();
onMounted(async () => {
await fetch();
});
const entityId = computed(function () {
return router.currentRoute.value.params.id;
});
const expeditions = ref({});
const lastExpedition = ref();
const slide = ref(null);
const videoList = ref([]);
const time = ref({
min: 0,
max: 24,
});
async function fetch() {
const filter = {
where: {
ticketFk: entityId.value,
},
};
const { data } = await axios.get(`/Expeditions/filter`, {
params: { filter },
});
if (data) expeditions.value = data;
}
async function getVideoList(expeditionId, timed) {
lastExpedition.value = expeditionId;
const params = {
id: expeditionId,
};
if (timed) {
Object.assign(params, { from: timed.min, to: timed.max });
}
const { data } = await axios.get(`/Boxings/getVideoList`, { params: params });
const list = [];
for (const video of data) {
const videName = video.split('.')[0].split('T')[1].replaceAll('-', ':');
list.push({
label: videName,
value: video,
url: `api/Boxings/getVideo?id=${expeditionId}&filename=${video}`,
});
}
videoList.value = list.reverse();
if (list[0]) {
slide.value = list[0].value;
time.value = {
min: parseInt(list[0].label.split(':')[0]),
max: parseInt(list[list.length - 1].label.split(':')[0]),
};
}
if (!data.length) {
return quasar.notify({
message: t('ticket.boxing.notFound'),
type: 'negative',
});
}
}
</script>
<template>
<q-layout view="hhh lpr ffr" class="fit">
<q-drawer show-if-above side="right" bordered>
<q-scroll-area class="fit">
<q-list bordered separator style="max-width: 318px">
<q-item v-if="lastExpedition && videoList.length">
<q-item-section>
<q-item-label class="text-h6">
{{ t('ticket.boxing.selectTime') }} ({{ time.min }}-{{ time.max }})
</q-item-label>
<q-range
v-model="time"
@change="getVideoList(lastExpedition, time)"
:min="0"
:max="24"
:step="1"
:left-label-value="time.min + ':00'"
:right-label-value="time.max + ':00'"
label
markers
snap
color="orange"
/>
</q-item-section>
</q-item>
<q-item v-if="lastExpedition && videoList.length">
<q-item-section>
<q-select
color="orange"
v-model="slide"
:options="videoList"
:label="t('ticket.boxing.selectVideo')"
emit-value
map-options
>
<template #prepend>
<q-icon name="schedule" />
</template>
</q-select>
</q-item-section>
</q-item>
<q-item
v-for="expedition in expeditions"
:key="expedition.id"
@click="getVideoList(expedition.id)"
clickable
v-ripple
>
<q-item-section>
<q-item-label class="text-h6">#{{ expedition.id }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.boxing.created') }}</q-item-label>
<q-item-label>
{{ date.formatDate(expedition.created, 'YYYY-MM-DD HH:mm:ss') }}
</q-item-label>
<q-item-label caption>{{ t('ticket.boxing.item') }}</q-item-label>
<q-item-label>{{ expedition.packagingItemFk }}</q-item-label>
<q-item-label caption>{{ t('ticket.boxing.worker') }}</q-item-label>
<q-item-label>{{ expedition.userName }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-scroll-area>
</q-drawer>
<q-page-container>
<q-page>
<q-card>
<q-carousel animated v-model="slide" height="max-content">
<q-carousel-slide v-for="video in videoList" :key="video.value" :name="video.value">
<q-video :src="video.url" :ratio="16 / 9" />
</q-carousel-slide>
</q-carousel>
</q-card>
</q-page>
</q-page-container>
</q-layout>
</template>

View File

@ -154,8 +154,8 @@ function stateColor(state) {
<q-item-section>{{ t('ticket.pageTitles.basicData') }}</q-item-section>
</q-item> -->
</q-list>
</q-scroll-area>
</q-drawer>
</q-scroll-area> </q-drawer
>-->
<q-page-container>
<router-view></router-view>
</q-page-container>

View File

@ -0,0 +1,69 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
import TicketBoxing from '../TicketBoxing.vue';
const mockPush = jest.fn();
jest.mock('vue-router', () => ({
useRouter: () => ({
push: mockPush,
currentRoute: {
value: {
params: {
id: 1
}
}
}
}),
}));
describe('TicketBoxing', () => {
let vm;
beforeAll(() => {
vm = createWrapper(TicketBoxing).vm;
});
afterEach(() => {
jest.clearAllMocks();
});
describe('getVideoList()', () => {
it('should when response videoList use to list', async () => {
const expeditionId = 1;
const timed = {
min: 1,
max: 2
}
const videoList = [
"2022-01-01T01-01-00.mp4",
"2022-02-02T02-02-00.mp4",
"2022-03-03T03-03-00.mp4",
]
jest.spyOn(axios, 'get').mockResolvedValue({ data: videoList });
jest.spyOn(vm.quasar, 'notify');
await vm.getVideoList(expeditionId, timed);
expect(vm.videoList.length).toEqual(videoList.length);
expect(vm.slide).toEqual(videoList.reverse()[0]);
});
it('should if not have video show notify', async () => {
const expeditionId = 1;
const timed = {
min: 1,
max: 2
}
jest.spyOn(axios, 'get').mockResolvedValue({ data: [] });
jest.spyOn(vm.quasar, 'notify')
await vm.getVideoList(expeditionId, timed);
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
{ 'type': 'negative' }
));
});
});
});

View File

@ -1,7 +1,7 @@
<script setup>
import { ref } from 'vue';
import { useState } from 'src/composables/useState';
import LeftMenu from 'src/components/LeftMenu.vue';
//import LeftMenu from 'src/components/LeftMenu.vue';
const state = useState();
const miniState = ref(true);
@ -18,9 +18,9 @@ const miniState = ref(true);
:width="256"
:breakpoint="500"
>
<q-scroll-area class="fit text-grey-8">
<!--<q-scroll-area class="fit text-grey-8">
<LeftMenu />
</q-scroll-area>
</q-scroll-area>-->
</q-drawer>
<q-page-container>
<router-view></router-view>

View File

@ -59,6 +59,14 @@ export default {
title: 'basicData'
},
component: () => import('src/pages/Ticket/Card/TicketBasicData.vue'),
},
{
path: 'boxing',
name: 'TicketBoxing',
meta: {
title: 'boxing'
},
component: () => import('src/pages/Ticket/Card/TicketBoxing.vue'),
}
]
},

View File

@ -0,0 +1,38 @@
describe('TicketBoxing', () => {
beforeEach(() => {
const ticketId = 1;
cy.viewport(1280, 720)
cy.login('developer')
cy.visit(`/#/ticket/${ticketId}/boxing`);
});
it('should load expeditions of ticket', () => {
cy.get('div[class="q-item__label text-h6"]').eq(0).should('have.text', '#1');
cy.get('div[class="q-item__label text-h6"]').eq(1).should('have.text', '#2');
cy.get('div[class="q-item__label text-h6"]').eq(2).should('have.text', '#3');
});
it('should show error if not have video list', () => {
cy.get('div[class="q-item__label text-h6"]').eq(0).click();
cy.get('.q-notification__message').should('have.text', 'No videos available');
});
it('should show select time and video if have video list', () => {
cy.intercept(
{
method: 'GET',
url: '/api/Boxings/*',
},
[
"2022-01-01T01-01-00.mp4",
"2022-02-02T02-02-00.mp4",
"2022-03-03T03-03-00.mp4",
]
).as('getVideoList');
cy.get('.q-list > :nth-child(3)').click();
cy.get('.q-list > :nth-child(1)').should('be.visible');
cy.get('.q-list > :nth-child(2)').should('be.visible');
});
});