Files
svc-hall-front/src/components/TreeNode/index copy.vue
T

487 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<ul class="opera-ul">
<Tooltip content="新增节点" placement="top" transfer>
<li @click="showAddNode" :class="{ disabled: !nodePermissions.canCreate }">
<SvgIcon name="tree-icon-1" />
</li>
</Tooltip>
<Tooltip content="编辑节点" placement="top" transfer>
<li @click="showEditNode" :class="{ disabled: !nodePermissions.canUpdate }">
<SvgIcon name="tree-icon-2" />
</li>
</Tooltip>
<Tooltip content="移动节点" placement="top" transfer>
<li @click="showMoveNode" :class="{ disabled: !nodePermissions.canMove }">
<SvgIcon name="tree-icon-3" />
</li>
</Tooltip>
<Tooltip content="删除节点" placement="top" transfer>
<li @click="showDeleteNode" :class="{ disabled: !nodePermissions.canDelete }">
<SvgIcon name="tree-icon-4" />
</li>
</Tooltip>
</ul>
<Select class="mt-8" v-model="curSubJectId" placeholder="请选择学科">
<Option v-for="item in subjectComp" :value="item.k">{{ item.v }}</Option>
</Select>
<MyTree v-if="!treeLoading" ref="refMyTree" :autoClick="false" :treeData="treeData" :setting="treeSetting"
@on-tree-click="treeLink" />
<div class="modal-wrap">
<Modal v-model="editNodeModal.modal" :title="editNodeModal.title" width="450px" :mask-closable="false">
<Form ref="refFormData" :label-width="100" :model="editNodeModal" class="myform mb-20 mr-20">
<Form-Item label="当前位置:">
{{ curNodePath.join(' > ') }}
</Form-Item>
<Form-Item label="节点名称:" prop="name"
:rules="{ required: true, message: '请输入节点名称', trigger: 'blur' }">
<Input ref="refNodeNameInput" maxlength="30" v-model="editNodeModal.name" />
</Form-Item>
</Form>
<template #footer>
<Button @click="editNodeModal.modal = false">取消</Button>
<Button type="primary" :loading="editNodeModal.loading" @click="saveEditNode">确认</Button>
</template>
</Modal>
<Modal id="modal-sortTreeNode-id" class-name="up-dowm-components" v-model="showMoveModalStatus" title="移动节点"
:closable="false" :mask-closable="false" width="600">
<div class="fix">
<Alert class="fl">拖拽到目标节点时,确保节点是展开状态,以保证节点数据一致</Alert>
<Button class="fr" @click="sendReloadTree()">刷新节点树</Button>
</div>
<MyTree class="tree-div" ref="refSortMyTree" :autoClick="false" :treeData="moveTreeData"
:setting="moveTreeSetting" @on-tree-drag="onTreeDragMove" />
<template #footer>
<Button @click="showMoveModalStatus = false" style="margin-left: 20px">关闭</Button>
</template>
</Modal>
</div>
</div>
</template>
<script lang="ts" setup>
import SvgIcon from "@/components/SvgIcon.vue";
import MyTree from '@/components/MyTree.vue'
import { useDefaultStore } from "@/store";
import { RootNode } from "@/types";
import { cloneDeep, isEmpty } from "lodash";
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
import { get, last } from "lodash";
const props = defineProps<{
rootType: RootNode;
}>()
const emit = defineEmits<{
'on-change': [stage: number, subject: string, treeNode: any]
}>()
const curTreeNode = defineModel<any>('curTreeNode', { default: {} })
//学科学段
const curSubjectInfo = defineModel<any>('curSubjectInfo', {
default: {
stage: null,
subject: null
}
})
const store = useDefaultStore();
const { $utils } = useCurrentInstance();
const refMyTree = useTemplateRef('refMyTree');
const refFormData = useTemplateRef('refFormData')
const refNodeNameInput = useTemplateRef('refNodeNameInput')
const treeSetting = ref({
view: {
dblClickExpand: false,
showIcon: false,
},
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false,
drag: false,
},
check: {
enable: false,
},
callback: {},
})
const moveTreeSetting = ref({
view: { dblClickExpand: false, showIcon: true },
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false,
drag: {
isMove: true,
isCopy: false,
showArrow: true,
prev: true,
next: true,
inner: true,
autoExpandTrigger: true
}
},
check: {
enable: false
},
callback: {}
})
const showMoveModalStatus = ref(false)
const editNodeModal = reactive({
modal: false,
title: '',
loading: false,
name: null,
id: null,
})
const curSubJectId = ref<number | null>(null);
const subjectComp = computed(() => {
return store.getStageSubjects;
})
const paramsComp = computed(() => {
const find = subjectComp.value.find((item: any) => item.k == curSubJectId.value)
if (!find) return null;
else
return {
rootType: props.rootType,
stage: find.stage,
subject: find.code
}
})
const curNodePath = computed(() => {
if (!curTreeNode.value) return [];
let arr: any[] = curTreeNode.value.getPath().map((x: any) => x.name)
return arr;
})
const moveTreeData = computed(() => {
function formatTree(list: any[]): any[] {
return list
.map(node => {
const [, , canMove] = $utils.unpackPerms(node.permissions)
if (!canMove) return null
const copy = cloneDeep(node)
copy.drag = true
copy.children = copy.children?.length
? formatTree(copy.children)
: null
return copy
})
.filter(Boolean)
}
return formatTree(treeData.value)
})
const { loading: treeLoading, data: treeData, send: sendReloadTree, onSuccess: onNodeTreeSuccess } = useRequest(
() => Apis.NodeTree.getNodeTree({ params: paramsComp.value }),
{
initialData: [],
immediate: false,
})
watch(() => curSubJectId.value, async (val) => {
await nextTick();
curTreeNode.value = null;
curSubjectInfo.value.stage = paramsComp.value?.stage;
curSubjectInfo.value.subject = paramsComp.value?.subject;
if (!!val)
sessionStorage.setItem('bsch.learnmanage.cur_subject_id', val.toString())
sendReloadTree(-1);
})
onNodeTreeSuccess(() => reloadTree(-1))
onMounted(async () => {
await nextTick();
if (subjectComp.value.length > 0) {
let cacheStr = sessionStorage.getItem('bsch.learnmanage.cur_subject_id');
if (!!cacheStr) {
curSubJectId.value = Number(cacheStr);
}
else
curSubJectId.value = subjectComp.value[0].k;
}
})
async function reloadTree(id?: number) {
await nextTick();
console.log(id);
treeData.value.forEach((n: any) => (n.open = true));
if (!!curTreeNode.value && !!curTreeNode.value.id)
refMyTree.value?.reloadTree(curTreeNode.value.id)
else
refMyTree.value?.reloadTree(id)
}
function showAddNode() {
if (!nodePermissions.value.canCreate) return;
editNodeModal.title = '新增节点';
editNodeModal.modal = true;
editNodeModal.id = null;
editNodeModal.name = null;
nextTick().then(() => {
refNodeNameInput.value?.focus()
})
}
function showEditNode() {
if (!nodePermissions.value.canUpdate) return;
editNodeModal.title = '编辑节点';
editNodeModal.modal = true;
editNodeModal.id = curTreeNode.value.id;
editNodeModal.name = curTreeNode.value.name;
nextTick().then(() => {
refNodeNameInput.value.focus()
})
}
function showMoveNode() {
if (!nodePermissions.value.canMove) return;
showMoveModalStatus.value = true;
}
async function showDeleteNode() {
if (!nodePermissions.value.canDelete) return;
const temp = cloneDeep(curTreeNode.value);
const parentNode = temp.getParentNode();
Modal.confirm({
title: '删除知识树节点',
content: `确定删除名为【${curTreeNode.value.name}】的知识树节点记录?`,
onOk: async () => {
const id = curTreeNode.value.id;
await Apis.NodeTree.deleteNode({ params: { nodeId: id } })
Message.success('删除成功!');
curTreeNode.value = parentNode;
sendReloadTree()
}
});
}
async function saveEditNode() {
let isAdd = !!editNodeModal.id ? false : true;
const validate = await refFormData.value.validate();
if (!validate) {
Message.error('请填写红色星号内容!');
return;
}
const { id, name } = editNodeModal;
editNodeModal.loading = true;
if (isAdd) {
const parentId = get(curTreeNode.value, 'id', -1)
const brotherId = get(last(get(curTreeNode.value, 'children')), 'id', 0);
const params: any = {
rootType: props.rootType,
name, parentId, brotherId,
stage: paramsComp.value?.stage,
subject: paramsComp.value?.subject
};
await Apis.NodeTree.addNode({ params })
sendReloadTree()
}
else {
await Apis.NodeTree.updateNodeName({ params: { name, nodeId: id } })
sendReloadTree();
}
editNodeModal.loading = false;
editNodeModal.modal = false;
}
async function refreshMoveTree() {
// const id = selectedNode.value.id;
// await Apis.NodeTree.refreshSortTree({ params: { nodeId: id } })
// Message.success('刷新成功!');
// refTreeNode.value?.reloadTree()
}
//@ts-ignore
async function onTreeDragMove({ treeNodes, targetNode, moveType }) {
let mType = moveType == "inner" ? 3 : moveType == "prev" ? 1 : moveType == "next" ? 2 : 0;
let currentNode = treeNodes[0];
let nativeNode = currentNode;
const params = formatMoveTree(treeNodes[0], targetNode, mType);
await Apis.NodeTree.move({
params: params,
})
sendReloadTree();
}
function formatMoveTree(currentNode: any, targetNode: any, moveType: any) {
let nativeNode = currentNode;
let treeNode = targetNode;
let pathArr = treeNode.path.split(",");
let index2 = pathArr.findIndex((ele: any) => {
return ele == nativeNode.id;
});
if (index2 != -1) {
Message.warning("父节点无法移动到子节点下方");
return;
}
let newBrother = ""; //新兄长节点 【接口参数】
let newParent = ""; //新父节点 【接口参数】
console.log('treeNode', treeNode);
var parentNode = treeNode.getParentNode();
let chilList = !!parentNode ? parentNode.children : treeNode.children;
let index = chilList.findIndex((ele: any) => {
return ele.id == treeNode.id;
});
if (treeNode.id == nativeNode.id || (treeNode.id == nativeNode.parentId && moveType == 3)) {
//选中同一节点,无效移动
Message.warning("目标节点与选中节点冲突,请选择其他目标节点");
return;
} else if ((moveType == 1 || moveType == 2) && nativeNode.parentId == treeNode.parentId) {
if (moveType == 1) {
console.log('idnex:' + index);
index--;
//前面
newBrother = index == 0 ? 0 : chilList[index - 1].id;
} else {
//后面
newBrother = chilList[index].id;
}
newParent = "";
} else {
//跨父节点移动
if (moveType == 1) {
//选择的是前面
//前面
newBrother = index == 0 ? index : chilList[index - 1].id;
newParent = treeNode.parentId;
} else if (moveType == 2) {
//选择的是后面
//后面
newBrother = chilList[index].id;
newParent = treeNode.parentId;
} else {
//选择的是里面
//里面 选中的children里面的最后一个
newBrother = isEmpty(treeNode.children)
? 0
: treeNode.children[treeNode.children.length - 1].id;
newParent = treeNode.id;
}
}
return {
targetId: nativeNode.id,
newParent: newParent,
newBrother: newBrother,
}
}
async function treeLink(treeNode: any) {
const copyNode = cloneDeep(treeNode)
copyNode.children = [];
curTreeNode.value = copyNode;
// console.log('click', treeNode);
// console.log(copyNode.getPath().map((x: any) => x.name));
curSubjectInfo.value.stage = paramsComp.value?.stage;
curSubjectInfo.value.subject = paramsComp.value?.subject;
const { stage, subject } = curSubjectInfo.value;
emit('on-change', stage, subject, copyNode)
}
const nodePermissions = computed(() => {
if (!curTreeNode.value) return { canCreate: false, canUpdate: false, canMove: false, canDelete: false };
const [canCreate, canUpdate, canMove, canDelete] = $utils.unpackPerms(curTreeNode.value.permissions)
return {
canCreate,
canUpdate,
canMove,
canDelete,
}
})
async function onChangeSubject() { }
</script>
<style lang="scss">
.opera-ul {
display: flex;
justify-content: space-around;
align-items: center;
border-bottom: 1px solid #ebeef5;
padding-bottom: 10px;
li {
padding: 10px;
height: 38px;
border-radius: 50%;
cursor: pointer;
&.active,
&:hover {
background-color: #f5f5f5;
}
svg {
width: 18px;
height: 18px;
}
}
li.disabled {
cursor: not-allowed;
opacity: 0.4;
&:hover {
background-color: #fff;
}
}
}
#modal-sortTreeNode-id {
position: relative;
z-index: 1000;
height: 380px;
.tree-div {
z-index: 1001;
border: 1px solid #cacaca;
border-radius: 5px;
height: 300px;
}
.ztree {
margin-bottom: 20px;
}
}
</style>