绘制电脑治理信息页面

This commit is contained in:
guanj
2026-05-27 10:10:19 +08:00
parent 17e47c1f07
commit 7bcc68a9df
35 changed files with 2910 additions and 1492 deletions

View File

@@ -0,0 +1,533 @@
<template xlang="wxml">
<view class="tki-tree">
<view class="tki-tree-mask" :class="{ show: showTree }" @tap="_cancel"></view>
<view class="tki-tree-cnt" :class="{ show: showTree }">
<view class="tki-tree-bar">
<view class="tki-tree-bar-cancel" :style="{ color: cancelColor }" hover-class="hover-c" @tap="_cancel"
>取消</view
>
<view class="tki-tree-bar-title" :style="{ color: titleColor }">{{ title }}</view>
<view
class="tki-tree-bar-confirm"
:style="{ color: confirmColor }"
hover-class="hover-c"
@tap="_confirm"
>确定</view
>
</view>
<view class="tki-tree-bar1">
<uni-search-bar
class="uni-input"
radius="5"
placeholder="请输入关键字搜索"
clearButton="none"
@input="input"
/>
<!-- <uni-search-bar
v-model="searchValue"
clearButton="none"
bgColor="#fff"
placeholder="请输入关键词"
@input="input"
></uni-search-bar> -->
</view>
<view class="tki-tree-view">
<scroll-view class="tki-tree-view-sc" :scroll-y="true">
<block v-for="(item, index) in treeList" :key="index">
<view
class="tki-tree-item"
:style="[
{
paddingLeft: item.rank * 15 + 'px',
zIndex: item.rank * -1 + 50,
},
]"
:class="{
border: border === true,
show: item.show,
last: item.lastRank,
showchild: item.showChild,
open: item.open,
}"
>
<view class="tki-tree-label" @tap.stop="_treeItemTap(item, index)">
<image
class="tki-tree-icon"
:src="item.lastRank ? lastIcon : item.showChild ? currentIcon : defaultIcon"
></image>
{{ item.name }}
</view>
<view
class="tki-tree-check"
@tap.stop="_treeItemSelect(item, index)"
v-if="selectParent ? true : item.lastRank"
>
<view
class="tki-tree-check-yes"
v-if="item.checked"
:style="{ 'border-color': confirmColor }"
>
<view
class="tki-tree-check-yes-b"
:style="{ 'background-color': confirmColor }"
></view>
</view>
<view
class="tki-tree-check-no"
v-if="!item.checked"
:style="{ 'border-color': confirmColor }"
></view>
</view>
</view>
</block>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'Cn-MultipleTree',
props: {
lazy: {
type: Boolean,
default: false,
},
range: {
type: Array,
default: function () {
return []
},
},
idKey: {
type: String,
default: 'id',
},
rangeKey: {
type: String,
default: 'name',
},
title: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
selectParent: {
//是否可以选父级
type: Boolean,
default: false,
},
foldAll: {
//折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开
type: Boolean,
default: false,
},
confirmColor: {
// 确定按钮颜色
type: String,
default: '#376cf3', // #07bb07
},
cancelColor: {
// 取消按钮颜色
type: String,
default: '', // #757575
},
titleColor: {
// 标题颜色
type: String,
default: '', // #757575
},
currentIcon: {
// 展开时候的ic
type: String,
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEQ0QTM0MzQ1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEQ0QTM0MzU1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowRDRBMzQzMjVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowRDRBMzQzMzVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PidwepsAAAK0SURBVHja7JxbTsJAFIYHww7ciStgCeoGvGxAiOsgURegoL5720AXYLiIr0aJviq3Zx3PhIEnKG3ndtr+f3KixrSUj/ZjzjClIqUUiFm2gAAQAREQEUAEREAERAQQAREQAREBREAEREBEEqa67h9RFDWllDv0awWYlqlQHmu1WjMRRMoV1QFttA12y3xRtdNczq8EsE4/f8FumX2q77ROvNXk8UGMEKdUz6tYJHljaZAbuyUH+UR1to5BEohTuqwPCeS4pAA/qY6o/kyHOAMCeRK3owJnj+rH1jjxhqpVsstaebCz6TmnHWyXyY+xHjSBWBY/bvSgadtXBj9u9KCN3rnIfkzkQVsTEEX0Y2IP2oKo/HhMICcFAThUcwVZNGU6FdbX/XURzkbVF4+ybGhjPrFdgP66QdXNurGtSdk6Xdb9nAJ8oDo3OQlsQZzkdPw41ONBo6vI5scDefRjZg+6gpg3Pxp50CXEvPjR2IOuIXL3oxUPuobI3Y9WPOgDIlc/WvOgL4iL/vqFCcD7LH0xB4hj7cfQ/fWH9qCT+FhG0tN+DBk1PzjOM0SVllixcsBT1AvYc/kAPhc0hRg/3uvxoCgKRN9+dOrBUBB9+9GpB0NC9OVH5x4MDdG1H714kANEV3705kEOEBf9dcPi/lQnsuvLg1wgSu3Ha0v7Uh4MMgUXeuG71H407a+VBy9CPQkOdw+MtB+nGbd/D+FBbhBNxo9SjwcngJjNj0E9yBFiFj8G9SBXiGn8GNyDnCEm8SMLD3KHGOdHNh7kDjHOj2w8mAeIi/5arX+c6b/fxHz9oADEdGdjR/fXCw/OOB5oVfCOgnepz8IB14PMw03jCmTE+QBx5z0gAmKSqK9OUF+hcAeIhu/QYr4Qie8rjW83hhMBERARQAREQAREBBABERCLnH8BBgA+TQI7U4t53AAAAABJRU5ErkJggg==',
},
defaultIcon: {
// 折叠时候的ic
type: String,
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAACE0lEQVR4Xu3c200DMRCF4XEltJAOkEugA+ggpUAHoQMqiFMCdEAJUMEiS4mEELlIO7bPOeN9i6K1rG/952myyea1WiCtXmEuYBPR4RBMxInoIOCwhOtJLKVszWyXc/5y2BvNEq6I+/3+kFK6M7OHnPM7jcLKjbZAvD/uaZtzflm5P4rbWyJWgDcze1LPuzVihfxUz7sH4ilJ2bx7Isrm3RtRMu8RiHJ5j0SUyXs0okTeCIj0eSMh0uaNhkiZNyIiXd7IiDR5oyNS5M2ACJ83EyJs3myIkHkzIsLlzYwIkzc7IkTeCojD81ZCHJa3GuKQvBURu+etjNgtb3XELnlHQGyedyTEZnlHQ2ySd0RE97wjI7rlHR3RJe+JeIrbLOecD6ePpZQ6W1kn2epo4MUrPOKyLN8ppYq1+y1VStncOjIdGnFZlo+U0uOtWOeOY2TE12Ouq//pEA7xXL7XfvcufR8K0Svfv6CREN3yDYfYIt9QiK3yjYTYLF95xB75SiP2ylcZsVu+cogj8pVCHJWvEuKwfOkREfKlRkTJlxkRJl86RMR8qRBR82VChM0XHpEhX2hElnyREWnyhUNkzBcKkTVfJETafIcjKuQ7FFEl35GIMvl2R1TMtyuiar49EWXzbY5oZpv/hibXTF2h3+s60FRKeT6+3TjMS3nrA3ZFRD8xrfY3ER1kJ+JEdBBwWGKeRAfEH1wS5WFZSDB/AAAAAElFTkSuQmCC',
},
lastIcon: {
// 没有子集的ic
type: String,
default: '',
},
border: {
// 是否有分割线
type: Boolean,
default: false,
},
},
data() {
return {
showTree: false,
treeList: [],
selectIndex: -1,
returnedItem: [], //定义一个空数组
pids: [],
ancestorsIds: [],
childNums: [],
dataTree: [],
inputTimer: null, // 节流定时器标识
searchValue: '',
}
},
computed: {},
methods: {
_show() {
this.showTree = true
if (this.searchValue != '') {
this.searchValue = ''
this.input('')
}
},
_hide() {
this.showTree = false
},
_cancel() {
this._hide()
this.$emit('cancel', '')
},
_confirm() {
// 处理所选数据
let rt = [],
obj = {}
this.treeList.forEach((v, i) => {
if (this.treeList[i].checked) {
// rt.push(this.treeList[i].id)
rt.push(this.treeList[i])
}
})
this._hide()
console.log('🚀 ~ rt:', rt)
if (rt.length == 0) return
this.$emit('confirm', rt)
},
//扁平化树结构
_renderTreeList(list = [], rank = 0, parentId = [], parents = []) {
list.forEach((item) => {
this.treeList.push({
id: item[this.idKey],
name: item[this.rangeKey],
source: item,
parentId, // 父级id数组
parents, // 父级id数组
rank, // 层级
showChild: false, //子级是否显示
open: false, //是否打开
show: rank === 0, // 自身是否显示
hideArr: [],
orChecked: item.checked ? item.checked : false,
checked: item.checked ? item.checked : false,
childNum: 0,
})
if (Array.isArray(item.children) && item.children.length > 0) {
let parentid = [...parentId],
parentArr = [...parents]
delete parentArr.children
parentid.push(item[this.idKey])
parentArr.push({
[this.idKey]: item[this.idKey],
[this.rangeKey]: item[this.rangeKey],
rank: rank,
})
// lazy
if (!this.lazy) {
this._renderTreeList(item.children, rank + 1, parentid, parentArr)
}
} else {
this.treeList[this.treeList.length - 1].lastRank = true
}
})
},
// 处理默认选择
_defaultSelect() {
this.treeList.forEach((v, i) => {
if (v.checked) {
this.treeList.forEach((v2, i2) => {
if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) {
v2.show = true
if (v.parentId.includes(v2.id)) {
v2.showChild = true
v2.open = true
}
}
})
}
})
},
getOwn(id, arr) {
//利用foreach循环遍历
arr.forEach((item) => {
//判断递归结束条件
if (item[this.idKey] == id) {
// 存储数据到空数组
this.returnedItem = item
} else if (item.children != null) //判断chlidren是否有数据
{
//递归调用
this.getOwn(id, item.children)
}
})
return this.returnedItem
},
setShow(id, arr, isShow) {
arr.forEach((item, index) => {
if (item.parentId.includes(id)) {
this.treeList[index].showChild = isShow
this.treeList[index].show = isShow
} else if (item.children !== undefined) {
this.setShow(id, item.children, isShow)
}
})
},
// 点击
_treeItemTap(item, index) {
// console.log(item)
if (item.lastRank === true) {
this.treeList[index].checked = !this.treeList[index].checked
if (!this.multiple) {
this._fixSingle(index)
}
return
}
let id = item.id
item.showChild = !item.showChild
// qingqian
if (item.showChild) {
// const range = this.range
const range = this.dataTree
const parentIdArr = item.parentId
// 找到当前元素
const own = this.getOwn(id, range)
const checkedChildren = own.children
// 子元素插入的索引位置
const nextIndex = this.treeList.findIndex((itemT) => itemT.id === item.id)
console.log(checkedChildren)
if (checkedChildren === undefined || checkedChildren.length < 1) {
return
}
// 子节点数量
this.treeList[index].childNum = checkedChildren.length
const newRank = item.rank + 1
checkedChildren.forEach((itemC) => {
const childObj = {
id: itemC[this.idKey],
name: itemC[this.rangeKey],
source: {},
parentId: [item.id], // 父级id数组
parents: [item], // 父级id数组
rank: newRank, // 层级
showChild: false, //子级是否显示
open: false, //是否打开
show: 1, // 自身是否显示
hideArr: [],
orChecked: this.treeList[index].checked,
checked: this.treeList[index].checked,
}
if (!this.treeList.some((itemT) => itemT.id === itemC[this.idKey])) {
this.treeList.splice(nextIndex + 1, 0, childObj)
}
})
}
// 展开/隐藏子级/孙级
let list = this.treeList
item.open = item.showChild ? true : !item.open
list.forEach((childItem, i) => {
if (item.showChild === false) {
//隐藏所有子级
if (!childItem.parentId.includes(id)) {
return
}
//TODO: 修改
if (!this.foldAll) {
if (childItem.lastRank !== true && !childItem.open) {
childItem.showChild = false
this.setShow(childItem.id, this.treeList, false)
}
// 为隐藏的内容添加一个标记
if (childItem.show) {
childItem.hideArr[item.rank] = id
}
} else {
if (childItem.lastRank !== true) {
childItem.showChild = false
// 继续隐藏子级的的子级
this.setShow(childItem.id, this.treeList, false)
}
}
if (childItem.children !== undefined) {
childItem.children.forEach((childItem1, i1) => {
if (!childItem1.parentId.includes(childItem.id)) {
return
}
childItem.children[i1].showChild = false
childItem.children[i1].show = false
})
}
childItem.show = false
} else {
// 打开子集
if (childItem.parentId[childItem.parentId.length - 1] === id) {
childItem.show = true
}
// 打开被隐藏的子集
if (childItem.parentId.includes(id) && !this.foldAll) {
// console.log(childItem.hideArr)
if (childItem.hideArr[item.rank] === id) {
childItem.show = true
if (childItem.open && childItem.showChild) {
childItem.showChild = true
} else {
childItem.showChild = false
}
childItem.hideArr[item.rank] = null
}
}
}
})
},
// 通过父id处理子级
syncChecked(trees, pid, checked) {
trees.forEach((item, index) => {
if (item.parentId.includes(pid)) {
this.treeList[index].checked = checked
this.syncChecked(trees, item.id, checked)
} else if (item.children !== undefined) {
this.syncChecked(item.children, pid, checked)
}
})
},
// 获取父级往上所有层级的id 并同步状态
setAncestors(pids, checked) {
this.treeList.forEach((item, index) => {
if (pids.includes(item.id)) {
if (checked && this.childNums[item.id] !== undefined && item.childNum === this.childNums[item.id]) {
// 子级全部选中, 父级才选中
this.treeList[index].checked = true
} else {
this.treeList[index].checked = false
}
this.setAncestors(item.parentId, checked)
}
})
},
_treeItemSelect(item, index) {
this.treeList[index].checked = !this.treeList[index].checked
// 选父级, 子级自动全选
this.syncChecked(this.treeList, item.id, this.treeList[index].checked)
if (item.rank > 0) {
item.parentId.forEach((pid, indexP) => {
const parent = this.treeList.filter((i) => i.id === pid)
const childNum = parent.length > 0 ? parent[0].childNum : 0
if (this.childNums[pid] === undefined) {
this.childNums[pid] = 1
} else if (this.childNums[pid] < childNum) {
this.childNums[pid]++
}
})
//子级选择/选满/取消选择, 父级往上同步状态
this.setAncestors(item.parentId, this.treeList[index].checked)
}
if (!this.multiple) {
this._fixSingle(index)
}
},
_fixSingle(index) {
this.treeList.forEach((v, i) => {
this.treeList[i].checked = i === index
})
},
// 重置数据
_reTreeList() {
this.treeList.forEach((v, i) => {
this.treeList[i].checked = v.orChecked
})
},
_initTree(range = this.range) {
this.treeList = []
this.dataTree = JSON.parse(JSON.stringify(range))
this._renderTreeList(range)
this.$nextTick(() => {
this._defaultSelect(range)
})
},
// 筛选
input(val) {
// 清除上一次的定时器,避免频繁执行
if (this.inputTimer) {
clearTimeout(this.inputTimer)
}
// 设置新的定时器,指定延迟后执行过滤逻辑
this.inputTimer = setTimeout(() => {
const keyword = val
// 执行树形过滤和初始化
this._initTree(this.filterNodes(this.range, keyword))
// 清空定时器标识
clearTimeout(this.inputTimer)
this.inputTimer = null
}, 500)
// this._initTree(this.filterNodes(this.range, val.detail.value))
},
filterNodes(node, query) {
const keyword = query.trim() // 获取搜索关键字并转换为小写
const nodes = node
// 使用递归函数过滤树形数据
const filteredNodes = []
for (const node of nodes) {
if (node.name.includes(keyword)) {
// 如果节点的标签包含关键字,将其添加到结果中
filteredNodes.push(node)
} else if (node.children && node.children.length > 0) {
// 如果节点有子节点,则递归过滤子节点
const filteredChildren = this.filterNodes(node.children, keyword)
if (filteredChildren.length > 0) {
// 如果子节点中有匹配的结果,则添加父节点
const clonedNode = { ...node, children: filteredChildren }
filteredNodes.push(clonedNode)
}
}
}
return filteredNodes
},
},
watch: {
range(list) {
this._initTree(list)
},
multiple() {
if (this.range.length) {
this._reTreeList()
}
},
selectParent() {
if (this.range.length) {
this._reTreeList()
}
},
},
mounted() {
this._initTree()
},
}
</script>
<style lang="scss" scoped>
@import './style.css';
/deep/ .uni-searchbar__box {
justify-content: left !important;
}
</style>

View File

@@ -0,0 +1,195 @@
.tki-tree-mask {
position: fixed;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
z-index: 9998;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
transition: all 0.3s ease;
visibility: hidden;
}
.tki-tree-mask.show {
visibility: visible;
opacity: 1;
}
.tki-tree-cnt {
position: fixed;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
z-index: 9999;
top: 40%;
transition: all 0.3s ease;
transform: translateY(100%);
}
.tki-tree-cnt.show {
transform: translateY(0);
}
.tki-tree-bar {
background-color: #fff;
height: 72rpx;
padding-left: 20rpx;
padding-right: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
border-bottom-width: 1rpx !important;
border-bottom-style: solid;
border-bottom-color: #f5f5f5;
font-size: 32rpx;
color: #757575;
line-height: 1;
}
.tki-tree-bar1 {
background-color: #fff;
}
.tki-tree-bar-confirm {
color: #07bb07;
}
.tki-tree-view {
position: absolute;
top: 0rpx;
right: 0rpx;
bottom: 0rpx;
left: 0rpx;
top: 160rpx;
background-color: #fff;
padding-top: 20rpx;
padding-right: 20rpx;
padding-bottom: 20rpx;
padding-left: 20rpx;
}
.tki-tree-view-sc {
height: 100%;
overflow: hidden;
}
.tki-tree-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 26rpx;
/* color: #757575; */
line-height: 1;
height: 0;
opacity: 0;
transition: 0.2s;
position: relative;
overflow: hidden;
}
.tki-tree-item.show {
height: 80rpx;
opacity: 1;
}
.tki-tree-item.showchild:before {
transform: rotate(90deg);
}
.tki-tree-item.last:before {
opacity: 0;
}
.tki-tree-icon {
width: 26rpx;
height: 26rpx;
margin-right: 8rpx;
}
.tki-tree-label {
flex: 1;
display: flex;
align-items: center;
height: 100%;
line-height: 1.2;
}
.tki-tree-check {
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.tki-tree-check-yes,
.tki-tree-check-no {
width: 20px;
height: 20px;
border-top-left-radius: 20%;
border-top-right-radius: 20%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 20%;
border-top-width: 1rpx;
border-left-width: 1rpx;
border-bottom-width: 1rpx;
border-right-width: 1rpx;
border-style: solid;
border-color: #07bb07;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.tki-tree-check-yes-b {
width: 12px;
height: 12px;
border-top-left-radius: 20%;
border-top-right-radius: 20%;
border-bottom-right-radius: 20%;
border-bottom-left-radius: 20%;
background-color: #07bb07;
}
.tki-tree-check .radio {
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%;
}
.tki-tree-check .radio .tki-tree-check-yes-b {
border-top-left-radius: 50%;
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%;
}
.hover-c {
opacity: 0.6;
}
.search {
position: absolute;
left: 35rpx;
}
/* 基础输入框样式 */
.uni-input {
width: 95%;
height: 60rpx;
line-height: 60rpx;
border-radius: 20rpx;
/* font-size: 32rpx;
color: #333;
background: #f5f5f5;
width: 100%;
padding: 0 24rpx 0 60rpx;
box-sizing: border-box;
border: none; */
}
/* 聚焦态样式 */
.uni-input:focus {
background: #fff;
border: 2rpx solid #007aff;
}
/* 占位符样式 */
.uni-input::placeholder {
color: #999;
font-size: 28rpx;
}
/* 兼容微信小程序 */
.uni-input::-webkit-input-placeholder {
color: #999;
font-size: 28rpx;
}

View File

@@ -1,13 +1,6 @@
<template>
<uni-card
:title="device.equipmentName"
:sub-title="device.mac"
:extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'"
padding="0"
@click="jump(device)"
class="boxClick"
:thumbnail="deviceIcon(device.runStatus)"
>
<uni-card :title="device.equipmentName" :sub-title="device.mac" :extra="device.isPrimaryUser == 1 ? '主设备' : '分享设备'"
padding="0" @click="jump(device)" class="boxClick" :thumbnail="deviceIcon(device.runStatus)">
<template v-slot:title>
<!-- 卡片标题 -->
<view class="uni-card__header" @click="jump(device)">
@@ -25,35 +18,38 @@
:color="device.runStatus == 1 ? '#ff3b30' : '#10B981'"
:size="device.devType == 'Direct_Connected_Device' ? '35' : '40'"
></uni-icons> -->
<Cn-icon-device
:devType="device.devType"
:runStatus="device.runStatus"
:alarmStatus="device.isAlarm ? 1 : 0"
></Cn-icon-device>
<Cn-icon-device :devType="device.devType" :runStatus="device.runStatus"
:alarmStatus="device.isAlarm ? 1 : 0"></Cn-icon-device>
</view>
</view>
<view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis">
{{ device.equipmentName }}
</text>
<text class="uni-card__header-content-subtitle uni-ellipsis">
<!-- {{ device.mac }}-->
</text>
<!-- <text class="uni-card__header-content-subtitle uni-ellipsis">
{{ device.mac }}
</text> -->
<view class="event-desc mt10 mb8">
<text>
工程名称{{ device.engineeringName }}
</text>
<text>
项目名称{{ device.projectName }}
</text>
</view>
<view class="tagBox">
<text class="event-tag" :class="device.runStatus == 1 ? 'lx-tag' : 'zx-tag'">
{{ device.runStatus == 1 ? '离线' : '在线' }}
</text>
<text
class="event-tag"
:class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'"
>
<text class="event-tag"
:class="device.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">
{{ device.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}
</text>
<text class="event-tag" :class="device.isPrimaryUser == 1 ? 'z-tag' : 'fx-tag'">
{{ device.isPrimaryUser == 1 ? '我的设备' : '他人设备' }}
</text>
</view
>
</view>
</view>
</view>
<view class="uni-card__header-extra" style="position: relative" @click.stop>
@@ -63,8 +59,8 @@
</view>
<!-- <slot name="title"></slot> -->
</template>
<view class="device-body">
<view class="device-body-item">
<!-- <view class="device-body">
<view class="device-body-item">
<text>工程名称</text>
<text>{{ device.engineeringName }}</text>
</view>
@@ -75,8 +71,8 @@
<view class="device-body-item mt6" v-if="device.process == 2 || device.process == 3">
<text>调试阶段</text>
<text>{{ device.process == 2 ? '功能调试' : '出厂调试' }}</text>
</view>
</view>
</view>
</view> -->
<view class="pinToTop" v-if="device.isTop == 1"> 置顶</view>
</uni-card>
</template>
@@ -166,10 +162,10 @@ export default {
/deep/ .uni-card__header {
display: flex;
border-bottom: 2rpx #ebeef5 solid;
// border-bottom: 2rpx #ebeef5 solid;
flex-direction: row;
align-items: center;
padding: 20rpx 20rpx 10rpx 0;
padding: 20rpx 0;
overflow: hidden;
}
}
@@ -279,4 +275,16 @@ export default {
transform: rotate(45deg) translate(50rpx, -10rpx);
transform-origin: top right;
}
.event-desc {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.event-desc text {
font-size: 28rpx;
color: #666666;
line-height: 1.2;
}
</style>

View File

@@ -0,0 +1,234 @@
<template>
<view class="nav choose">
<view class="nav-menu nav-menu1" @click="selectEngineering" v-if="showQianTree">
<view class="nav-text">
{{ lineDisplayText }}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<view class="nav-menu nav-menu1" @click="selectEngineering" v-if="showQianTree">
<view class="nav-text">
{{
'指标配置'
}}
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
<!-- 弹框组件 -->
<Cn-MultipleTree ref="qiantree" :selectParent="true" :multiple="true" :range="list" :foldAll="true"
@confirm="treeConfirm" @cancel="treeCancel"></Cn-MultipleTree>
<slot />
</view>
</template>
<script>
import { lineTree } from '@/common/api/device'
export default {
components: {},
props: {
level: { type: Number, default: 3 },
singleChoice: { type: Boolean, default: false },
showQianTree: { type: Boolean, default: true },
},
data() {
return {
select: {
lineList: []//监测点id
},
list: [],
}
},
created() { },
onShow() { },
mounted() { },
methods: {
getTree() {
this.clear()
lineTree().then((res) => {
let list = {}
// if (this.singleChoice) {
// let result = this.findFirstLevel(res.data)
// } else {
// list = {
// id: '',
// pid: '0',
// pids: '0',
// name: '全部工程',
// path: null,
// provinceId: null,
// cityId: null,
// area: null,
// remark: null,
// sort: 0,
// level: 0,
// comFlag: null,
// type: null,
// lineType: null,
// conType: null,
// process: null,
// isTop: 0,
// children: [],
// ndid: null,
// }
// }
this.list = this.filterTreeByLevel(this.singleChoice ? res.data : [...res.data])
// this.findFirstLevel( this.list)
})
},
// 递归过滤函数去除level > 2的节点
filterTreeByLevel(tree) {
// 遍历每一个节点
return tree.map((node) => {
// 复制当前节点(避免修改原数据)
const newNode = { ...node }
// 如果当前节点有子节点并且当前节点的level <= 2因为level=2的节点的子节点是level=3需要过滤
if (newNode.children && newNode.children.length > 0) {
// 递归过滤子节点只保留子节点中level <= 2的
newNode.children = this.filterTreeByLevel(
newNode.children.filter((child) => child.level <= this.level),
)
}
return newNode
})
},
selectEngineering() {
this.$refs.qiantree._show()
},
// 确定回调事件
treeConfirm(e) {
this.select.lineList = e.filter(item => item.rank == 3)
},
// 清空
clear() {
this.select.lineList = []//监测点id
},
// 取消回调事件
treeCancel(e) {
console.log(e)
},
findFirstLevel(list, parents = []) {
for (const item of list) {
// 当前就是 level=3
if (item.level === 3) {
return {
node: item, // 第一个 level=3
parents: parents, // 它的所有上级
}
}
// 递归子节点
if (item.children && item.children.length) {
const res = this.findFirstLevel(item.children, [...parents, item])
if (res) return res // 找到直接返回,不再循环
}
}
return null
},
},
computed: {
lineDisplayText() {
const list = this.select.lineList || []
if (!list.length) {
return '全部工程'
}
const text = list
.map((item) => item.name)
.filter(Boolean)
.join('、')
if (text.length > 8) {
return text.slice(0, 8) + '...'
}
return text
},
},
watch: {
select: {
handler(val, oldVal) {
console.log("🚀 ~ val:", val)
if (this.loading) return
this.$emit('select', val)
},
deep: true,
immediate: true,
},
level: {
handler(val, oldVal) {
this.getTree()
},
deep: true,
immediate: true,
},
// showDatetime: {
// handler(val, oldVal) {
// if (val == false) {
// console.log("🚀 ~ this.select.range:", this.select.range)
// }
// },
// deep: true,
// },
},
}
</script>
<style lang="scss" scoped>
/deep/ .uni-date-editor {
width: 360rpx;
}
.nav-menu {
display: flex;
align-items: center;
}
// .nav-menu1 {
// max-width: calc(100vw - 150px);
// overflow: hidden !important;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
// }
.nav-menu1 {
display: flex;
align-items: center;
max-width: calc(100vw - 150px);
}
/* 文字容器:单行溢出省略 */
.nav-text {
flex: 1;
overflow: hidden;
white-space: nowrap;
/* 强制不换行 */
text-overflow: ellipsis;
// -webkit-line-clamp: 1;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// text-overflow: ellipsis;
// word-break: break-all;
// white-space: nowrap;
line-height: 1;
}
</style>

View File

@@ -1,45 +1,45 @@
<template>
<view v-html="svgHtml" class="svg-container"></view>
<view v-html="svgHtml" class="svg-container"></view>
</template>
<script>
export default {
props: {
// 父组件传递的参数
name: {
type: String,
default: '',
},
props: {
// 父组件传递的参数
name: {
type: String,
default: '',
},
data() {
return {}
},
computed: {
svgHtml() {
if (this.name == '电压暂降') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
},
data() {
return {}
},
computed: {
svgHtml() {
if (this.name == '电压暂降') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,56 L56,54 L58,55 L60,54 L63,56 L66,60 L68,62 L70,60 L72,56 L75,54 L77,52 L79,54 L81,56 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#2563eb" stroke-width="4"/>
</svg>`
} else if (this.name == '电压暂升') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
} else if (this.name == '电压暂升') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,43 L56,34 L58,26 L60,34 L63,43 L66,54 L68,60 L70,54 L72,43 L75,34 L77,26 L79,34 L81,43 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#e6a23c" stroke-width="4"/>
</svg>`
} else if (this.name == '电压中断') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
} else if (this.name == '电压中断') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,50 L57,50 L60,50 L63,50 L66,50 L69,50 L72,50 L75,50 L78,50 L81,50 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#6b7280" stroke-width="4"/>
</svg>`
} else if (this.name == '瞬态') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
} else if (this.name == '瞬态') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L53,50 L55,50 L57,20 L59,50 L61,50 L63,50 L66,60 L68,62 L70,60 L72,56 L75,54 L77,52 L79,54 L81,56 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#8b5cf6" stroke-width="4"/>
</svg>`
} else if (this.name == '未知') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
} else if (this.name == '未知') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<path d="M8,50 L15,50 L18,38 L21,28 L24,38 L27,50 L30,62 L33,72 L36,62 L39,50 L42,38 L45,28 L48,38 L51,50 L54,56 L56,54 L58,55 L60,54 L63,56 L66,60 L68,62 L70,60 L72,56 L75,54 L77,52 L79,54 L81,56 L84,50 L87,38 L90,28 L93,38 L96,50" fill="none" stroke="#6b7280" stroke-width="4"/>
<text x="50" y="82" text-anchor="middle" font-size="18" fill="#6b7280" font-family="Arial, sans-serif" font-weight="bold">?</text>
</svg>`
} else if (this.name == '稳态越限') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
} else if (this.name == '稳态越限') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<!-- Limit line -->
<line x1="5" y1="40" x2="95" y2="40" stroke="#e6a23c" stroke-width="2" stroke-dasharray="4,4"/>
@@ -70,14 +70,14 @@ export default {
</marker>
</defs>
</svg>`
} else if (this.name == '运行告警') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="40" height="40">
} else if (this.name == '运行告警') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="40" height="40">
<path d="M78.43 4H20.06C9.48 4 1.16 12.33 1.16 22.9v38.37c0 10.57 8.32 18.9 18.9 18.9h26.49v7.27H25.77v7.41h47.96v-7.41H53.96v-7.27h26.47c10.58 0 18.9-8.33 18.9-18.9V22.9c0-10.57-8.32-18.9-18.9-18.9z m11.49 57.27c0 6.33-5.14 11.49-11.49 11.49H20.06c-6.34 0-11.49-5.15-11.49-11.49V22.9c0-6.33 5.14-11.49 11.49-11.49h59.37c6.34 0 11.49 5.15 11.49 11.49v38.37z" fill="#007aff"/>
<line x1="50" y1="28" x2="50" y2="50" stroke="#007aff" stroke-width="6" stroke-linecap="round"/>
<circle cx="50" cy="62" r="4" fill="#007aff"/>
</svg>`
} else if (this.name == '治理设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
} else if (this.name == '治理设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
<rect x="0" y="0" width="100" height="100" rx="8" ry="8" fill="#007aff30" stroke="#007aff" stroke-width="2"/>
<rect x="8" y="8" width="84" height="84" rx="4" ry="4" fill="#FFFFFF" stroke="#007aff" stroke-width="1.5"/>
<rect x="10" y="12" width="80" height="16" rx="2" ry="2" fill="#007aff30" stroke="#CCC" stroke-width="0.8"/>
@@ -95,8 +95,8 @@ export default {
<circle cx="86" cy="69" r="2" fill="#007aff"/>
<polygon points="88,65 86,70 84,65" fill="#007aff" opacity="0.7"/>
</svg>`
} else if (this.name == '监测设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
} else if (this.name == '监测设备') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="38" height="38">
<style>
text { font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; }
</style>
@@ -119,8 +119,8 @@ export default {
<text x="54" y="65" font-size="7" fill="#007aff">Ic: 125.1A</text>
</svg>`
} else if (this.name == '报告') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="47" height="47">
} else if (this.name == '报告') {
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="47" height="47">
<path d="M12,12 L78,12 L88,22 L88,88 L12,88 Z" fill="none" stroke="#007aff" stroke-width="4" stroke-linejoin="round"/>
<path d="M78,12 L78,22 L88,22" fill="none" stroke="#007aff" stroke-width="4" stroke-linejoin="round"/>
<polyline points="20,50 26,50 28,46 30,42 32,46 34,50 36,54 38,58 40,54 42,50 44,46 46,42 48,46 50,50 56,50" fill="none" stroke="#007aff" stroke-width="4" stroke-linecap="round"/>
@@ -129,18 +129,20 @@ export default {
<circle cx="70" cy="68" r="9" fill="none" stroke="#007aff" stroke-width="4"/>
<line x1="76" y1="74" x2="86" y2="84" stroke="#007aff" stroke-width="4" stroke-linecap="round"/>
</svg>`
}
},
} else if (this.name == '监测点') {
return `<svg t="1779762122379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3577" width="38" height="38"><path d="M875.17148 230.296136c30.706152 56.294611 46.059227 122.824606 46.059227 194.472293 0 107.47153-40.941535 209.825369-107.47153 286.590748 0 0 0 5.117692-5.117692 5.117692l-261.002288 286.590748c0 5.117692-5.117692 10.235384-5.117692 10.235383-15.353076 10.235384-30.706152 15.353076-46.059227 5.117692-5.117692 0-10.235384-5.117692-15.353076-10.235384v-5.117691L209.87153 716.476869s-5.117692-5.117692-5.117692-10.235384c-66.529995-76.765379-102.353838-174.001525-102.353838-281.473056C102.4 189.354601 286.636909 0 511.815354 0c81.883071 0 153.530758 25.58846 220.060752 66.529995 5.117692 0 5.117692 5.117692 10.235384 5.117692h5.117692c46.059227 35.823843 81.883071 81.883071 112.589222 133.05999 10.235384 5.117692 15.353076 15.353076 15.353076 25.588459z m-163.766141-92.118454c-5.117692 0-10.235384-5.117692-15.353076-10.235384-51.176919-35.823843-112.589222-56.294611-179.119217-56.294611-189.354601 0-337.767667 158.64845-337.767667 353.120742 0 92.118455 30.706152 174.001525 87.000762 235.413829l20.470768 20.470767 20.470768 20.470768 143.295374 153.530758L511.815354 931.41993l71.647687-76.765379 143.295373-153.530758 5.117692-5.117692 35.823844-40.941535c0-5.117692 5.117692-5.117692 10.235384-5.117692 51.176919-61.412303 81.883071-143.295374 81.88307-230.296136-5.117692-112.589222-66.529995-214.943061-148.413065-281.473056z m-199.589985 460.592273c-92.118455 0-163.766141-76.765379-163.766142-174.001526C348.049212 332.649975 419.696899 255.884596 511.815354 255.884596c92.118455 0 163.766141 76.765379 163.766141 174.001525 0 92.118455-71.647687 168.883833-163.766141 168.883834z m0-271.237672c-51.176919 0-97.236146 46.059227-97.236147 102.353838s46.059227 102.353838 97.236147 102.353839c51.176919 0 97.236146-46.059227 97.236146-102.353839s-46.059227-102.353838-97.236146-102.353838z" fill="#007aff" p-id="3578"></path></svg>`
}
},
methods: {},
},
methods: {},
}
</script>
<style scoped>
.svg-container {
width: 100rpx;
display: flex;
justify-content: center;
align-items: center;
width: 100rpx;
display: flex;
justify-content: center;
align-items: center;
}
</style>