Skip to content

Instantly share code, notes, and snippets.

@dansp89
Last active February 29, 2024 12:47
Show Gist options
  • Save dansp89/1e9f5b9a8c30ee1cd3e4b7adca0d1be1 to your computer and use it in GitHub Desktop.
Save dansp89/1e9f5b9a8c30ee1cd3e4b7adca0d1be1 to your computer and use it in GitHub Desktop.
Componente VUE3 para criar Gestão de aulas, Módulos - Aulas,
<template>
<el-button type="primary" @click="addModule">Adicionar Módulo</el-button>
<el-tree
:data="treeData"
draggable
default-expand-all
node-key="id"
:allow-drag="allowDrag"
:allow-drop="allowDrop"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
>
<template #default="{ node, data }">
<div
style="
display: flex;
align-items: center;
justify-content: space-between;
"
>
<span>{{ node.label }}</span>
<!-- Mostrar botão de excluir para aulas -->
<el-button
v-if="data.type === 'lesson'"
:text="true"
icon="el-icon-delete"
@click.stop="deleteNode(data.id, data.type)"
>
x
</el-button>
<!-- Mostrar botão editar aulas -->
<el-button v-if="data.type === 'lesson'" :text="true" icon="el-icon-">
Editar
</el-button>
<!-- Mostrar botão de excluir para módulos sem aulas -->
<el-button
v-if="
data.type === 'module' &&
(!data.children || data.children.length === 0)
"
:text="true"
icon="el-icon-delete"
@click.stop="deleteNode(data.id, data.type)"
>
X
</el-button>
<!-- Botão para adicionar aula, visível apenas para módulos -->
<el-button
v-if="data.type === 'module'"
:text="true"
icon="el-icon-plus"
@click.stop="addLesson(data.id)"
>
+
</el-button>
</div>
</template>
</el-tree>
</template>
<script lang="ts" setup>
/**
* @source <https://element-plus.org/en-US/component/tree.html#draggable>
*/
import { ref } from "vue";
import type Node from "element-plus/es/components/tree/src/model/node";
import type { DragEvents } from "element-plus/es/components/tree/src/model/useDragNode";
import type {
AllowDropType,
NodeDropType
} from "element-plus/es/components/tree/src/tree.type";
import { nanoid } from "nanoid";
const treeData = ref([
{
id: "module-1",
label: "Módulo 1",
type: "module",
children: [
{
id: "lesson-1",
label: "Aula 1",
type: "lesson"
},
{
id: "lesson-2",
label: "Aula 2",
type: "lesson"
}
]
},
{
id: "module-2",
label: "Módulo 2",
type: "module",
children: [
{
id: "lesson-3",
label: "Aula 3",
type: "lesson"
},
{
id: "lesson-4",
label: "Aula 4",
type: "lesson"
}
]
}
]);
const allowDrop = (draggingNode: Node, dropNode: Node, type: AllowDropType) => {
// Ajuste para permitir que módulos sejam reordenados entre si.
if (
draggingNode.data.type === "module" &&
dropNode.data.type === "module" &&
(type === "prev" || type === "next")
) {
return true;
}
// Permitir mover aulas apenas dentro de módulos ou entre módulos, mas não permitir que sejam pais (não podem ter filhos).
if (draggingNode.data.type === "lesson") {
// Permitir se o destino for um módulo e a aula está sendo movida para dentro dele (como filha).
if (dropNode.data.type === "module" && type === "inner") {
return true;
}
// Permitir mover aula para o mesmo nível dentro de outro módulo ou dentro do mesmo módulo (prev ou next, mas não dentro de outra aula).
if (
dropNode.data.type === "lesson" &&
(type === "prev" || type === "next")
) {
return true;
}
}
return false; // Não permite outros casos, incluindo aulas sendo pais.
};
const allowDrag = (draggingNode: Node) => {
// Todos os nós podem ser arrastados, mas as restrições de onde podem ser soltos são definidas em allowDrop.
return true;
};
const handleDragStart = (node: Node, ev: DragEvents) => {
console.log("drag start", node);
};
const handleDragEnter = (
draggingNode: Node,
dropNode: Node,
ev: DragEvents
) => {
console.log("tree drag enter:", dropNode.label);
};
const handleDragLeave = (
draggingNode: Node,
dropNode: Node,
ev: DragEvents
) => {
console.log("tree drag leave:", dropNode.label);
};
const handleDragOver = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
console.log("tree drag over:", dropNode.label);
};
const handleDragEnd = (
draggingNode: Node,
dropNode: Node,
dropType: NodeDropType,
ev: DragEvents
) => {
console.log("tree drag end:", dropNode && dropNode.label, dropType);
};
const handleDrop = (
draggingNode: Node,
dropNode: Node,
dropType: NodeDropType,
ev: DragEvents
) => {
console.log("tree drop:", dropNode.label, dropType);
// Aqui você deve implementar a lógica para atualizar a estrutura de dados conforme a nova posição do nó arrastado.
};
const deleteNode = (nodeId, nodeType) => {
// Função genérica para encontrar e excluir o nó
const findAndDelete = (nodes, id) =>
nodes.filter((node) => {
if (node.id === id) {
return false; // Exclui o nó
}
if (node.children) {
node.children = findAndDelete(node.children, id); // Procura recursivamente
}
return true;
});
if (nodeType === "module") {
// Excluir o módulo se não tiver aulas
treeData.value = findAndDelete(treeData.value, nodeId);
} else if (nodeType === "lesson") {
// Excluir a aula
treeData.value.forEach((module) => {
if (module.children) {
module.children = findAndDelete(module.children, nodeId);
}
});
}
};
const addModule = () => {
const newModule = {
id: nanoid(), // Gerar um ID único para o novo módulo
label: `Módulo ${treeData.value.length + 1}`,
type: "module",
children: []
};
treeData.value.push(newModule);
};
const addLesson = (moduleId) => {
const newLesson = {
id: nanoid(), // Gerar um ID único para a nova aula
label: `Aula Nova`,
type: "lesson"
};
const module = treeData.value.find((module) => module.id === moduleId);
if (module) {
if (!module.children) {
module.children = [];
}
module.children.push(newLesson);
}
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment