Commit 29e1442d authored by Julien BOUYER's avatar Julien BOUYER
Browse files

UNOTOPLYS-171 feat(screen) : drag-n-drop des Ecrans

parent e06ffd6d
This diff is collapsed.
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
import { IScreen } from '@/shared/model/screen.model';
@Component
export default class DndList extends Vue {
@Prop()
public screenList: any[];
@Prop()
public idScreen: number;
private currentList: any[];
constructor() {
super();
this.currentList = this.screenList;
}
public set list(screenList: any[]) {
this.currentList = screenList;
}
public get list(): any[] {
return this.currentList;
}
public get options() {
return {
dropzoneSelector: 'ol',
draggableSelector: 'li',
excludeOlderBrowsers: true,
showDropzoneAreas: true,
};
}
public isCurrentPanel(panel: any): boolean {
return this.idScreen == panel.id;
}
public selectScreen(panelScreen: IScreen): void {
this.$emit('selectScreen', panelScreen);
}
public reordered(e: CustomEvent) {
const selectedElm = e.detail.items[0];
const screen = this.screenList.find(s => s.id === Number.parseInt(selectedElm.getAttribute('data-screenid'), 10));
this.$emit('update', { screen, newIndex: e.detail.index });
}
}
<template>
<div v-drag-and-drop:options="options">
<ol class="p-2 text-sm select-none" @reordered="reordered">
<li
v-for="panelScreen in list"
:key="panelScreen.index"
:class="[
'flex items-center p-1 leading-tight transition rounded-md cursor-pointer group hover:absolute focus:ring ',
isCurrentPanel(panelScreen) ? 'font-medium text-white bg-blue-600 hover:bg-blue-700' : 'hover:bg-blue-100',
]"
tabindex="0"
:data-screenid="panelScreen.id"
role="button"
@click="selectScreen(panelScreen)"
>
<span
:class="[
'flex-shrink-0 inline-block w-8 h-6 mr-2 text-sm text-center border rounded-md',
isCurrentPanel(panelScreen)
? 'text-blue-900 bg-blue-100 border-white group-hover:border-blue-900-400'
: 'bg-white border-gray-300 group-hover:border-gray-400',
]"
>{{ panelScreen.index }}</span
>{{ panelScreen.titleBo }}
</li>
</ol>
</div>
</template>
<script lang="ts" src="./dnd-list.component.ts" />
import Vue from 'vue'; import Vue from 'vue';
import { Component } from 'vue-property-decorator'; import { Component } from 'vue-property-decorator';
import { IScreen } from '@/shared/model/screen.model';
import DndList from '@/components/dnd-list/dnd-list.vue';
import Icon from '@/components/icon/icon.vue'; import Icon from '@/components/icon/icon.vue';
@Component({ @Component({
components: { components: {
DndList,
Icon, Icon,
}, },
}) })
export default class Panel extends Vue { export default class Panel extends Vue {
public get screenList(): boolean { public get screenList(): any[] {
return this.$store.getters.screenList; return this.$store.getters.screenList;
} }
public isCurrentPanel(panel) { public updateScreenIndex({ screen, newIndex }) {
return this.idScreen == panel.id; this.$store.dispatch('updateScreenIndex', { screen, newIndex });
} }
public get idWorkspace(): string { public get idWorkspace(): string {
...@@ -25,18 +29,18 @@ export default class Panel extends Vue { ...@@ -25,18 +29,18 @@ export default class Panel extends Vue {
return this.$store.getters.idForm; return this.$store.getters.idForm;
} }
public get idScreen(): string { public get idScreen(): number {
return this.$store.getters.idScreen; return this.$store.getters.idScreen;
} }
public selectScreen(screen) { public selectScreen(screen: IScreen) {
if (screen.id != this.idScreen) { if (screen.id != this.idScreen) {
this.$router.push({ this.$router.push({
name: 'ScreenEditComponent', name: 'ScreenEditComponent',
params: { params: {
idWorkspace: this.idWorkspace, idWorkspace: this.idWorkspace,
idForm: this.idForm, idForm: this.idForm,
idScreen: screen.id, idScreen: `${screen.id}`,
}, },
}); });
} }
......
...@@ -13,29 +13,7 @@ ...@@ -13,29 +13,7 @@
<icon name="trash" /> <icon name="trash" />
</button> </button>
</div> </div>
<ol class="p-2 text-sm select-none"> <dnd-list :screenList="screenList" :idScreen="idScreen" @update="updateScreenIndex" @selectScreen="selectScreen" />
<li
v-for="panelScreen in screenList"
:key="panelScreen.index"
:class="[
'flex items-center p-1 leading-tight transition rounded-md cursor-pointer group hover:absolute focus:ring ',
isCurrentPanel(panelScreen) ? 'font-medium text-white bg-blue-600 hover:bg-blue-700' : 'hover:bg-blue-100',
]"
tabindex="0"
role="button"
@click="selectScreen(panelScreen)"
>
<span
:class="[
'flex-shrink-0 inline-block w-8 h-6 mr-2 text-sm text-center border rounded-md',
isCurrentPanel(panelScreen)
? 'text-blue-900 bg-blue-100 border-white group-hover:border-blue-900-400'
: 'bg-white border-gray-300 group-hover:border-gray-400',
]"
>{{ panelScreen.index }}</span
>{{ panelScreen.titleBo }}
</li>
</ol>
</div> </div>
</aside> </aside>
</template> </template>
......
...@@ -95,4 +95,17 @@ export default class ScreenService { ...@@ -95,4 +95,17 @@ export default class ScreenService {
}); });
}); });
} }
public updateIndex(id: number, index: number): Promise<IScreen> {
return new Promise<IScreen>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${id}`, { index })
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import Vue from 'vue'; import Vue from 'vue';
import App from './app.vue'; import App from './app.vue';
import Vue2Filters from 'vue2-filters'; import Vue2Filters from 'vue2-filters';
import VueDraggable from 'vue-draggable';
import router from './router'; import router from './router';
import { metaInfo } from './shared/meta'; import { metaInfo } from './shared/meta';
import * as config from './shared/config/config'; import * as config from './shared/config/config';
...@@ -18,6 +19,7 @@ import HeaderService from '@/shared/service/header-service'; ...@@ -18,6 +19,7 @@ import HeaderService from '@/shared/service/header-service';
Vue.config.productionTip = false; Vue.config.productionTip = false;
config.initVueApp(Vue); config.initVueApp(Vue);
Vue.use(Vue2Filters); Vue.use(Vue2Filters);
Vue.use(VueDraggable);
const i18n = config.initI18N(Vue); const i18n = config.initI18N(Vue);
const store = config.initVueXStore(Vue); const store = config.initVueXStore(Vue);
......
import { Module } from 'vuex'; import { Module } from 'vuex';
import FormService from '@/entities/form/form.service'; import FormService from '@/entities/form/form.service';
import ScreenService from '@/entities/screen/screen.service'; import ScreenService from '@/entities/screen/screen.service';
import { IScreen } from '@/shared/model/screen.model';
const formService = new FormService(); const formService = new FormService();
const screenService = new ScreenService(); const screenService = new ScreenService();
...@@ -17,6 +18,14 @@ export const formStore: Module<any, any> = { ...@@ -17,6 +18,14 @@ export const formStore: Module<any, any> = {
screenList: state => state.screenList, screenList: state => state.screenList,
}, },
actions: { actions: {
updateScreenIndex({ state, dispatch }, { screen, newIndex }) {
screenService
.updateIndex(screen.id, newIndex)
.then(() => {
dispatch('loadScreens', state.idForm);
})
.catch(console.error);
},
loadScreens({ commit }, idForm) { loadScreens({ commit }, idForm) {
screenService.findByFormId(idForm).then(res => { screenService.findByFormId(idForm).then(res => {
commit('setScreenList', res); commit('setScreenList', res);
......
...@@ -33,3 +33,20 @@ ...@@ -33,3 +33,20 @@
content: '/'; content: '/';
@apply inline-block px-4 font-light text-gray-200; @apply inline-block px-4 font-light text-gray-200;
} }
@keyframes nodeInserted {
from {
opacity: 0.2;
}
to {
opacity: 0.8;
}
}
.item-dropzone-area {
height: 2rem;
background: #888;
opacity: 0.8;
animation-duration: 0.5s;
animation-name: nodeInserted;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment