Files
SPDM/src/components/common/dataFileTree/index.vue

328 lines
8.0 KiB
Vue
Raw Normal View History

2025-10-30 19:30:06 +08:00
<template>
<div class="comp-content">
<div class="content">
2025-11-06 10:51:33 +08:00
<div v-if="!hideTree" class="left-content" :class="{ hide: !isToggleShow }">
2025-10-30 19:30:06 +08:00
<div class="options">
<slot name="options" />
</div>
<div class="tree-data">
<el-tree
v-if="visible"
ref="treeRef"
node-key="id"
highlight-current
:load="loadMoreFun"
lazy
:props="{
2025-11-12 15:16:46 +08:00
label: 'originalName',
2025-10-30 19:30:06 +08:00
children: 'children',
isLeaf: 'leaf',
}"
2025-11-11 20:29:34 +08:00
v-bind="$attrs"
2025-10-30 19:30:06 +08:00
@node-click="nodeClickFun"
@current-change="currentChangeFun"
>
<template #default="{ data, node }">
<div class="tree-item">
<div class="name">
<div class="icon">
2025-11-26 18:11:50 +08:00
<el-icon :size="18">
<MessageBox v-if="data.relatedResourceUuidOwnType === NODE_TYPE.PROJECT" />
<Share v-else-if="data.relatedResourceUuidOwnType === NODE_TYPE.PHASE" />
2025-12-02 09:38:12 +08:00
<Document v-else-if="data.relatedResourceUuidOwnType === NODE_TYPE.TASK" />
2025-11-26 18:11:50 +08:00
<Folder v-else />
2025-11-07 18:42:09 +08:00
</el-icon>
2025-10-30 19:30:06 +08:00
</div>
2025-11-12 15:16:46 +08:00
<div class="label">{{ data.originalName }}</div>
2025-10-30 19:30:06 +08:00
</div>
<div class="actions">
<slot name="treeAction" :data="data" :node="node" />
</div>
</div>
</template>
</el-tree>
</div>
</div>
2025-11-06 10:51:33 +08:00
<div class="toggle-btn" :class="{ hide: !isToggleShow }" @click="toggleFun">
<el-icon :size="12">
<DArrowLeft />
</el-icon>
</div>
2025-10-30 19:30:06 +08:00
<div class="right-content">
2025-11-12 15:16:46 +08:00
<div class="top-content">
<div class="menu">
<el-breadcrumb separator="/">
2025-12-02 09:38:12 +08:00
<el-breadcrumb-item v-for="item in navList" :key="item.id" @click="openDirFun(item.id)">
2025-11-12 15:16:46 +08:00
{{ item.originalName }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="search" @click="searchFun">
2025-11-12 16:00:01 +08:00
<el-input v-model="searchData" :suffix-icon="Search" placeholder="搜索" size="small" clearable />
2025-11-12 15:16:46 +08:00
</div>
2025-10-30 19:30:06 +08:00
</div>
<div class="table">
<slot name="table" />
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
2025-11-26 18:11:50 +08:00
import { MessageBox, Share, Folder, DArrowLeft, Search, Document } from '@element-plus/icons-vue';
2025-11-07 18:42:09 +08:00
import { NODE_TYPE } from '@/utils/enum/node';
2025-10-30 19:30:06 +08:00
interface Props {
api: any;
hideTree?: boolean;
2025-11-07 09:16:43 +08:00
templateId: number;
2025-10-30 19:30:06 +08:00
}
const props = withDefaults(defineProps<Props>(), {
api: null,
hideTree: false,
2025-11-07 09:16:43 +08:00
templateId: 0,
2025-10-30 19:30:06 +08:00
});
2025-11-12 15:16:46 +08:00
const emit = defineEmits(['choseNode', 'updateNav', 'search']);
2025-10-30 19:30:06 +08:00
const treeRef = ref<any>();
const navList = ref<any>([]);
const visible = ref(true);
2025-11-06 10:51:33 +08:00
const isToggleShow = ref(true);
2025-11-12 16:00:01 +08:00
const searchData = ref<any>('');
2025-10-30 19:30:06 +08:00
2025-12-02 09:38:12 +08:00
watch(
() => props.templateId,
() => {
reloadFun();
}
);
2025-11-07 09:16:43 +08:00
2025-10-30 19:30:06 +08:00
// 加载节点
2025-12-02 09:38:12 +08:00
const loadMoreFun = async (node: any, resolve: any) => {
2025-11-07 09:16:43 +08:00
const listData: any = await getDataFun(node.data);
2025-10-30 19:30:06 +08:00
if (node.level >= 1) {
2025-11-12 15:16:46 +08:00
listData.forEach((item: any) => {
item.relatedParentUuid = node.data.relatedResourceUuid;
});
2025-10-30 19:30:06 +08:00
node.data.children = listData;
choseNodeFun(node.data);
}
return resolve(listData);
};
// 获取节点数据
2025-12-02 09:38:12 +08:00
const getDataFun = async (data: any) => {
2025-10-30 19:30:06 +08:00
if (props.api) {
2025-11-07 09:16:43 +08:00
const params = {
dimensionTemplateId: props.templateId,
2025-11-12 15:16:46 +08:00
fileId: data.id || '',
2025-11-07 09:16:43 +08:00
};
const res: any = await props.api(params);
2025-10-30 19:30:06 +08:00
if (res.code === 200) {
return res.data;
} else {
return [];
}
}
};
// 树形节点点击
const nodeClickFun = (data: any, node: any) => {
updateNavFun([]);
getTreeMenuFun(node);
choseNodeFun(data);
};
// 循环获取父节点
const getTreeMenuFun = (node: any) => {
if (node.label && node.parent) {
const data = navList.value;
data.unshift(node.data);
updateNavFun(data);
getTreeMenuFun(node.parent);
}
};
// 打开目录
const openDirFun = (id: any) => {
const node = treeRef.value.getNode(String(id));
if (node) {
node.loaded = false;
node.expand();
treeRef.value.setCurrentKey(id);
choseNodeFun(node.data);
}
};
// 返回上一级
const backFun = () => {
const data = navList.value[navList.value.length - 2];
openDirFun(data.id);
};
// 当前节点更改
const currentChangeFun = (data: any, node: any) => {
updateNavFun([]);
getTreeMenuFun(node);
};
// 选中节点
const choseNodeFun = (data: any) => {
emit('choseNode', data);
};
// 导航变更
const updateNavFun = (data: any) => {
navList.value = data;
emit('updateNav', data);
};
const reloadFun = () => {
2025-11-12 18:12:04 +08:00
navList.value = [];
2025-10-30 19:30:06 +08:00
visible.value = false;
setTimeout(() => {
visible.value = true;
}, 0);
};
2025-11-06 10:51:33 +08:00
const toggleFun = () => {
isToggleShow.value = !isToggleShow.value;
};
2025-11-12 15:16:46 +08:00
const searchFun = () => {
emit('search');
};
2025-12-01 09:49:34 +08:00
const reloadNodeFun = (id: any) => {
const node = treeRef.value.getNode(id);
if (node) {
node.loaded = false;
node.expand();
}
};
2025-10-30 19:30:06 +08:00
defineExpose({
backFun,
openDirFun,
reloadFun,
2025-12-01 09:49:34 +08:00
reloadNodeFun,
2025-10-30 19:30:06 +08:00
});
</script>
<style lang="scss" scoped>
.comp-content {
height: 100%;
.content {
2025-11-06 10:51:33 +08:00
position: relative;
2025-10-30 19:30:06 +08:00
height: 100%;
display: flex;
2025-11-06 10:51:33 +08:00
.toggle-btn {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 400px;
margin-top: -20px;
background-color: var(--el-bg-color);
border-radius: 0 4px 4px 0;
width: 14px;
height: 40px;
border: solid 1px var(--el-border-color-darker);
border-left: 0;
color: var(--el-text-color-regular);
cursor: pointer;
transition: all 0.3s;
&.hide {
left: -14px;
transform: rotateZ(180deg);
}
}
2025-10-30 19:30:06 +08:00
.left-content {
width: 400px;
overflow: auto;
margin-right: var(--margin-normal);
background-color: var(--el-bg-color);
border-radius: var(--border-radius-normal);
padding: var(--padding-normal);
2025-11-06 10:51:33 +08:00
border-right: solid 1px var(--el-border-color-darker);
transition: all 0.3s;
&.hide {
width: 0;
padding: 0;
margin: 0;
}
2025-10-30 19:30:06 +08:00
.tree-item {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 20px;
width: 0;
.name {
flex: 1;
display: flex;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
.icon {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
margin-right: var(--margin-tiny);
}
.label {
display: flex;
align-items: center;
min-height: 20px;
}
}
.actions {
padding-left: var(--padding-normal);
display: flex;
align-items: center;
min-height: 20px;
}
}
}
.right-content {
flex: 1;
overflow: auto;
background-color: var(--el-bg-color);
border-radius: var(--border-radius-normal);
2025-11-12 15:16:46 +08:00
padding: 0 var(--padding-normal) var(--padding-normal);
.top-content {
2025-10-30 19:30:06 +08:00
display: flex;
align-items: center;
2025-11-12 15:16:46 +08:00
padding: 10px 0;
margin-bottom: 10px;
border-bottom: solid 1px var(--el-border-color-light);
.menu {
flex: 1;
2025-11-12 16:00:01 +08:00
height: 24px;
2025-11-12 15:16:46 +08:00
background-color: var(--el-bg-color-page);
margin-right: 20px;
border-radius: 4px;
display: flex;
align-items: center;
padding: 0 10px;
}
.search {
2025-11-12 16:00:01 +08:00
height: 24px;
2025-11-12 15:16:46 +08:00
background-color: var(--el-bg-color-page);
border-radius: 4px;
display: flex;
align-items: center;
}
2025-10-30 19:30:06 +08:00
}
}
}
}
</style>