4 changed files with 672 additions and 5 deletions
@ -0,0 +1,428 @@ |
|||
<template> |
|||
<div class="tree-wrapper"> |
|||
<div class="tree-filter" v-if="showInput"> |
|||
<el-input placeholder="请输入搜索关键字" v-model="filterText" maxlength="30" show-word-limit clearable></el-input> |
|||
<slot name="filter-btns"></slot> |
|||
</div> |
|||
<el-tree ref="tree" class="tree-main" :class="{ 'no-checkbox': noCheckbox }" :node-key="nodeKey" :data="data" |
|||
:props="defaultProps" :filter-node-method="filterNode" :default-expand-all="defaultExpandAll" |
|||
:emptyText="emptyText" :renderAfterExpand="renderAfterExpand" :checkStrictly="checkStrictly" |
|||
:expandOnClickNode="expandOnClickNode" :checkOnClickNode="checkOnClickNode" |
|||
:checkDescendants="checkDescendants" :autoExpandParent="autoExpandParent" |
|||
:defaultCheckedKeys="defaultCheckedKeys" :defaultExpandedKeys="defaultExpandedKeys" |
|||
:showCheckbox="showCheckbox" :lazy="lazy" :load="load" :draggable="draggable" :allowDrag="allowDrag" |
|||
:allowDrop="allowDrop" :highlightCurrent="highlightCurrent" :accordion="accordion" :indent="indent" |
|||
:iconClass="iconClass" :renderContent="renderContent" @node-click="handleNodeClick" |
|||
@node-expand="handleExpand" @node-collapse="handleCollapse"> |
|||
<template slot-scope="{ node, data }"> |
|||
<div class="custom-tree-node" :class="node.checked || node.indeterminate ? '' : 'opacity'"> |
|||
<div class="left"> |
|||
<!-- <iconpark-icon v-if="data && data[defaultProps.children]" class="icon" name="organization" |
|||
size="16"></iconpark-icon> --> |
|||
<slot v-bind="{ node, data }"></slot> |
|||
</div> |
|||
<div class="right"> |
|||
<slot name="right" v-bind="{ node, data }"></slot> |
|||
<span class="more" @mouseleave="moreMenuLeave"> |
|||
<slot name="more" v-bind="{ node, data, onMoreHandle }"></slot> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</el-tree> |
|||
<div class="more-menu-box" ref="moreMenuBox" v-show="isMoreMenuShow" @mouseleave="hideMoreMenu"> |
|||
<slot name="more-menu" v-bind="{ moreMenuData, hideMoreMenu }"></slot> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
let timer; |
|||
export default { |
|||
name: "tree", |
|||
props: { |
|||
data: { |
|||
type: Array, |
|||
default: () => [], |
|||
}, |
|||
emptyText: { |
|||
type: String, |
|||
default () { |
|||
return "暂无数据"; |
|||
}, |
|||
}, |
|||
renderAfterExpand: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
nodeKey: { |
|||
type: String, |
|||
default: "key", |
|||
}, |
|||
checkStrictly: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
defaultExpandAll: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
expandOnClickNode: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
checkOnClickNode: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
checkDescendants: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
autoExpandParent: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
defaultCheckedKeys: { |
|||
type: Array, |
|||
default: () => [], |
|||
}, |
|||
defaultExpandedKeys: { |
|||
type: Array, |
|||
default: () => [], |
|||
}, |
|||
currentNodeKey: [String, Number], |
|||
renderContent: Function, |
|||
showCheckbox: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
draggable: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
allowDrag: Function, |
|||
allowDrop: Function, |
|||
defaultProps: { |
|||
default () { |
|||
return { |
|||
children: "children", |
|||
label: "label", |
|||
isLeaf: "isLeaf", |
|||
}; |
|||
}, |
|||
}, |
|||
lazy: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
highlightCurrent: Boolean, |
|||
load: Function, |
|||
filterNodeMethod: Function, |
|||
accordion: Boolean, |
|||
indent: { |
|||
type: Number, |
|||
default: 18, |
|||
}, |
|||
iconClass: String, |
|||
noCheckbox: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
showInput: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}, |
|||
data () { |
|||
return { |
|||
filterText: "", |
|||
isMoreMenuShow: false, |
|||
moreMenuData: null, |
|||
moreMenuTriggered: false, |
|||
}; |
|||
}, |
|||
watch: { |
|||
filterText (val) { |
|||
this.$refs.tree.filter(val); |
|||
}, |
|||
}, |
|||
|
|||
mounted () { }, |
|||
methods: { |
|||
handleNodeClick (data, node, self) { |
|||
this.$emit("node-click", data, node, self); |
|||
}, |
|||
handleExpand (data) { |
|||
this.$emit("node-expand", data); |
|||
}, |
|||
handleCollapse (data) { |
|||
this.$emit("node-collapse", data); |
|||
}, |
|||
filterNode (value, data) { |
|||
if (!value || !data || !data[this.defaultProps.label]) return true; |
|||
if (this.filterNodeMethod) { |
|||
return this.filterNodeMethod.call(null, value, data); |
|||
} |
|||
return data[this.defaultProps.label].indexOf(value) !== -1; |
|||
}, |
|||
onMoreHandle (event, data) { |
|||
this.$set(this, "moreMenuData", data); |
|||
this.isMoreMenuShow = true; |
|||
this.moreMenuTriggered = true; |
|||
this.$nextTick(() => { |
|||
this.$refs.moreMenuBox.style.top = event.clientY + 20 + "px"; |
|||
this.$refs.moreMenuBox.style.left = |
|||
event.clientX - this.$refs.moreMenuBox.offsetWidth + 15 + "px"; |
|||
}); |
|||
}, |
|||
hideMoreMenu () { |
|||
clearTimeout(timer); |
|||
timer = setTimeout(() => { |
|||
this.isMoreMenuShow = false; |
|||
}, 600); |
|||
}, |
|||
moreMenuLeave () { |
|||
if (this.moreMenuTriggered) { |
|||
clearTimeout(timer); |
|||
timer = setTimeout(() => { |
|||
this.isMoreMenuShow = false; |
|||
this.moreMenuTriggered = false; |
|||
}, 300); |
|||
} |
|||
}, |
|||
toggleShow (node, data, keyName) { |
|||
const isShow = !data[keyName]; |
|||
node.data[keyName] = isShow; |
|||
if (node.data.children) { |
|||
const traverse = function (arr) { |
|||
for (let i = 0; i < arr.length; i++) { |
|||
arr[i][keyName] = isShow; |
|||
if (arr[i].children) { |
|||
traverse(arr[i].children); |
|||
} |
|||
} |
|||
}; |
|||
traverse(node.data.children); |
|||
} |
|||
let tempNode = node.parent; |
|||
let tempTreeData = []; |
|||
while (tempNode) { |
|||
tempTreeData = tempNode.data; |
|||
if ( |
|||
tempTreeData.children && |
|||
tempTreeData.children.every((f) => f[keyName] === isShow) |
|||
) { |
|||
tempTreeData[keyName] = isShow; |
|||
} |
|||
tempNode = tempNode.parent; |
|||
} |
|||
tempTreeData = JSON.parse(JSON.stringify(tempTreeData)); |
|||
return tempTreeData; |
|||
}, |
|||
getCheckedKeys (leafOnly) { |
|||
return this.$refs?.tree?.getCheckedKeys(leafOnly); |
|||
}, |
|||
setCheckedKeys (keys, leafOnly) { |
|||
this.$refs?.tree?.setCheckedKeys(keys, leafOnly); |
|||
}, |
|||
getCheckedNode (leafOnly) { |
|||
return this.$refs?.tree?.getCheckedNodes(leafOnly); |
|||
}, |
|||
getNode (data) { |
|||
return this.$refs?.tree?.getNode(data); |
|||
}, |
|||
setChecked (key, checked, deep) { |
|||
this.$refs?.tree?.setChecked(key, checked, deep); |
|||
}, |
|||
updateKeyChildren (key, data) { |
|||
this.$refs?.tree?.updateKeyChildren(key, data); |
|||
}, |
|||
}, |
|||
beforeDestroy () { }, |
|||
}; |
|||
</script> |
|||
<style lang="scss" scoped> |
|||
.tree-wrapper { |
|||
padding: 12px 0; |
|||
min-height: 350px; |
|||
|
|||
::v-deep.tree-filter { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 0 16px; |
|||
margin-bottom: 8px; |
|||
|
|||
.el-input__inner, |
|||
.el-textarea__inner { |
|||
// color: #fff; |
|||
|
|||
&::placeholder { |
|||
color: rgba(255, 255, 255, 0.35); |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
|
|||
.el-input__count .el-input__count-inner { |
|||
background: transparent; |
|||
} |
|||
|
|||
.el-input__inner { |
|||
//background-color: transparent; |
|||
border-color: transparent; |
|||
} |
|||
|
|||
.is-disabled { |
|||
background-color: transparent; |
|||
} |
|||
} |
|||
|
|||
::v-deep .el-input { |
|||
.el-input__inner { |
|||
height: 32px; |
|||
line-height: 32px; |
|||
background-color: #444550; |
|||
color: rgb(38, 38, 38); |
|||
border: none; |
|||
padding-left: 8px; |
|||
} |
|||
|
|||
.el-input__count-inner { |
|||
background: #444550; |
|||
color: rgba(255, 255, 255, 0.35); |
|||
} |
|||
|
|||
.el-input__icon { |
|||
line-height: 28px; |
|||
} |
|||
} |
|||
|
|||
::v-deep.tree-main { |
|||
background: none; |
|||
padding: 0 16px; |
|||
|
|||
.el-tree-node__content { |
|||
height: 34px; |
|||
line-height: 34px; |
|||
margin-bottom: 4px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
.el-tree-node:focus>.el-tree-node__content, |
|||
.el-tree-node__content:hover { |
|||
background: #ebf7f5; |
|||
color: rgb(54, 178, 158) !important; |
|||
// border-right: 3px solid #36b29e; |
|||
} |
|||
|
|||
//.el-tree-node__expand-icon { |
|||
// color: rgba(255, 255, 255, 0.55); |
|||
// } |
|||
|
|||
.el-tree-node__expand-icon.is-leaf { |
|||
color: transparent; |
|||
cursor: default; |
|||
} |
|||
|
|||
.custom-tree-node { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
// color: rgb(38, 38, 38); |
|||
// width: 100%; |
|||
// padding-right: 8px; |
|||
font-family: "思源黑体"; |
|||
font-size: 14px; |
|||
font-weight: normal; |
|||
letter-spacing: 0em; |
|||
flex: 1; |
|||
|
|||
.left, |
|||
.right { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.icon { |
|||
margin-right: 8px; |
|||
} |
|||
|
|||
.name { |
|||
// flex: 1; |
|||
max-width: 120px; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.btn-item { |
|||
margin-right: 9px; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
&:hover { |
|||
background: rgba(255, 255, 255, 0.16); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.custom-tree-node.opacity { |
|||
// opacity: 0.5; |
|||
} |
|||
|
|||
&.no-checkbox { |
|||
.el-tree-node__content { |
|||
.el-checkbox { |
|||
display: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.more-menu-box { |
|||
position: fixed; |
|||
background-color: #4d4f5b; |
|||
border-radius: 4px; |
|||
z-index: 1000; |
|||
padding: 8px; |
|||
border: 0.5px solid rgba(255, 255, 255, 0.16); |
|||
box-shadow: 0px 3px 14px 2px rgba(0, 0, 0, 0.05), |
|||
0px 8px 10px 1px rgba(0, 0, 0, 0.06), 0px 5px 5px -3px rgba(0, 0, 0, 0.1); |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 4px; |
|||
flex-grow: 1; |
|||
|
|||
.menu-item { |
|||
min-width: 104px; |
|||
height: 28px; |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
padding: 3px 8px; |
|||
gap: 8px; |
|||
align-self: stretch; |
|||
border-radius: 4px; |
|||
font-family: "思源黑体"; |
|||
font-size: 14px; |
|||
font-weight: normal; |
|||
line-height: 22px; |
|||
letter-spacing: 0em; |
|||
color: rgb(38, 38, 38); |
|||
cursor: pointer; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, 0.1216); |
|||
} |
|||
|
|||
&.red { |
|||
color: #d54941; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,70 @@ |
|||
<template> |
|||
<div class="forecast-detail-wrapper"> |
|||
<div class="detail-title">预报详情</div> |
|||
<div class="select-content"> |
|||
<span>预报类型</span> |
|||
<el-select v-model="selectValue" placeholder="请选择"> |
|||
<el-option v-for="item in selectOptions" :key="item.value" :label="item.label" :value="item.value"> |
|||
</el-option> |
|||
</el-select> |
|||
<el-radio-group v-model="radioValue"> |
|||
<el-radio v-for="item in radioOptions" :key="item.label" :label="item.label">{{ item.name }}</el-radio> |
|||
</el-radio-group> |
|||
</div> |
|||
<div class="analysis-content"> |
|||
<div class="echarts-content" id="chart"></div> |
|||
<div class="warn-analysis"> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data () { |
|||
return { |
|||
selectOptions: [{ |
|||
value: '1', |
|||
label: '工程水位预报' |
|||
}, { |
|||
value: '2', |
|||
label: '河道水位预报' |
|||
}, { |
|||
value: '3', |
|||
label: '工程降雨量预报' |
|||
}, { |
|||
value: '4', |
|||
label: '水库出库流量预报' |
|||
}, { |
|||
value: '5', |
|||
label: '流域来水量预报' |
|||
}, { |
|||
value: '6', |
|||
label: '河道流量预报' |
|||
}], |
|||
selectValue: '1', |
|||
radioOptions: [{ |
|||
label: 1, |
|||
name: '飞来峡水库' |
|||
}, { |
|||
label: 2, |
|||
name: '龙潭水库' |
|||
}], |
|||
radioValue: 1 |
|||
}; |
|||
}, |
|||
methods: { |
|||
handleNodeClick (data) { |
|||
console.log(data); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
<style lang="scss" scoped> |
|||
.forecast-detail-wrapper { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
</style> |
@ -1,3 +1,164 @@ |
|||
<template> |
|||
<div>预警信息管理</div> |
|||
<div class="warn-wrapper"> |
|||
<!-- 预警信息管理 --> |
|||
<Tree :data="treeData" :defaultProps="defaultProps" :showInput="false" :default-checked-keys="defaultCheckedKeys" |
|||
show-checkbox no-checkbox node-key="id" ref="warnTreeRef" class="warn-tree"> |
|||
<template v-slot:default="{ node, data }"> |
|||
<span class="name">{{ data.name }}</span> |
|||
</template> |
|||
<template v-slot:right="{ node, data }"> |
|||
<el-dropdown @command="handleCommand($event, data)" v-if="data && !data.children"> |
|||
<span class="btn-item"> |
|||
<i class="el-icon-more"></i> |
|||
</span> |
|||
<template #dropdown> |
|||
<el-dropdown-menu class="dropdown-menu"> |
|||
<el-dropdown-item class="right-menu" command="infoSetting"> |
|||
预演信息配置 |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</template> |
|||
</el-dropdown> |
|||
</template> |
|||
|
|||
</Tree> |
|||
<forecastDetail></forecastDetail> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import forecastDetail from './components/forecastDetail.vue' |
|||
import Tree from './components/Tree.vue' |
|||
export default { |
|||
components: { Tree, forecastDetail }, |
|||
data () { |
|||
return { |
|||
treeData: [ |
|||
{ |
|||
"id": "1752932766908338178", |
|||
"parentId": "root", |
|||
"name": "全部", |
|||
"userId": 1, |
|||
"children": [ |
|||
{ |
|||
"id": "1759857493740810240", |
|||
"parentId": "1752932766908338178", |
|||
"name": "2024年预报方案", |
|||
"userId": 1, |
|||
"children": [ |
|||
{ |
|||
"id": "1759858444149125122", |
|||
"name": "4月12号", |
|||
"level": 2, |
|||
"children": [ |
|||
{ |
|||
"id": "1759858444149125142", |
|||
"name": "预报方案1", |
|||
"level": 3 |
|||
}, |
|||
{ |
|||
"id": "1759458444149125142", |
|||
"name": "预报方案2", |
|||
"level": 3 |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"id": "1776817687412244481", |
|||
"name": "4月13号", |
|||
"level": 2, |
|||
"children": [ |
|||
{ |
|||
"id": "1759858444142125142", |
|||
"name": "预报方案1", |
|||
"level": 3 |
|||
}, |
|||
{ |
|||
"id": "1759468444149125142", |
|||
"name": "预报方案2", |
|||
"level": 3 |
|||
} |
|||
] |
|||
} |
|||
], |
|||
"level": 1 |
|||
}, |
|||
{ |
|||
"id": "1759857493700810240", |
|||
"parentId": "1752932766908338178", |
|||
"name": "2023年预报方案", |
|||
"userId": 1, |
|||
"children": [ |
|||
{ |
|||
"id": "1759858444109125122", |
|||
"name": "4月15号", |
|||
"level": 2, |
|||
"children": [ |
|||
{ |
|||
"id": "1759858484149125142", |
|||
"name": "预报方案1", |
|||
"level": 3 |
|||
}, |
|||
{ |
|||
"id": "1759458444142125142", |
|||
"name": "预报方案2", |
|||
"level": 3 |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"id": "1776817687412244481", |
|||
"name": "4月17号", |
|||
"level": 2, |
|||
"children": [ |
|||
{ |
|||
"id": "1759858544142125142", |
|||
"name": "预报方案1", |
|||
"level": 3 |
|||
}, |
|||
{ |
|||
"id": "1759468444749125142", |
|||
"name": "预报方案2", |
|||
"level": 3 |
|||
} |
|||
] |
|||
} |
|||
], |
|||
"level": 1 |
|||
} |
|||
], |
|||
"level": 0 |
|||
} |
|||
], |
|||
defaultProps: { |
|||
children: "children", |
|||
label: "name", |
|||
// isLeaf: "isLeaf", |
|||
}, |
|||
defaultCheckedKeys: [], |
|||
draw: null, |
|||
_poiTreeData: {}, |
|||
checkedKeys: [], |
|||
entityFeatures: [], |
|||
childArr: [], |
|||
}; |
|||
}, |
|||
methods: { |
|||
handleCommand (node, data) { |
|||
console.log(node, data, 'node, data'); |
|||
} |
|||
}, |
|||
}; |
|||
</script> |
|||
<style lang="scss" scoped> |
|||
.warn-wrapper { |
|||
width: 100%; |
|||
height: 100%; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.warn-tree { |
|||
width: 350px !important; |
|||
background-color: aliceblue; |
|||
} |
|||
</style> |
|||
|
Loading…
Reference in new issue