vue-tree-color 组件实现组织架构图遇到的坑和解决方案以及实现
2023-12-13 05:17:03
2、安装完 vue-tree-color 和 less less-loader 后启动项目,报错,两种情况,一种是less 版本问题(less 使用 3.9.0) 和 autoprefixer 版本问题(使用 7.1.6)
3、进入开发,主要是样式问题了(先看看最终效果)
4、并不是单纯的展示数据而已,还要操作,自定义样式,按钮权限等
// index.vue
<template>
<div v-loading="loading" class="culture_box" :style="{ transform: scale }" @mousewheel="handleMouseWheel">
<vue2-org-tree v-if="isShow" :data="treeData" :render-content="renderContent" :props="props" collapsable @on-expand="onExpand" />
<el-dialog :title="popTitle" append-to-body :visible.sync="addPop" width="30%" :close-on-click-modal="false" @close="closeDialog">
<el-form ref="editForm" label-width="120px" :model="editForm" :rules="rules">
<el-form-item label="部(所)名称" prop="deptName" class="add_form_item">
<el-input v-model="editForm.deptName" :maxlength="10" auto-complete="off" :disabled="type == 3" placeholder="请输入部(所)名称" />
</el-form-item>
<el-form-item label="文化路径展示" class="add_form_item">
<el-upload
v-if="type === 1 || type === 2"
ref="uploadImg"
class="avatar-uploader"
:show-file-list="false"
action="/tk/api/icomx-resource/oss/endpoint/put-file-attach"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="editForm.photographs !== ''" style="width: 100px;" :src="editForm.photographs" alt="">
<i v-else class="el-icon-plus upload_plus" />
</el-upload>
<el-image v-else style="width: 100px;" :src="editForm.photographs" alt="" :preview-src-list="[editForm.photographs]" />
<div v-if="(type === 2 || type === 1) && editForm.photographs != ''" class="btn_img">
<el-button @click="delImg">删除</el-button>
<el-button @click="changeImg">更换</el-button>
</div>
</el-form-item>
<el-form-item label="部(所)简介" class="add_form_item">
<el-input v-model="editForm.deptDescribe" type="textarea" auto-complete="off" :disabled="type == 3" placeholder="请输入部(所)简介" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="closeDialog">{{ type === 3? '关闭': '取消' }}</el-button>
<el-button v-if="type === 1 || type === 2" type="primary" class="title" :loading="saveLoading" @click="handleSave">保存</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
</template>
<script>
import { getTreeData, getTreeAdd, getTreeEdit, getTreeDel } from '@/api/culture/index.js'
export default {
data() {
return {
treeData: {},
props: {
label: 'deptName',
children: 'children',
expand: 'expand'
},
isShow: false,
imgUrl: '',
dialogVisible: false,
dialogImageUrl: '',
type: 1, // 新增修改详情参数
addPop: false,
editForm: {
deptName: '',
photographs: '',
deptDescribe: ''
},
saveLoading: false,
rules: {
deptName: [
{ required: true, message: '请输入部(所)名称', trigger: 'blur' }
]
},
scaleRatio: 1,
loading: false,
popTitle: ''
}
},
computed: {
scale() {
return `scale(${this.scaleRatio})`
}
},
created() {
this.init()
},
methods: {
// 初始化数据
async init() {
this.loading = true
let res = await getTreeData()
this.loading = false
if (res.data.code === 200) {
this.treeData = res.data.data[0]
this.toggleExpand(this.treeData, true)
this.isShow = true
}
},
// 自定义事件
handleEdit(data, type) {
this.type = type
this.addPop = true
this.editForm = { ...data }
this.popTitle = this.type === 1 ? data.deptName + '新增' : this.type === 2 ? data.deptName + '编辑' : data.deptName + '详情'
// 新增清空项
if (type === 1) {
this.editForm.deptName = ''
this.editForm.photographs = ''
this.editForm.deptDescribe = ''
}
},
// 删除某节点
handleDel(data) {
this.$confirm('确认是否删除该部(所)?', '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
return getTreeDel(data.id).then(() => {
this.init()
this.$message({
type: 'success',
message: '操作成功!'
})
})
}).catch(() => {
})
},
// 渲染节点
renderContent(h, data) {
return h('div', { class: 'tree_box' }, [
h('div', { class: 'tree_title' }, [
h('span', {}, data.deptName)
]),
h('div', { class: 'tree_content' }, [
h('div', { class: 'culture_show' }, [
h('span', '文化路径展示'),
h('el-image', {
attrs: {
src: data.photographs,
alt: '',
class: 'img_box'
},
props: {
'preview-src-list': [data.photographs] // 添加preview-src-list属性
}
})
]),
h('div', { class: 'des_box' }, [
h('span', '部(所)简介'),
h('el-input', {
attrs: {
type: 'textarea',
disabled: true
},
props: {
'value': [data.deptDescribe]
}
})
])
]),
h('div', { class: 'tree_btn' }, [
h('i', {
class: 'el-icon-edit',
on: {
click: () => this.handleEdit(data, 2)
}}
),
h('span', {
on: {
click: () => this.handleEdit(data, 3)
}
}, '详情'),
h('span', {
on: {
click: () => this.handleEdit(data, 1)
}
}, '新增下级')
]),
h('div', { class: 'del_btn' }, [
h('i', {
class: 'el-icon-close',
style: {
display: data.parentId === '0' ? 'none' : 'inline-block'
},
on: {
click: () => this.handleDel(data)
}}
)
])
])
},
// 默认展开还是收起 -- 第一个参数是data,第二个参数是全部展开或否
toggleExpand(data, val) {
if (Array.isArray(data)) {
data.forEach(item => {
this.$set(item, 'expand', val)
if (item.children) {
this.toggleExpand(item.children, val)
}
})
} else {
this.$set(data, 'expand', val)
if (data.children) {
this.toggleExpand(data.children, val)
}
}
},
collapse(list) {
list.forEach(child => {
if (child.expand) {
child.expand = false
}
child.children && this.collapse(child.children)
})
},
// 收起展开
onExpand(e, data) {
if ('expand' in data) {
data.expand = !data.expand
if (!data.expand && data.children) {
this.collapse(data.children)
}
} else {
this.$set(data, 'expand', true)
}
},
// 弹窗保存
async handleSave() {
this.$refs.editForm.validate(async(valid) => {
if (valid) {
this.saveLoading = true
// 判断新增或是修改
let res
if (this.type === 1) {
this.editForm.parentId = this.editForm.id
delete this.editForm.id
res = await getTreeAdd(this.editForm)
}
if (this.type === 2) {
res = await getTreeEdit(this.editForm)
}
this.saveLoading = false
if (res.data.code === 200) {
this.$nextTick(() => {
this.$refs.editForm.resetFields()
})
this.$message.success(this.type === 1 ? '新增成功!' : '修改成功!')
this.addPop = false
this.init()
} else {
this.$message.error(res.data.msg)
}
} else {
return false
}
})
},
// 弹窗关闭
closeDialog() {
this.$nextTick(() => {
this.$refs.editForm.resetFields()
})
this.addPop = false
},
// 上传成功
handleAvatarSuccess(res, file) {
// console.log(res, file)
if (res.code === 200) {
// this.editForm.photographs = URL.createObjectURL(file.raw)
this.editForm.photographs = res.data.link
}
this.$refs.uploadImg.clearFiles()
},
// 上传前
beforeAvatarUpload(file) {
// const isJPG = file.type === 'image/jpeg'
// const isLt2M = file.size / 1024 / 1024 < 2
// if (!isJPG) {
// this.$message.error('上传头像图片只能是 JPG 格式!')
// }
// if (!isLt2M) {
// this.$message.error('上传头像图片大小不能超过 2MB!')
// }
// return isJPG && isLt2M
},
// 弹窗文化路径展示删除
delImg() {
this.editForm.photographs = ''
},
// 更换
changeImg() {
// 触发上传
this.$nextTick(() => {
this.$refs.uploadImg.$children[0].$refs.input.click()
})
},
// 鼠标滚动事件(wheelDelta值上滚为负下滚为正)
handleMouseWheel(e) {
// 同时按下shift键
if (e.wheelDelta > 0 && e.shiftKey === true) {
this.decreaseScale()
}
if (e.wheelDelta < 0 && e.shiftKey === true) {
this.increaseScale()
}
},
// 放大
increaseScale() {
this.scaleRatio += 0.1
},
// 缩小
decreaseScale() {
if (this.scaleRatio > 0.2) {
this.scaleRatio -= 0.1
}
}
}
}
</script>
<style lang="less">
@import './tree';
</style>
6、重点代码是渲染节点的方法,如果加按钮权限,则是下面的代码
import { mapGetters } from 'vuex'
computed: {
...mapGetters(['permission']),
scale() {
return `scale(${this.scaleRatio})`
},
// 按钮权限
permissionList() {
return {
addBtn: this.vaildData(this.permission.businessCulture_add, false),
viewBtn: this.vaildData(this.permission.businessCulture_view, false),
delBtn: this.vaildData(this.permission.businessCulture_remove, false),
editBtn: this.vaildData(this.permission.businessCulture_edit, false)
}
}
},
methods:{
// 渲染节点
renderContent(h, data) {
const btnElements = []
const delElements = []
// 根据权限显隐
if (this.permissionList.editBtn) {
btnElements.push(
h('i', {
class: 'el-icon-edit',
on: {
click: () => this.handleEdit(data, 2)
}
})
)
}
if (this.permissionList.viewBtn) {
btnElements.push(
h('span', {
on: {
click: () => this.handleEdit(data, 3)
}
}, '详情')
)
}
if (this.permissionList.addBtn) {
btnElements.push(
h('span', {
on: {
click: () => this.handleEdit(data, 1)
}
}, '新增下级')
)
}
if (this.permissionList.delBtn) {
delElements.push(
h('i', {
class: 'el-icon-close',
style: {
display: data.parentId === '0' ? 'none' : 'inline-block'
},
on: {
click: () => this.handleDel(data)
}}
)
)
}
return h('div', { class: 'tree_box' }, [
h('div', { class: 'tree_title' }, [
h('span', {}, data.deptName)
]),
h('div', { class: 'tree_content' }, [
h('div', { class: 'culture_show' }, [
h('span', '文化路径展示'),
h('el-image', {
attrs: {
src: data.photographs,
alt: '',
class: 'img_box'
},
props: {
'preview-src-list': [data.photographs] // 添加preview-src-list属性
}
})
]),
h('div', { class: 'des_box' }, [
h('span', '部(所)简介'),
h('el-input', {
attrs: {
type: 'textarea',
disabled: true
},
props: {
'value': [data.deptDescribe]
}
})
])
]),
h('div', { class: 'tree_btn' }, btnElements),
h('div', { class: 'del_btn' }, delElements)
])
}
}
7、less 代码也贴贴
// tree.less
.culture_box {
// width: calc(100vw - 240px);
height: calc(100vh - 122px);
overflow-x: auto;
overflow-y: auto;
}
.tree_box {
width: 100%;
font-size: 14px;
display: flex;
flex-direction: column;
.tree_title {
width: 100%;
font-weight: 600;
margin-bottom: 10px;
span {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.tree_content {
.culture_show {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-bottom: 10px;
.el-image {
width: 170px;
height: 50px;
margin-top: 4px;
}
}
.des_box {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-bottom: 10px;
.el-textarea {
font-size: 14px;
margin-top: 4px;
background: #f2f2f2;
}
}
}
.tree_btn {
display: flex;
justify-content: space-around;
align-items: center;
.el-icon-edit {
cursor: pointer;
}
span {
cursor: pointer;
text-decoration: underline;
}
}
.del_btn {
position: absolute;
top: 2px;
right: 4px;
font-size: 16px;
cursor: pointer;
}
.avatar {
width: 100px;
}
.upload_plus {
font-size: 30px;
}
}
.org-tree-node-label {
width: 200px;
}
磕磕碰碰才是人生哈
文章来源:https://blog.csdn.net/agua001/article/details/134869760
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!