442 lines
13 KiB
Vue
442 lines
13 KiB
Vue
<template>
|
|
<v-container fluid>
|
|
|
|
<v-row class="fill-height">
|
|
<v-btn @click="showAddProductDialog = true">Add products</v-btn>
|
|
</v-row>
|
|
|
|
<v-row class="fill-height">
|
|
<v-col cols="4">
|
|
<v-card>
|
|
<DragListHeading title="Sections">
|
|
<v-btn icon class="ma-0 pa-0" @click="showAddSectionDialog = true">
|
|
<v-icon>add</v-icon>
|
|
</v-btn>
|
|
</DragListHeading>
|
|
|
|
<div id="sections" class="list-group">
|
|
<div v-for="item in catalog.sections" :key="item.id">
|
|
<v-hover :key="item.id">
|
|
<v-list-item
|
|
slot-scope="{ hover }"
|
|
:class="sectionListItemClasses(item.id, hover)"
|
|
@click="selectSection(item.id)"
|
|
>
|
|
<!-- TODO try move sectionparent into v-list-title
|
|
and so section-drop can cover all interior
|
|
-->
|
|
<v-list-item-content class="section-parent">
|
|
<v-list-item-title v-html="item.name"/>
|
|
<v-list-item-subtitle
|
|
class="caption font-weight-light"
|
|
color="grey lighten-2"
|
|
>
|
|
{{ sectionModelCount(item.id) }} {{ sectionModelCount(item.id) | pluralize('model') }}
|
|
</v-list-item-subtitle>
|
|
<v-list-item-subtitle class="section-drop" :section-id="item.id"/>
|
|
</v-list-item-content>
|
|
|
|
<v-list-item-action>
|
|
<span class="group">
|
|
<v-btn icon @click.stop="popSectionInfo(item.id)">
|
|
<v-icon small color="grey lighten-1">info</v-icon>
|
|
</v-btn>
|
|
<v-btn icon @click.stop="popSectionDelete(item.id)">
|
|
<v-icon small color="grey lighten-1">delete</v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</v-list-item-action>
|
|
|
|
</v-list-item>
|
|
</v-hover>
|
|
</div>
|
|
</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<v-col cols="4">
|
|
<v-card>
|
|
<DragListHeading title="Models" />
|
|
|
|
<div id="models" class="list-group">
|
|
<div v-for="item in selectedModels" :key="item.model">
|
|
<v-hover :key="item.model">
|
|
<v-list-item
|
|
slot-scope="{ hover }"
|
|
:class="modelListItemClasses(item.model, hover)"
|
|
@click="selectModel(item.model)"
|
|
>
|
|
<v-list-item-content>
|
|
<v-list-item-title v-html="item.name"/>
|
|
<v-list-item-subtitle
|
|
class="caption font-weight-light"
|
|
color="grey lighten-2">
|
|
{{ item.ids.length }} {{ item.ids.length | pluralize('material') }}
|
|
</v-list-item-subtitle>
|
|
</v-list-item-content>
|
|
|
|
<v-list-item-action>
|
|
<span class="group">
|
|
<v-btn icon @click.stop="popModelInfo(item.model)">
|
|
<v-icon small color="grey lighten-1">info</v-icon>
|
|
</v-btn>
|
|
<v-btn icon @click.stop="popModelDelete(item.model)">
|
|
<v-icon small color="grey lighten-1">delete</v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</v-list-item-action>
|
|
|
|
</v-list-item>
|
|
</v-hover>
|
|
</div>
|
|
</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<v-col cols="4">
|
|
<v-card>
|
|
<DragListHeading title="Materials" />
|
|
|
|
<div id="materials" class="list-group">
|
|
<div v-for="item in selectedMaterials" :key="item.id">
|
|
<v-hover :key="item.id">
|
|
<v-list-item
|
|
slot-scope="{ hover }"
|
|
:class="materialListItemClasses(item.id, hover)"
|
|
@click="selectMaterial(item.id)"
|
|
>
|
|
<v-list-item-content>
|
|
<v-list-item-title><b>{{ item.id }}</b> {{ item.name }}</v-list-item-title>
|
|
<v-list-item-subtitle v-html="item.color"/>
|
|
</v-list-item-content>
|
|
|
|
<v-list-item-action>
|
|
<span class="group">
|
|
<v-btn icon @click="popMaterialDelete(item.id)">
|
|
<v-icon small color="grey lighten-1">delete</v-icon>
|
|
</v-btn>
|
|
</span>
|
|
</v-list-item-action>
|
|
</v-list-item>
|
|
</v-hover>
|
|
</div>
|
|
</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
</v-row>
|
|
|
|
<AddProductDialog v-model="showAddProductDialog"/>
|
|
<AddSectionDialog v-model="showAddSectionDialog"/>
|
|
<SectionInfoDialog v-model="showSectionInfoDialog"/>
|
|
<SectionDeleteDialog v-model="showSectionDeleteDialog"/>
|
|
<ModelInfoDialog v-model="showModelInfoDialog"/>
|
|
<ModelDeleteDialog v-model="showModelDeleteDialog"/>
|
|
<MaterialDeleteDialog v-model="showMaterialDeleteDialog"/>
|
|
|
|
</v-container>
|
|
</template>
|
|
|
|
<script>
|
|
import Sortable from 'sortablejs'
|
|
import { mapState, mapGetters, mapActions } from 'vuex'
|
|
//import RawDisplayer from './RawDisplayer'
|
|
import DragListHeading from './DragListHeading'
|
|
import AddProductDialog from './AddProductDialog'
|
|
import AddSectionDialog from './AddSectionDialog'
|
|
import SectionInfoDialog from './SectionInfoDialog'
|
|
import SectionDeleteDialog from './SectionDeleteDialog'
|
|
import ModelInfoDialog from './ModelInfoDialog'
|
|
import ModelDeleteDialog from './ModelDeleteDialog'
|
|
import MaterialDeleteDialog from './MaterialDeleteDialog'
|
|
|
|
export default {
|
|
components: {
|
|
DragListHeading,
|
|
AddProductDialog,
|
|
AddSectionDialog,
|
|
SectionInfoDialog,
|
|
SectionDeleteDialog,
|
|
ModelInfoDialog,
|
|
ModelDeleteDialog,
|
|
MaterialDeleteDialog,
|
|
//RawDisplayer,
|
|
},
|
|
|
|
data: () => ({
|
|
showAddProductDialog: false,
|
|
showAddSectionDialog: false,
|
|
showSectionInfoDialog: false,
|
|
showSectionDeleteDialog: false,
|
|
showModelInfoDialog: false,
|
|
showModelDeleteDialog: false,
|
|
//showMaterialInfoDialog: false,
|
|
showMaterialDeleteDialog: false,
|
|
}),
|
|
computed: {
|
|
...mapState([
|
|
'catalog',
|
|
'materials',
|
|
'selectedSectionID',
|
|
'selectedModelID',
|
|
'selectedMaterialID',
|
|
]),
|
|
...mapGetters([
|
|
'section',
|
|
'selectedSection',
|
|
'selectedModel',
|
|
'selectedMaterial',
|
|
'sectionModels',
|
|
'modelMaterials',
|
|
'material',
|
|
]),
|
|
selectedModels() {
|
|
let section = this.selectedSection
|
|
return this.sectionModels(section)
|
|
},
|
|
selectedMaterials() {
|
|
let model = this.selectedModel
|
|
return this.modelMaterials(model)
|
|
},
|
|
},
|
|
|
|
mounted: function() {
|
|
let me = this
|
|
|
|
// reordering of sections
|
|
Sortable.create(document.getElementById('sections'), {
|
|
group: {
|
|
name: 'sections',
|
|
},
|
|
animation: 150,
|
|
onEnd: function(evt) {
|
|
me.reorderSection({ from: evt.oldIndex, to: evt.newIndex })
|
|
},
|
|
})
|
|
|
|
// reordering of models
|
|
Sortable.create(document.getElementById('models'), {
|
|
group: {
|
|
name: 'models',
|
|
},
|
|
animation: 150,
|
|
onStart: function(evt) {
|
|
addSectionDrops(me)
|
|
},
|
|
onEnd: function(evt) {
|
|
if (evt.from === evt.to) {
|
|
me.reorderModel({ section: me.selectedSection,
|
|
fromIndex: evt.oldIndex,
|
|
toIndex: evt.newIndex })
|
|
} else {
|
|
// dropped on a section.
|
|
let models = me.selectedModels
|
|
let model = models[evt.oldIndex]
|
|
|
|
let sectionID = Number(evt.to.getAttribute('section-id'))
|
|
let newSection = me.section(sectionID)
|
|
|
|
if (me.selectedSection.id !== newSection.id) {
|
|
me.moveModelToSection({ model: model,
|
|
oldSection: me.selectedSection,
|
|
newSection: newSection })
|
|
} else {
|
|
console.log('not moving to same section')
|
|
}
|
|
}
|
|
},
|
|
})
|
|
|
|
// reordering of materials
|
|
Sortable.create(document.getElementById('materials'), {
|
|
group: {
|
|
name: 'materials',
|
|
},
|
|
animation: 150,
|
|
onStart: function(evt) {
|
|
addSectionDrops(me)
|
|
},
|
|
onEnd: function(evt) {
|
|
if (evt.from === evt.to) {
|
|
me.reorderMaterial({ section: me.selectedSection,
|
|
model: me.selectedModel,
|
|
fromIndex: evt.oldIndex,
|
|
toIndex: evt.newIndex })
|
|
} else {
|
|
// dropped on a section.
|
|
let mats = me.selectedMaterials
|
|
let mat = mats[evt.oldIndex]
|
|
|
|
let sectionID = Number(evt.to.getAttribute('section-id'))
|
|
let newSection = me.section(sectionID)
|
|
|
|
if (me.selectedSection.id !== newSection.id) {
|
|
me.moveMaterialToSection({ material: mat,
|
|
oldSection: me.selectedSection,
|
|
oldModel: me.selectedModel,
|
|
newSection: newSection })
|
|
} else {
|
|
console.log('not moving to same section')
|
|
}
|
|
}
|
|
},
|
|
})
|
|
},
|
|
|
|
methods: {
|
|
sectionModelCount(sectionID) {
|
|
let section = this.section(sectionID)
|
|
if (section) {
|
|
let models = this.sectionModels(section) || []
|
|
return models.length
|
|
} else {
|
|
return 0
|
|
}
|
|
},
|
|
|
|
sectionListItemClasses(id, hovering) {
|
|
if (id === this.selectedSectionID) {
|
|
return 'list-item primary'
|
|
} else if (hovering) {
|
|
return 'list-item list-hover'
|
|
} else {
|
|
return 'list-item'
|
|
}
|
|
},
|
|
|
|
modelListItemClasses(id, hovering) {
|
|
if (id === this.selectedModelID) {
|
|
return 'list-item primary'
|
|
} else if (hovering) {
|
|
return 'list-item list-hover'
|
|
} else {
|
|
return 'list-item'
|
|
}
|
|
},
|
|
|
|
materialListItemClasses(id, hovering) {
|
|
if (id === this.selectedMaterialID) {
|
|
return 'list-item primary'
|
|
} else if (hovering) {
|
|
return 'list-item list-hover'
|
|
} else {
|
|
return 'list-item'
|
|
}
|
|
},
|
|
|
|
popSectionInfo(id) {
|
|
this.selectSection(id)
|
|
this.showSectionInfoDialog = true
|
|
},
|
|
|
|
popSectionDelete(id) {
|
|
this.selectSection(id)
|
|
this.showSectionDeleteDialog = true
|
|
},
|
|
|
|
popModelInfo(id) {
|
|
this.selectModel(id)
|
|
this.showModelInfoDialog = true
|
|
},
|
|
|
|
popModelDelete(id) {
|
|
this.selectModel(id)
|
|
this.showModelDeleteDialog = true
|
|
},
|
|
|
|
popMaterialDelete(id) {
|
|
this.selectMaterial(id)
|
|
this.showMaterialDeleteDialog = true
|
|
},
|
|
|
|
...mapActions([
|
|
'selectSection',
|
|
'selectModel',
|
|
'selectMaterial',
|
|
'reorderSection',
|
|
'reorderModel',
|
|
'reorderMaterial',
|
|
'moveModelToSection',
|
|
'moveMaterialToSection',
|
|
]),
|
|
}
|
|
}
|
|
|
|
function addSectionDrops(myvue) {
|
|
// make sure our section drop targets are set up
|
|
// after catalog load or section add
|
|
|
|
// drop model or material into a section
|
|
var drops = document.getElementsByClassName('section-drop')
|
|
for (var i = 0; i < drops.length; ++i) {
|
|
if (!drops[i].getAttribute('drop-ready')) {
|
|
drops[i].setAttribute('drop-ready', true)
|
|
|
|
Sortable.create(drops[i], {
|
|
group: {
|
|
name: 'section-drops',
|
|
pull: false,
|
|
put: function(to, from) {
|
|
// don't allow drop on section where it already lives
|
|
let oldSectionID = myvue.selectedSection.id
|
|
let newSectionID = to.el.getAttribute('section-id')
|
|
if (Number(oldSectionID) === Number(newSectionID)) {
|
|
return false
|
|
}
|
|
|
|
// allow drop from anything but another section
|
|
return from.options.group.name !== 'sections'
|
|
},
|
|
},
|
|
animation: 150,
|
|
// (actual drop is handled in the originating list)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.selected {
|
|
background-color: purple;
|
|
}
|
|
|
|
.sortable-chosen {
|
|
color: black;
|
|
background-color: #fddd04;
|
|
}
|
|
|
|
.sortable-ghost {
|
|
background-color: #bababa;
|
|
}
|
|
|
|
.section-parent {
|
|
position: relative;
|
|
}
|
|
|
|
.section-drop {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 100%;
|
|
}
|
|
|
|
.list-item {
|
|
background-color: white;
|
|
border-bottom: 1px solid #ddd;
|
|
}
|
|
|
|
.list-hover {
|
|
background-color: #eee;
|
|
border-bottom: 1px solid #ccc;
|
|
}
|
|
|
|
.list-group {
|
|
background-color: #ccc;
|
|
min-height: 200px;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
}
|
|
</style>
|