绘制电脑治理信息页面

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

@@ -6,20 +6,16 @@
<view class="grid-card-title">温度</view>
<view class="grid-card-content-4">
<template v-for="item in renderData">
<view class="item item-title"
>{{ item[0].clDid }}
<view class="item item-title">{{ item[0].clDid }}
<template v-if="item[0].clDid"> (°C)</template>
</view>
<view class="item item-title"
>{{ item[1].clDid }}
<view class="item item-title">{{ item[1].clDid }}
<template v-if="item[1].clDid"> (°C)</template>
</view>
<view class="item item-title"
>{{ item[2].clDid }}
<view class="item item-title">{{ item[2].clDid }}
<template v-if="item[2].clDid"> (°C)</template>
</view>
<view class="item item-title"
>{{ item[3].clDid }}
<view class="item item-title">{{ item[3].clDid }}
<template v-if="item[3].clDid"> (°C)</template>
</view>
<view class="item">{{ item[0].clDid ? Math.round(item[0].value) || '-' : '' }}</view>
@@ -30,27 +26,21 @@
</view>
</view>
<!-- 运维管理员工程用户 可看 -->
<view
class="grid-card"
v-if="userInfo.authorities == 'operation_manager' || userInfo.authorities == 'engineering_user'"
>
<view class="grid-card"
v-if="(userInfo.authorities == 'operation_manager' || userInfo.authorities == 'engineering_user') && moduleData.length > 0">
<view class="grid-card-title">状态</view>
<view class="grid-card-content-4">
<template v-for="(item, index) in moduleData">
<view class="item item-title"
>{{ item[0].moduleName }}
<view class="item item-title">{{ item[0].moduleName }}
<template v-if="item[0].moduleName"></template>
</view>
<view class="item item-title"
>{{ item[1].moduleName }}
<view class="item item-title">{{ item[1].moduleName }}
<template v-if="item[1].moduleName"></template>
</view>
<view class="item item-title"
>{{ item[2].moduleName }}
<view class="item item-title">{{ item[2].moduleName }}
<template v-if="item[2].moduleName"></template>
</view>
<view class="item item-title"
>{{ item[3].moduleName }}
<view class="item item-title">{{ item[3].moduleName }}
<template v-if="item[3].moduleName"></template>
</view>
<!-- <uni-tag :text="item[0].moduleState" :type=" item[0].moduleState=='离线'?'error' : 'success'" /> -->
@@ -101,6 +91,7 @@ export default {
computed: {
renderData() {
let arr = []
// 把IOData转换成每4个一组的二维数组
for (let i = 0; i < this.IOData.length; i += 4) {
this.IOData.slice(i, i + 4).forEach((item) => {
@@ -120,7 +111,6 @@ export default {
}
}
})
console.warn(arr)
return arr
},
moduleData() {
@@ -159,6 +149,5 @@ export default {
}
</script>
<style lang="scss">
.basic {
}
.basic {}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<view>
<uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more>
<uni-load-more status="loading"
v-if="renderData.电网电流.length == 0 || renderData.电网电压.length == 0 || renderData.负载电流.length == 0 || renderData.补偿电流.length == 0 "></uni-load-more>
<view class="basic" v-else>
<view class="grid-card">
<view class="grid-card-title">电网电流</view>
@@ -12,10 +13,10 @@
<view class="item">{{ item.phase }}</view>
<view class="item">{{
item['Apf_RmsI_Sys(A)'] > 0 ? item['Apf_RmsI_Sys(A)'].toFixed(2) : item['Apf_RmsI_Sys(A)']
}}</view>
}}</view>
<view class="item">{{
item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)']
}}</view>
}}</view>
</template>
</view>
</view>
@@ -30,13 +31,13 @@
<view class="item">{{ item.phase }}</view>
<view class="item">{{
item['Apf_PhV_Sys(V)'] > 0 ? item['Apf_PhV_Sys(V)'].toFixed(2) : item['Apf_PhV_Sys(V)']
}}</view>
}}</view>
<view class="item">{{
item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)']
}}</view>
}}</view>
<view class="item">{{
item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)']
}}</view>
}}</view>
</template>
</view>
</view>
@@ -73,15 +74,15 @@
item['Apf_RmsI_TolOut(A)'] == 3.1415926
? '-'
: item['Apf_RmsI_TolOut(A)'] > 0
? item['Apf_RmsI_TolOut(A)'].toFixed(2)
: item['Apf_RmsI_TolOut(A)']
? item['Apf_RmsI_TolOut(A)'].toFixed(2)
: item['Apf_RmsI_TolOut(A)']
}}</view>
<view class="item">{{
item['load_Rate'] == 3.1415926
? '-'
: item['load_Rate'] > 0
? item['load_Rate'].toFixed(2)
: item['load_Rate']
? item['load_Rate'].toFixed(2)
: item['load_Rate']
}}</view>
</template>
</view>
@@ -179,6 +180,5 @@ export default {
}
</script>
<style lang="scss">
.basic {
}
.basic {}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<view>
<uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more>
<uni-load-more status="loading" v-if="renderData.电网侧.length == 0 || renderData.负载侧.length == 0"></uni-load-more>
<view class="basic" v-else>
<view class="grid-card">
<view class="grid-card-title">电网侧</view>
@@ -12,14 +12,14 @@
<view class="item item-title">功率因数</view>
<template v-for="(item, index) in renderData.电网侧">
<view class="item">{{ item.phase }}</view>
<view class="item"
>{{ item['Apf_P_Sys(W)'] == '-' ? '-' : (item['Apf_P_Sys(W)'] / 1000).toFixed(2) }}
<view class="item">{{ item['Apf_P_Sys(W)'] == '-' ? '-' : (item['Apf_P_Sys(W)'] /
1000).toFixed(2) }}
</view>
<view class="item"
>{{ item['Apf_Q_Sys(Var)'] == '-' ? '-' : (item['Apf_Q_Sys(Var)'] / 1000).toFixed(2) }}
<view class="item">{{ item['Apf_Q_Sys(Var)'] == '-' ? '-' : (item['Apf_Q_Sys(Var)'] /
1000).toFixed(2) }}
</view>
<view class="item"
>{{ item['Apf_S_Sys(VA)'] == '-' ? '-' : (item['Apf_S_Sys(VA)'] / 1000).toFixed(2) }}
<view class="item">{{ item['Apf_S_Sys(VA)'] == '-' ? '-' : (item['Apf_S_Sys(VA)'] /
1000).toFixed(2) }}
</view>
<view class="item">{{ item['Apf_PF_Sys(null)'] || '-' }}</view>
</template>
@@ -35,14 +35,14 @@
<view class="item item-title">功率因数</view>
<template v-for="(item, index) in renderData.负载侧">
<view class="item">{{ item.phase }}</view>
<view class="item"
>{{ item['Apf_P_Load(W)'] == '-' ? '-' : (item['Apf_P_Load(W)'] / 1000).toFixed(2) }}
<view class="item">{{ item['Apf_P_Load(W)'] == '-' ? '-' : (item['Apf_P_Load(W)'] /
1000).toFixed(2) }}
</view>
<view class="item">{{
item['Apf_Q_Load(Var)'] == '-' ? '-' : (item['Apf_Q_Load(Var)'] / 1000).toFixed(2)
}}</view>
<view class="item"
>{{ item['Apf_S_Load(VA)'] == '-' ? '-' : (item['Apf_S_Load(VA)'] / 1000).toFixed(2) }}
}}</view>
<view class="item">{{ item['Apf_S_Load(VA)'] == '-' ? '-' : (item['Apf_S_Load(VA)'] /
1000).toFixed(2) }}
</view>
<view class="item">{{ item['Apf_PF_Load(null)'] || '-' }}</view>
</template>
@@ -130,6 +130,5 @@ export default {
}
</script>
<style lang="scss">
.basic {
}
.basic {}
</style>

View File

@@ -5,18 +5,10 @@
<view class="detail-header">
<Cn-htmlToImg domId="header" @renderFinish="renderFinish">
<view class="header" id="header" ref="header" @click="previewImg">
<img
:src="topoImg"
style="width: 375px; display: block"
mode="widthFix"
@load="domLoading = false"
/>
<view
class="point"
:style="{ left: item.lat + 'px', top: item.lng + 'px' }"
v-for="(item, index) in topolodyData"
:key="index"
>
<img :src="topoImg" style="width: 375px; display: block" mode="widthFix"
@load="domLoading = false" />
<view class="point" :style="{ left: item.lat + 'px', top: item.lng + 'px' }"
v-for="(item, index) in topolodyData" :key="index">
<view class="grid-card mt10" style="width: fit-content">
<view class="grid-card-content-1">
<view class="item">{{ item.label }}</view>
@@ -51,13 +43,9 @@
<text class="ml10">设备状态</text>
</view> -->
<view class="nav" style="margin-top: -10rpx">
<view
class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
<view class="nav-menu" :class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList" :key="index" @click="navMenuClick(index)">{{ item.text
}}
</view>
</view>
</view>
@@ -107,22 +95,10 @@
</uni-popup> -->
<!-- 输入框示例 -->
<uni-popup ref="inputDialog" type="dialog">
<uni-popup-dialog
ref="inputClose"
type="info"
mode="input"
:title="dialogType"
value="对话框预置提示内容!"
placeholder="请输入内容"
@confirm="dialogInputConfirm"
>
<uni-easyinput
type="textarea"
:maxlength="250"
autoHeight
v-model="remarkContent"
placeholder="请输入备注"
></uni-easyinput>
<uni-popup-dialog ref="inputClose" type="info" mode="input" :title="dialogType" value="对话框预置提示内容!"
placeholder="请输入内容" @confirm="dialogInputConfirm">
<uni-easyinput type="textarea" :maxlength="250" autoHeight v-model="remarkContent"
placeholder="请输入备注"></uni-easyinput>
</uni-popup-dialog>
</uni-popup>
</view>
@@ -140,6 +116,7 @@ import { manualAccess } from '@/common/api/accessBoot'
import { MQTT_IP, MQTT_OPTIONS } from '@/common/js/mqtt.js'
import mqtt from 'mqtt/dist/mqtt.js'
import { base64ToPath, pathToBase64 } from 'image-tools'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
import hoverMenu from '@/hover-menu/components/hover-menu/hover-menu.vue'
export default {
components: {
@@ -164,6 +141,7 @@ export default {
navHeight: 0,
img: '',
topoImg: '',
targetLists: [],
navMenuList: [
{
text: '基本',
@@ -177,9 +155,6 @@ export default {
text: '功率',
id: 'a16aceae7d1565bf9f94dd7410cf9bce',
},
// {
// text: '波形',
// },
{
text: '其他',
},
@@ -358,11 +333,21 @@ export default {
},
})
},
init() {
getTarget() {
return queryByCode('app_harmonic_code').then((res) => {
return queryStatistical({ id: res.data.id }).then((resp) => {
this.targetLists = resp.data.selectedList
})
})
},
async init() {
console.log('init')
this.loading = true
this.domLoading = true
queryTopologyDiagram(this.devId).then((res) => {
await queryTopologyDiagram(this.devId).then((res) => {
res.data.filePath = this.$config.static + res.data.filePath
this.deviceInfo = res.data
this.downloadImg()
@@ -371,6 +356,7 @@ export default {
let index = this.deviceInfo.appsLineTopologyDiagramPO?.findIndex((element) => {
element.label = element.name
item.label = element.name
item.target = element.target
return element.linePostion === item.linePostion
})
if (index > -1) {
@@ -384,10 +370,14 @@ export default {
})
console.log(this.topolodyData)
if (this.client) {
this.client.publish(`/zl/askDevData/${this.devId}/${this.navMenuList[0].id}`)
this.loading = false
} else {
this.initMqtt(this.navMenuList[0].id)
}
console.log("🚀 ~ this.client:", this.client)
})
},
renderFinish(e) {
@@ -460,22 +450,28 @@ export default {
console.log('连接断开')
})
.on('message', (topic, message) => {
console.log('接收推送信息:', JSON.parse(message.toString()), topic)
console.log('🚀 ~ .on ~ topic:', topic)
// console.log('接收推送信息:', JSON.parse(message.toString()), topic)
// console.log('🚀 ~ .on ~ topic:', topic)
if (topic === `/zl/devData/${this.devId}/${id}`) {
const data = JSON.parse(message.toString())
if (Array.isArray(data) && !data.length) return
if ((!message.toString() || message.toString().length < 10) && this.loading) {
this.$util.toast('该设备暂无数据')
}
this.loading = false
this.handlerData(JSON.parse(message.toString()))
this.handlerData(data)
} else if (topic === `/zl/TemperData/${this.devId}`) {
const data = JSON.parse(message.toString())
if (Array.isArray(data) && !data.length) return
// this.basicData.forEach((item) => {
// if (item.statisticalName === '温度' && item.phase === 'avg') {
// item.statisticalData = message.toString()
// }
// })
this.IOData = JSON.parse(message.toString())
this.IOData = data
// this.IOData = this.IOData.filter((item) => item.value !== 0)
this.IOData.forEach((item) => {
if (!item.value) {
@@ -490,37 +486,60 @@ export default {
})
},
handlerData(data) {
async handlerData(data) {
this.basicData = data
this.topolodyData.forEach((element) => {
let arr = []
let list = this.targetLists.filter(key => key.dataType == element.target)
element.showKey.forEach((key) => {
if (list.length > 0) {
let id = list[0]?.eleEpdPqdVOS.filter(key => key.phase == 'A')[0]?.id || ''
data.forEach((item) => {
if (item.statisticalName === key && item.phase === 'avg') {
if (key === 'Apf_RmsI_TolOut(A)') {
arr.push({
label: '总输出电流:',
value: Math.round(item.statisticalData) + 'A',
})
} else {
arr.push({
label: '电流畸变率:',
value: Math.round(item.statisticalData) + '%',
})
// arr.push('电流畸变率:' + item.statisticalData + '%')
}
if (item.statisticalIndex === id && item.phase === 'avg') {
arr.push({
label: list[0].dataTypeName.split('-')[1] + ':',
value: (item.statisticalData) + `${item.unit || ''}`,
})
}
if (item.time) {
this.dataTime = item.time.seconds
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
// console.log(11111111,this.dataTime);
}
})
})
}
else {
element.showKey.forEach((key) => {
data.forEach((item) => {
if (item.statisticalName === key && item.phase === 'avg') {
if (key === 'Apf_RmsI_TolOut(A)') {
arr.push({
label: '总输出电流:',
value: (item.statisticalData) + 'A',
})
} else {
arr.push({
label: '电流畸变率:',
value: (item.statisticalData) + '%',
})
}
}
if (item.time) {
this.dataTime = item.time.seconds
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
}
})
})
}
element.value = arr
})
console.log("🚀 ~ this.topolodyData:", this.topolodyData)
console.log(this.topolodyData)
this.$forceUpdate()
},
@@ -539,13 +558,16 @@ export default {
}, 1000)
},
onLoad(options) {
async onLoad(options) {
await this.getTarget()
this.pageOptions = options
this.device = JSON.parse(options.device)
console.log('🚀 ~ options:', options)
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.devId = options.id
this.isPrimaryUser = options.isPrimaryUser
if (this.pageOptions.process == 2 || this.pageOptions.process == 3) {
this.content.splice(
0,
@@ -626,9 +648,11 @@ export default {
lng: '',
showKey: item.showKey, //要展示的指标key
value: [],
target: item.target
}
})
})
this.init()
},
}
@@ -636,6 +660,7 @@ export default {
<style lang="scss">
.detail {
// background: $uni-theme-white;
.header-bg {
position: absolute;
@@ -666,7 +691,7 @@ export default {
z-index: 2;
text-align: center;
color: #111;
width: 110rpx;
width: 150rpx;
font-size: 16rpx;
opacity: 0.8;

File diff suppressed because it is too large Load Diff

View File

@@ -6,13 +6,8 @@
<uni-forms-item label="设备识别码">
<view style="display: flex">
<uni-easyinput type="text" v-model="formData.nDid" placeholder="请输入设备识别码" />
<uni-icons
type="camera"
color="#007aff"
size="26"
class="ml20"
@click="scanCode"
></uni-icons>
<uni-icons type="camera" color="#007aff" size="26" class="ml20"
@click="scanCode"></uni-icons>
</view>
</uni-forms-item>
</uni-forms>
@@ -28,36 +23,18 @@
<uni-forms>
<uni-forms-item label="工程">
<view style="display: flex; align-items: center">
<uni-data-select
v-model="formData.engineeringId"
:localdata="engineeringList"
@change="engineeringChang($event, true)"
:clear="false"
></uni-data-select>
<uni-icons
type="plusempty"
color="#007aff"
size="26"
class="ml20"
@click="createEngineering"
></uni-icons>
<uni-data-select v-model="formData.engineeringId" :localdata="engineeringList"
@change="engineeringChang($event, true)" :clear="false"></uni-data-select>
<uni-icons type="plusempty" color="#007aff" size="26" class="ml20"
@click="createEngineering"></uni-icons>
</view>
</uni-forms-item>
<uni-forms-item label="项目">
<view style="display: flex; align-items: center">
<uni-data-select
v-model="formData.projectId"
:localdata="projectRange"
@change="queryTopologyDiagramPage"
:clear="false"
></uni-data-select>
<uni-icons
type="plusempty"
color="#007aff"
size="26"
class="ml20"
@click="createProject"
></uni-icons>
<uni-data-select v-model="formData.projectId" :localdata="projectRange"
@change="queryTopologyDiagramPage" :clear="false"></uni-data-select>
<uni-icons type="plusempty" color="#007aff" size="26" class="ml20"
@click="createProject"></uni-icons>
</view>
</uni-forms-item>
@@ -69,25 +46,14 @@
</view>
<view v-else class="gplot gplot-empty center" @click="chooseGplot"> 选择拓扑图</view>
</view>
<uni-icons
type="image"
color="#007aff"
size="26"
class="ml20"
@click="chooseGplot"
></uni-icons>
<uni-icons type="image" color="#007aff" size="26" class="ml20"
@click="chooseGplot"></uni-icons>
</view>
</uni-forms-item>
<uni-forms-item
label="监测点"
v-if="pointList.length && formData.topologyDiagramUrl && formData.projectId"
>
<view
class="point-item"
v-for="(item2, index2) in pointList"
:key="index2"
@click="editPoint(item2, index2)"
>
<uni-forms-item label="监测点"
v-if="pointList.length && formData.topologyDiagramUrl && formData.projectId">
<view class="point-item" v-for="(item2, index2) in pointList" :key="index2"
@click="editPoint(item2, index2)">
<view style="flex: 1" v-if="item2.name">{{ item2.name }}</view>
<view style="flex: 1; color: #999" v-else>请选择监测点</view>
<uni-icons type="compose" color="#007aff" size="26" class="ml20"></uni-icons>
@@ -106,17 +72,10 @@
<uni-drawer ref="gplot" mode="right" :mask-click="false">
<scroll-view style="height: 100%" scroll-y="true">
<view class="content">
<image
class="gplot gplot-box"
mode="aspectFill"
:class="{ 'gplot-active': key == activeGplot }"
:src="item.filePath"
@click="activeGplot = key"
v-for="(item, key) in imageList"
:key="key"
/>
<view v-if="imageList.length === 0" style="text-align: center" class="mt50 mb50"
>暂无拓扑图
<image class="gplot gplot-box" mode="aspectFill" :class="{ 'gplot-active': key == activeGplot }"
:src="item.filePath" @click="activeGplot = key" v-for="(item, key) in imageList"
:key="key" />
<view v-if="imageList.length === 0" style="text-align: center" class="mt50 mb50">暂无拓扑图
</view>
<view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -142,22 +101,18 @@
</view>
<view class="content">
<view class="content-des">请拖动图中的文字选择监测点位置</view>
<uni-forms>
<uni-data-select
v-model="point.position"
:localdata="positionList"
@change="positionChange"
disabled
:clear="false"
></uni-data-select>
<uni-easyinput
:clearable="false"
class="mt20"
type="text"
v-model="point.alias"
@change="aliasChange"
placeholder="别名(非必填)"
/>
<uni-forms labelWidth="70px">
<uni-forms-item label="位置">
<uni-data-select v-model="point.position" :localdata="positionList"
@change="positionChange" disabled :clear="false"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="别名">
<uni-easyinput :clearable="false" type="text" v-model="point.alias"
@change="aliasChange" placeholder="别名(非必填)" />
</uni-forms-item>
<uni-forms-item label="绑定指标">
<uni-data-select v-model="point.target" :localdata="targetList"></uni-data-select>
</uni-forms-item>
</uni-forms>
<view class="btn-wrap">
<view class="btn-wrap-item" @click="closeDrawer"> 取消</view>
@@ -181,6 +136,7 @@ import {
} from '@/common/api/device.js'
import { getProjectList, queryTopologyDiagramPage } from '@/common/api/project.js'
import ykAuthpup from '@/components/yk-authpup/yk-authpup'
import { queryByCode, queryStatistical } from '@/common/api/dictionary'
export default {
components: {
ykAuthpup,
@@ -204,6 +160,8 @@ export default {
activeGplot: 0,
positionList: [],
imageList: [],
targetLists: [],//总数据
targetList: [],//根据位置切换数据
isAdaptive: false, // 是否适应当前项目
dialogOpen: false,
options: {},
@@ -226,9 +184,20 @@ export default {
onLoad(o) {
this.options = o
let dictData = uni.getStorageSync(this.$cacheKey.dictData)
queryByCode('app_harmonic_code').then((res) => {
queryStatistical({ id: res.data.id }).then((resp) => {
this.targetLists = resp.data.selectedList.map((item) => {
return {
...item,
text: item.dataTypeName,
value: item.dataType,
}
})
})
})
dictData.forEach((item) => {
if (item.code == 'Line_Position') {
this.positionList = item.children.map((item) => {
this.positionList = item.children.filter((child) => child.name !== 'PCC公共点').map((item) => {
return {
...item,
text: item.name,
@@ -264,6 +233,19 @@ export default {
// })
},
methods: {
// 设置绑定指标
settarget(e) {
let pointName = this.positionList.find((item) => item.id == this.point.position).name
this.targetList = this.targetLists.filter(item => item.dataTypeName.includes(pointName)).map((item) => {
return {
...item,
text: item.dataTypeName.split('-')[1],
value: item.dataType,
}
})
},
getEngineering() {
queryEngineeringPage({ pageNum: 1, pageSize: 9999 }).then((res) => {
let arr = [
@@ -377,7 +359,7 @@ export default {
console.log(e)
},
projectChange(e) {},
projectChange(e) { },
scanCode() {
if (plus.os.name == 'Android') {
this.$refs['authpup'].open()
@@ -509,6 +491,7 @@ export default {
this.point.alias = ''
}
}
this.settarget()
this.dialogOpen = true
this.$refs.point.open()
this.$forceUpdate()

View File

@@ -739,126 +739,129 @@ export default {
// console.log('接收推送信息:', JSON.parse(message.toString()), topic)
if (!this.connection) return
// console.log('🚀 ~ .on ~ topic:', topic, this.userInfo.userIndex)
if (topic == `/Web/RealData/${this.lineId}`) {
if (
topic == `/Web/RealData/${this.lineId}` ||
topic == `/Web/RealData/${this.userInfo.userIndex}`
) {
let list = JSON.parse(message.toString())
if (list.lineId != this.lineId) return
// if (list.userId == this.userInfo.userIndex) {
// console.log(list)
this.realTime = list.dataTime
let pt = list.pt || 0
let ct = list.ct || 0
// console.log(list)
this.realTime = list.dataTime
let pt = list.pt || 0
let ct = list.ct || 0
let data = {
vRmsA: ((list.vRmsA * pt) / 1000).toFixed(2),
vRmsB: ((list.vRmsB * pt) / 1000).toFixed(2),
vRmsC: ((list.vRmsC * pt) / 1000).toFixed(2),
iRmsA: (list.iRmsA * ct).toFixed(2),
iRmsB: (list.iRmsB * ct).toFixed(2),
iRmsC: (list.iRmsC * ct).toFixed(2),
v1A: ((list.v1A * pt) / 1000).toFixed(2),
v1B: ((list.v1B * pt) / 1000).toFixed(2),
v1C: ((list.v1C * pt) / 1000).toFixed(2),
v1AngA: list.v1AngA.toFixed(2),
v1AngB: list.v1AngB.toFixed(2),
v1AngC: list.v1AngC.toFixed(2),
let data = {
vRmsA: ((list.vRmsA * pt) / 1000).toFixed(2),
vRmsB: ((list.vRmsB * pt) / 1000).toFixed(2),
vRmsC: ((list.vRmsC * pt) / 1000).toFixed(2),
iRmsA: (list.iRmsA * ct).toFixed(2),
iRmsB: (list.iRmsB * ct).toFixed(2),
iRmsC: (list.iRmsC * ct).toFixed(2),
v1A: ((list.v1A * pt) / 1000).toFixed(2),
v1B: ((list.v1B * pt) / 1000).toFixed(2),
v1C: ((list.v1C * pt) / 1000).toFixed(2),
v1AngA: list.v1AngA.toFixed(2),
v1AngB: list.v1AngB.toFixed(2),
v1AngC: list.v1AngC.toFixed(2),
i1A: (list.i1A * ct).toFixed(2),
i1B: (list.i1B * ct).toFixed(2),
i1C: (list.i1C * ct).toFixed(2),
i1AngA: list.i1AngA.toFixed(2),
i1AngB: list.i1AngB.toFixed(2),
i1AngC: list.i1AngC.toFixed(2),
vDevA: list.vDevA.toFixed(2),
vDevB: list.vDevB.toFixed(2),
vDevC: list.vDevC.toFixed(2),
vThdA: list.vThdA.toFixed(2),
vThdB: list.vThdB.toFixed(2),
vThdC: list.vThdC.toFixed(2),
i1A: (list.i1A * ct).toFixed(2),
i1B: (list.i1B * ct).toFixed(2),
i1C: (list.i1C * ct).toFixed(2),
i1AngA: list.i1AngA.toFixed(2),
i1AngB: list.i1AngB.toFixed(2),
i1AngC: list.i1AngC.toFixed(2),
vDevA: list.vDevA.toFixed(2),
vDevB: list.vDevB.toFixed(2),
vDevC: list.vDevC.toFixed(2),
vThdA: list.vThdA.toFixed(2),
vThdB: list.vThdB.toFixed(2),
vThdC: list.vThdC.toFixed(2),
}
this.realTimeData = [
{ name: '电压有效值(kV)', A: data.vRmsA, B: data.vRmsB, C: data.vRmsC },
{ name: '电流有效值(A)', A: data.iRmsA, B: data.iRmsB, C: data.iRmsC },
{ name: '基波电压幅值(kV)', A: data.v1A, B: data.v1B, C: data.v1C },
{ name: '基波电压相位(°)', A: data.v1AngA, B: data.v1AngB, C: data.v1AngC },
{ name: '基波电流幅值(A)', A: data.i1A, B: data.i1B, C: data.i1C },
{ name: '基波电流相位(°)', A: data.i1AngA, B: data.i1AngB, C: data.i1AngC },
{ name: '电压偏差(%)', A: data.vDevA, B: data.vDevB, C: data.vDevC },
{ name: '电压总谐波畸变率(%)', A: data.vThdA, B: data.vThdB, C: data.vThdC },
]
// 电压
let vMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.vRmsA * 100) / 100 || 1,
Math.floor(data.vRmsB * 100) / 100 || 1,
Math.floor(data.vRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataV1.series[0].max = vMax
this.echartsDataV2.series[0].max = vMax
this.echartsDataV3.series[0].max = vMax
this.echartsDataV1.series[0].data[0].value = data.vRmsA
this.echartsDataV2.series[0].data[0].value = data.vRmsB
this.echartsDataV3.series[0].data[0].value = data.vRmsC
// 电流
let aMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.iRmsA * 100) / 100 || 1,
Math.floor(data.iRmsB * 100) / 100 || 1,
Math.floor(data.iRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataA1.series[0].max = aMax
this.echartsDataA2.series[0].max = aMax
this.echartsDataA3.series[0].max = aMax
this.echartsDataA1.series[0].data[0].value = data.iRmsA
this.echartsDataA2.series[0].data[0].value = data.iRmsB
this.echartsDataA3.series[0].data[0].value = data.iRmsC
this.echartsData0.series[0].data[0].value = data.i1AngA
this.echartsData0.series[0].data[1].value = data.i1AngB
this.echartsData0.series[0].data[2].value = data.i1AngC
this.echartsData1.series[0].data[0].value = data.v1AngA
this.echartsData1.series[0].data[1].value = data.v1AngB
this.echartsData1.series[0].data[2].value = data.v1AngC
const charts = [
{ instance: this.echart0, data: this.echartsData0 },
{ instance: this.echart1, data: this.echartsData1 },
{ instance: this.echartV1, data: this.echartsDataV1 },
{ instance: this.echartV2, data: this.echartsDataV2 },
{ instance: this.echartV3, data: this.echartsDataV3 },
{ instance: this.echartA1, data: this.echartsDataA1 },
{ instance: this.echartA2, data: this.echartsDataA2 },
{ instance: this.echartA3, data: this.echartsDataA3 },
]
charts.forEach(({ instance, data }) => {
if (instance && instance.setOption) {
instance.setOption(data, true)
}
this.realTimeData = [
{ name: '电压有效值(kV)', A: data.vRmsA, B: data.vRmsB, C: data.vRmsC },
{ name: '电流有效值(A)', A: data.iRmsA, B: data.iRmsB, C: data.iRmsC },
{ name: '基波电压幅值(kV)', A: data.v1A, B: data.v1B, C: data.v1C },
{ name: '基波电压相位(°)', A: data.v1AngA, B: data.v1AngB, C: data.v1AngC },
{ name: '基波电流幅值(A)', A: data.i1A, B: data.i1B, C: data.i1C },
{ name: '基波电流相位(°)', A: data.i1AngA, B: data.i1AngB, C: data.i1AngC },
{ name: '电压偏差(%)', A: data.vDevA, B: data.vDevB, C: data.vDevC },
{ name: '电压总谐波畸变率(%)', A: data.vThdA, B: data.vThdB, C: data.vThdC },
]
// 电压
let vMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.vRmsA * 100) / 100 || 1,
Math.floor(data.vRmsB * 100) / 100 || 1,
Math.floor(data.vRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataV1.series[0].max = vMax
this.echartsDataV2.series[0].max = vMax
this.echartsDataV3.series[0].max = vMax
this.echartsDataV1.series[0].data[0].value = data.vRmsA
this.echartsDataV2.series[0].data[0].value = data.vRmsB
this.echartsDataV3.series[0].data[0].value = data.vRmsC
})
// 电流
let aMax =
Math.ceil(
(Math.max(
...[
Math.floor(data.iRmsA * 100) / 100 || 1,
Math.floor(data.iRmsB * 100) / 100 || 1,
Math.floor(data.iRmsC * 100) / 100 || 1,
],
) *
1.2) /
10,
) * 10
this.echartsDataA1.series[0].max = aMax
this.echartsDataA2.series[0].max = aMax
this.echartsDataA3.series[0].max = aMax
this.echartsDataA1.series[0].data[0].value = data.iRmsA
this.echartsDataA2.series[0].data[0].value = data.iRmsB
this.echartsDataA3.series[0].data[0].value = data.iRmsC
this.echartsData0.series[0].data[0].value = data.i1AngA
this.echartsData0.series[0].data[1].value = data.i1AngB
this.echartsData0.series[0].data[2].value = data.i1AngC
this.echartsData1.series[0].data[0].value = data.v1AngA
this.echartsData1.series[0].data[1].value = data.v1AngB
this.echartsData1.series[0].data[2].value = data.v1AngC
const charts = [
{ instance: this.echart0, data: this.echartsData0 },
{ instance: this.echart1, data: this.echartsData1 },
{ instance: this.echartV1, data: this.echartsDataV1 },
{ instance: this.echartV2, data: this.echartsDataV2 },
{ instance: this.echartV3, data: this.echartsDataV3 },
{ instance: this.echartA1, data: this.echartsDataA1 },
{ instance: this.echartA2, data: this.echartsDataA2 },
{ instance: this.echartA3, data: this.echartsDataA3 },
]
charts.forEach(({ instance, data }) => {
if (instance && instance.setOption) {
instance.setOption(data, true)
}
})
// this.echart0.setOption(this.echartsData0, true)
// this.echart1.setOption(this.echartsData1, true)
// this.echartV1.setOption(this.echartsDataV1, true)
// this.echartV2.setOption(this.echartsDataV2, true)
// this.echartV3.setOption(this.echartsDataV3, true)
// this.echartA1.setOption(this.echartsDataA1, true)
// this.echartA2.setOption(this.echartsDataA2, true)
// this.echartA3.setOption(this.echartsDataA3, true)
// this.echart0.setOption(this.echartsData0, true)
// this.echart1.setOption(this.echartsData1, true)
// this.echartV1.setOption(this.echartsDataV1, true)
// this.echartV2.setOption(this.echartsDataV2, true)
// this.echartV3.setOption(this.echartsDataV3, true)
// this.echartA1.setOption(this.echartsDataA1, true)
// this.echartA2.setOption(this.echartsDataA2, true)
// this.echartA3.setOption(this.echartsDataA3, true)
// }
}
})
@@ -1029,7 +1032,8 @@ export default {
.table-row {
display: flex;
justify-content: space-between;
padding: 20rpx 30rpx;
padding: 15rpx 30rpx;
height: 20px;
border-bottom: 1rpx solid #eee;
text {
flex: 1;

View File

@@ -24,9 +24,10 @@
</view>
<view class="content" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0">
<!-- extra="🔍" -->
<uni-card
:title="item.name"
extra="🔍"
@click="jumpProject(item)"
v-for="(item, index) in store.data"
:key="index"
@@ -258,7 +259,7 @@ export default {
.term-list-bottom {
.term-list-bottom-item {
font-size: 28rpx;
margin-bottom: 20rpx;
// margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
// view:first-of-type{
@@ -270,4 +271,10 @@ export default {
margin-bottom: 0;
}
}
/deep/ .uni-card__content {
padding: 5px 10px 10px !important;
}
/deep/ .uni-card__header-content-title {
font-weight: 700;
}
</style>

View File

@@ -14,7 +14,8 @@
<uni-swipe-action-item v-for="(item, index) in store.data"
:style="{ marginTop: index === 0 ? '0' : '' }" :key="index" :threshold="0"
:right-options="item.isTop == 0 ? options1 : options12" @click="bindClick($event, item)">
<uni-card class="boxClick" :title="item.name" extra="🔍" @click="jump(item)">
<!-- extra="🔍" -->
<uni-card class="boxClick" :title="item.name" @click="jump(item)">
<view class="term-list-bottom">
<view class="term-list-bottom-item">
<view>区域</view>

View File

@@ -142,6 +142,7 @@ export default {
},
computed: {
deviceListFilter() {
let arr = this.store.data.filter((item) => {
if (this.select.projectName && this.select.projectType) {
return item.project === this.select.projectName && item.type === this.select.projectType

View File

@@ -151,8 +151,8 @@ export default {
// 存储参数
uni.setStorageSync('messageParams', {
engineeringName: this.device.engineeringName,
engineeringId: this.device.engineeringId, //工程ID
engineeringName: item.engineeringName,
engineeringId: item.engineeringId, //工程ID
projectName: '',
projectId: '', //項目ID
deviceName: '',

View File

@@ -0,0 +1,349 @@
<template>
<view class="dashboard-container">
<!-- 页面头部 -->
<view class="page-header">
<Cn-filterInformation @select="select" />
<view class="legend-row">
<view class="legend-item">
<view class="legend-color" style="background:#DAA520"></view>
<text class="legend-text">A相</text>
</view>
<view class="legend-item">
<view class="legend-color" style="background:#2E8B57"></view>
<text class="legend-text">B相</text>
</view>
<view class="legend-item">
<view class="legend-color" style="background:#A52A2A"></view>
<text class="legend-text">C相</text>
</view>
</view>
</view>
<!-- 监测点列表 - 竖向滚动 -->
<scroll-view class="monitors-scroll" scroll-y :show-scrollbar="true">
<view class="monitors-list">
<view v-for="(point, idx) in monitoringPoints" :key="idx" class="monitor-card">
<!-- 卡片头部 -->
<view class="card-header">
<view class="event-icon">
<Cn-icon-transient :name="`监测点`" />
</view>
<view class="card-header-info">
<view class="point-name">
<text class="point-text ellipsis">{{ point.pointName }}</text>
</view>
<view class="meta-row">
<text class="meta-item ellipsis">工程: {{ point.projectName }}</text>
<text class="meta-item ellipsis">项目: {{ point.siteName }}</text>
<text class="meta-item ellipsis meta-item-full">设备: {{ point.deviceName }}</text>
</view>
</view>
</view>
<!-- 参数区域使用 children 数据循环每两个指标放一行 -->
<view class="params-section">
<view v-for="(rowItems, rowIdx) in chunkedChildren(point.children)" :key="rowIdx"
class="double-row">
<view v-for="(child, childIdx) in rowItems" :key="childIdx" class="param-group">
<view class="param-title">
<text>{{ child.name }}</text>
</view>
<!-- 三相数据颜色区分无文字 -->
<view class="phase-vertical">
<view class="phase-item-vertical">
<text class="phase-value-vertical" style="color:#DAA520">{{ child.A }}</text>
</view>
<view class="phase-divider"></view>
<view class="phase-item-vertical">
<text class="phase-value-vertical" style="color:#2E8B57">{{ child.B }}</text>
</view>
<view class="phase-divider"></view>
<view class="phase-item-vertical">
<text class="phase-value-vertical" style="color:#A52A2A">{{ child.C }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
// 监测点基础信息 + children 指标数据
monitoringPoints: [
{
pointName: "升压站#1主变测点",
projectName: "华光100MW工程11111",
siteName: "绿色智慧能源11111",
deviceName: "PMC-800终端",
children: [
{ name: '电压有效值(kV)', A: '10.52', B: '10.45', C: '10.39' },
{ name: '电流有效值(A)', A: '408.0', B: '395.0', C: '403.0' },
{ name: '基波电压幅值(kV)', A: '10.48', B: '10.42', C: '10.35' },
{ name: '基波电流幅值(A)', A: '405.5', B: '392.8', C: '400.2' }
]
},
{
pointName: "光伏区#3汇流箱",
projectName: "华光100MW工程",
siteName: "绿色智慧能源示范",
deviceName: "汇流监测单元",
children: [
{ name: '电压有效值(kV)', A: '10.72', B: '10.65', C: '10.59' },
{ name: '电流有效值(A)', A: '426.0', B: '413.0', C: '421.0' },
{ name: '基波电压幅值(kV)', A: '10.68', B: '10.62', C: '10.55' },
{ name: '基波电流幅值(A)', A: '423.5', B: '410.8', C: '418.2' }
]
},
],
// 三相颜色配置
phaseColors: [
{ name: 'A相', color: '#DAA520' },
{ name: 'B相', color: '#2E8B57' },
{ name: 'C相', color: '#A52A2A' }
]
}
},
methods: {
// 将 children 数组每两个一组进行分组,用于一行显示两个指标
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
select(value) {
console.log("🚀 ~ value:", value)
},
}
}
</script>
<style>
* {
box-sizing: border-box;
}
.dashboard-container {
min-height: 100vh;
background: #f5f7fb;
padding: 20rpx 20rpx 0rpx 20rpx;
display: flex;
flex-direction: column;
}
/* 头部样式 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
flex-shrink: 0;
}
.title-section {
display: flex;
align-items: baseline;
gap: 12rpx;
}
.title-icon {
font-size: 40rpx;
}
.title {
font-size: 34rpx;
font-weight: 700;
color: #2c3e50;
}
/* 图例 */
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 6rpx;
}
.legend-color {
width: 24rpx;
height: 24rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #333;
font-weight: 500;
}
/* 竖向滚动区域 */
.monitors-scroll {
flex: 1;
max-height: calc(100vh - 100rpx);
}
.monitors-list {
display: flex;
flex-direction: column;
gap: 20rpx;
padding-bottom: 20rpx;
}
/* 卡片样式 */
.monitor-card {
background: #ffffff;
border-radius: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
display: flex;
flex-direction: column;
border: 1rpx solid #e8ecf0;
}
.card-header {
padding: 20rpx 20rpx 10rpx 20rpx;
border-bottom: 1rpx solid #eef2f6;
display: flex;
align-items: center;
}
.card-header-info {
flex: 1;
min-width: 0;
overflow: hidden;
}
.point-name {
margin-bottom: 4rpx;
}
.point-text {
display: block;
font-size: 30rpx;
font-weight: 700;
color: #333333;
}
/* 工程、项目、设备:两列布局,超出显示省略号 */
.meta-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6rpx 8rpx;
width: 100%;
}
.meta-item {
display: block;
min-width: 0;
font-size: 24rpx;
color: #666666;
line-height: 1.3;
}
.meta-item-full {
grid-column: 1 / -1;
}
/* 参数区域 */
.params-section {
padding: 20rpx 16rpx 24rpx 16rpx;
flex: 1;
}
.double-row {
display: flex;
gap: 16rpx;
margin-bottom: 16rpx;
flex-wrap: wrap;
}
.double-row:last-child {
margin-bottom: 0;
}
.param-group {
flex: 1;
min-width: 200rpx;
background: transparent;
border-radius: 20rpx;
padding: 12rpx 8rpx 8rpx;
border: 1rpx solid #e8ecf0;
}
.param-title {
font-size: 24rpx;
color: #666666;
font-weight: 650;
margin-bottom: 4rpx;
display: flex;
align-items: center;
gap: 8rpx;
padding-left: 4rpx;
}
/* 三相数据垂直布局 */
.phase-vertical {
display: flex;
align-items: stretch;
justify-content: space-between;
gap: 0;
}
.phase-item-vertical {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 4rpx 4rpx;
}
.phase-value-vertical {
font-size: 28rpx;
font-weight: 700;
display: block;
letter-spacing: -0.5rpx;
}
/* 竖线分割 */
.phase-divider {
width: 1rpx;
background-color: #e0e4e8;
margin: 8rpx 0;
}
/* 文字溢出显示省略号 */
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
.event-icon {
position: relative;
width: 110rpx;
height: 110rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
background-color: #376cf320;
}
</style>

View File

@@ -1,33 +1,20 @@
<template>
<Cn-page :loading="loading" noPadding>
<view slot="body" class="canneng-index">
<uni-nav-bar
rightWidth="300rpx"
leftWidth="300rpx"
dark
:fixed="true"
status-bar
background-color="#fff"
color="#111"
@clickRight="selectEngineering"
>
<uni-nav-bar rightWidth="300rpx" leftWidth="300rpx" dark :fixed="true" status-bar background-color="#fff"
color="#111" @clickRight="selectEngineering">
<template slot="left">
<text style="font-size: 32rpx; font-weight: 500">灿能物联</text>
</template>
<template slot="right">
<text class="hide-txt mr5" style="font-size: 28rpx"
>{{
userInfo.authorities === 'engineering_user'
? '创建工程'
: select.engineeringName || emptyEngineeringName
}}
<text class="hide-txt mr5" style="font-size: 28rpx">{{
userInfo.authorities === 'engineering_user'
? '创建工程'
: select.engineeringName || emptyEngineeringName
}}
</text>
<uni-icons
type="bottom"
size="16"
color="#111"
v-if="select.engineeringName && userInfo.authorities != 'engineering_user'"
></uni-icons>
<uni-icons type="bottom" size="16" color="#111"
v-if="select.engineeringName && userInfo.authorities != 'engineering_user'"></uni-icons>
</template>
</uni-nav-bar>
<view class="index">
@@ -48,7 +35,10 @@
</template>
<!-- 设备列表 -->
<template v-else v-show="engineeringList.length">
<view class="canneng-index-title mt20">设备列表</view>
<view class="canneng-index-title mt20">
<view>设备列表</view>
<view class="nav-menu nav-menu-btn boxClick" @click="jump">电能质量信息 </view>
</view>
<Device ref="device" :store="store" />
</template>
</view>
@@ -227,6 +217,11 @@ export default {
})
},
// 动态配置导航栏按钮
jump() {
uni.navigateTo({
url: `/pages/index/comp/monitoringPoint`,
})
}
},
onLoad() {
// 页面加载时,动态配置导航栏按钮
@@ -308,6 +303,7 @@ export default {
.canneng-index-title {
padding: 0 20rpx;
font-weight: 500;
display: flex;
}
/deep/ .uni-card {
@@ -317,4 +313,28 @@ export default {
/deep/ .uni-drawer__content {
width: 100vw !important;
}
.nav-menu {
height: 40rpx;
padding: 4rpx 20rpx;
// margin-left: 20rpx;
// margin-bottom: 20rpx;
line-height: 38rpx;
font-size: 24rpx;
border-radius: 8rpx;
background: #ebeaec;
color: #666;
&-active {
background: #dfe5f7;
color: $uni-theme-color;
}
&-btn {
background: $uni-theme-color;
color: #fff;
}
margin-left: auto;
}
</style>

View File

@@ -2,13 +2,8 @@
<Cn-page :loading="loading" class="messageBox" style="padding-top: 10px">
<view slot="body" class="message">
<view class="tabsBox">
<uni-segmented-control
:current="current"
:values="items"
style-type="text"
active-color="#376cf3"
@clickItem="onClickItem"
/>
<uni-segmented-control :current="current" :values="items" style-type="text" active-color="#376cf3"
@clickItem="onClickItem" />
<!-- 角标 -->
<view class="badge-container">
<span v-for="(item, index) in items" :key="index" class="badge">
@@ -17,59 +12,28 @@
</span>
</view>
<!-- 筛选条件 -->
<Cn-filterCriteria
ref="cnFilterCriteria"
:level="current === 0 ? 3 : current === 1 ? 3 : 2"
@select="select"
>
<picker
v-if="current === 0"
@change="bindPickerChange"
:value="sortIndex"
:range="sortOptions"
style="margin-left: auto"
>
<view class="sort-picker">
{{ sortOptions[sortIndex] }}排序
<uni-icons
custom-prefix="iconfont"
type="icon-paixu1"
size="10"
color="#2563EB"
></uni-icons>
<Cn-filterCriteria ref="cnFilterCriteria" :level="current === 0 ? 3 : current === 1 ? 3 : 2"
@select="select">
<picker v-if="current === 0" @change="bindPickerChange" :value="sortIndex" :range="sortOptions">
<view class="nav-menu nav-menu1">
<view class="nav-text">
{{ sortOptions[sortIndex] }}排序
</view>
<uni-icons type="bottom" size="14"></uni-icons>
</view>
</picker>
</Cn-filterCriteria>
</view>
<view class="content">
<Transient
ref="TransientRef"
v-if="current === 0"
:navHeight="navHeight"
:selectValue="selectValue"
@getDevCount="getDevCount"
/>
<SteadyState
ref="SteadyStateRef"
v-if="current === 1"
:navHeight="navHeight"
:selectValue="selectValue"
@getDevCount="getDevCount"
/>
<Alarm
ref="AlarmRef"
v-if="current === 2"
:navHeight="navHeight"
:selectValue="selectValue"
@getDevCount="getDevCount"
/>
<Run
ref="RunRef"
v-if="current === 3"
:navHeight="navHeight"
:selectValue="selectValue"
@getDevCount="getDevCount"
/>
<Transient ref="TransientRef" v-if="current === 0" :navHeight="navHeight" :selectValue="selectValue"
:sortIndex="sortIndex" @getDevCount="getDevCount" />
<SteadyState ref="SteadyStateRef" v-if="current === 1" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" />
<Alarm ref="AlarmRef" v-if="current === 2" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" />
<Run ref="RunRef" v-if="current === 3" :navHeight="navHeight" :selectValue="selectValue"
@getDevCount="getDevCount" />
</view>
</view>
</Cn-page>
@@ -100,7 +64,7 @@ export default {
sortOptions: ['发生时间', '暂降深度', '持续时间'],
}
},
onLoad() {},
onLoad() { },
mounted() {
this.setHeight()
},
@@ -204,9 +168,11 @@ export default {
},
bindPickerChange(e) {
this.sortIndex = e.detail.value
if (this.$refs.TransientRef) {
this.$refs.TransientRef.setSort(this.sortIndex)
}
setTimeout(() => {
if (this.$refs.TransientRef) {
this.$refs.TransientRef.init()
}
}, 0)
},
// 设置角标
getDevCount() {
@@ -275,13 +241,16 @@ export default {
<style lang="scss">
.messageBox {
overflow: hidden;
/deep/.tabsBox {
position: relative;
background-color: #fff;
.segmented-control {
// height: 40px;
background-color: #fff;
border-bottom: 1px solid #cccccc70;
.segmented-control__item {
align-items: baseline;
margin-top: 5px;
@@ -292,10 +261,12 @@ export default {
font-size: 30rpx !important;
color: rgb(96, 98, 102);
}
.segmented-control__item--text {
font-weight: bold;
padding: 0 0 5rpx;
}
.choose {
// padding: 20rpx;
// display: flex;
@@ -309,16 +280,20 @@ export default {
width: 90%;
margin: 20rpx auto;
}
.badge-container {
position: absolute;
top: -10rpx; /* 徽章向上偏移,与控件重叠 */
top: -10rpx;
/* 徽章向上偏移,与控件重叠 */
display: flex;
justify-content: space-around;
right: 0;
width: 100%;
height: 0;
pointer-events: none; /* 确保徽章不干扰点击事件 */
pointer-events: none;
/* 确保徽章不干扰点击事件 */
}
/deep/ .uni-badge--error {
background-color: #ff3b30;
}
@@ -326,6 +301,7 @@ export default {
.badge {
flex: 1;
text-align: center;
.uni-badge--x {
left: 70rpx;
}
@@ -339,4 +315,32 @@ export default {
white-space: nowrap;
}
}
.nav-menu {
display: flex;
align-items: center;
}
.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

@@ -52,6 +52,7 @@
<view class="mine-nav-label">项目管理</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view>
<view class="mine-nav" @click="jump('feedback')" v-if="userInfo.authorities !== 'tourist'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/feedback.png" />
<view class="mine-nav-label">反馈列表</view>
@@ -81,12 +82,11 @@
<view class="mine-nav-label">关注工程配置</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view>
<view class="mine-nav" @click="jump('transientSetting')" v-if="userInfo.authorities !== 'tourist'">
<!-- 调试内容配置 serverSetting-->
<!-- <view class="mine-nav" @click="jump('transientSetting')" v-if="userInfo.authorities !== 'tourist'">
<image mode="aspectFill" class="mine-nav-icon" src="/static/tongji.png" />
<view class="mine-nav-label">暂态统计配置</view>
<uni-icons type="forward" color="#aaa" size="20"></uni-icons>
</view>
</view> -->
<view class="mine-nav" @click="jump('setup')" style="border-bottom: none">
<image mode="aspectFill" class="mine-nav-icon" src="/static/setup.png" />
<view class="mine-nav-label">设置</view>

View File

@@ -3,23 +3,12 @@
<!-- 运行告警 -->
<!-- 卡片 -->
<scroll-view
scroll-y="true"
@refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower"
:refresher-triggered="triggered"
refresher-enabled="true"
class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }"
>
<scroll-view scroll-y="true" @refresherrefresh="refresherrefresh" @scrolltolower="scrolltolower"
:refresher-triggered="triggered" refresher-enabled="true" class="event-list"
:style="{ height: 'calc(100vh - ' + (navHeight + 10) + 'px)', overflow: 'auto' }">
<!-- 循环渲染事件项 -->
<uni-card
class="event-item boxClick"
:class="item.type"
v-for="(item, index) in this.store.data"
:key="index"
@click="jump(item)"
>
<uni-card class="event-item boxClick" :class="item.type" v-for="(item, index) in this.store.data"
:key="index" @click="jump(item)">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view class="event-icon">
@@ -39,8 +28,9 @@
</view>
<view class="event-desc">
<text>告警终端总数{{ item.warnNums }}</text>
<text>质量指标告警终端数{{ item.interruptCounts }}</text>
<text>事件触发告警终端数{{ item.warnCounts }}</text>
<text v-if="item.onlineRateIsWarn ">在线率偏低</text>
<text v-if="item.integrityIsWarn">完整性偏低</text>
<text v-if="item.warnCounts > 0">事件触发终端告警{{ item.warnCounts }}</text>
</view>
</view>
@@ -52,10 +42,8 @@
<text> 告警终端总数{{ item.warnNums }} </text>
</view> -->
</uni-card>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
<uni-load-more v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"></uni-load-more>
<Cn-empty v-else style="top: 20%"></Cn-empty>
</scroll-view>
</view>
@@ -102,8 +90,9 @@ export default {
},
jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比')
item.status = '1'
uni.navigateTo({ url: '/pages/message1/comp/alarmDetails?detail=' + encodeURIComponent(str) })
item.isRead = 1
},
// 下拉
refresherrefresh() {
@@ -138,6 +127,7 @@ export default {
<style lang="scss" scoped>
@import './index.scss';
/* 列表容器 */
.event-list {
margin-top: 20rpx;

View File

@@ -225,7 +225,7 @@ export default {
// 点击查看详情
let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比')
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
// uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
})
},
},

View File

@@ -217,7 +217,7 @@ export default {
// 点击查看详情
let item = params.value[3]
let str = JSON.stringify(item).replace(/%/g, '百分比')
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
// uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
})
},
},

View File

@@ -13,10 +13,8 @@
<uni-card class="event-item" :class="item.type" v-for="(item, index) in list" :key="index">
<!-- 头部图标 + 信息 + 操作 -->
<view class="event-header">
<view
class="event-icon"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'"
>
<view class="event-icon"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-bgc' : 'jc-bgc'">
<!-- 动态图标根据类型切换 -->
<!-- <uni-icons
custom-prefix="iconfont"
@@ -25,46 +23,55 @@
color="#FF0000"
></uni-icons> -->
<!-- <Cn-icon-transient :name="`运行告警`" /> -->
<Cn-icon-transient
:name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'"
/>
<Cn-icon-transient :name="item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备'" />
<view class="badge1" v-if="item.status == 0"> </view>
</view>
<view class="event-info">
<view class="event-title">
<text class="event-id">{{ item.devName }}</text>
<text
class="event-tag"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'"
>{{ item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text
>
<text class="event-tag"
:class="item.devType == 'Direct_Connected_Device' ? 'zl-tag' : 'jc-tag'">{{
item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<!-- <text v-if="item.dataDetails.onlineRate.isAbnormal">在线率{{
item.dataDetails.onlineRate.value }}% 限值{{ item.dataDetails.onlineRate.threshold
}}% </text> -->
<!-- <text>事件时间{{ item.startTime }}</text> -->
</view>
</view>
</view>
<!-- 详情区域 -->
<view class="event-detail">
<view v-if="item.interruptCounts">
通讯中断 {{ item.interruptCounts }} 详情如下
<view class="textBox">
<view
v-for="date in String(item.interruptDetails || '').split('')"
class="textBox mb5"
>{{ date }}</view
></view
>
<view v-if="item.dataDetails.onlineRate.isAbnormal">
<text>在线率
{{item.dataDetails.onlineRate.value }}% 
</text>
</view>
<view v-if="item.warnCounts">
<view v-if="hasIntegrityAbnormal(item)" class="mt10">
数据完整性
<view class="data-table">
<view class="table-header">
<text>监测点名称</text>
<text>完整性</text>
</view>
<view class="table-row"
v-for="value in item.dataDetails.integrity.monitorPoints.filter((p) => p.isAbnormal === true)">
<text>{{ value.monitorName }}</text>
<text>{{ value.value }}%</text>
</view>
</view>
</view>
<view v-if="item.warnCounts" class="mt10">
终端告警 {{ item.warnCounts }} 详情如下
<view class="textBox">
<view v-for="val in item.warnDetails" class="textBox mb5">
{{ val.warnEventTime + '发生' + val.warnEventDesc }}
</view></view
>
</view>
</view>
</view>
</view>
</uni-card>
@@ -97,6 +104,11 @@ export default {
}
},
methods: {
hasIntegrityAbnormal(item) {
const points = item?.dataDetails?.integrity?.monitorPoints
if (!Array.isArray(points) || !points.length) return false
return points.every((p) => p.isAbnormal === true)
},
init() {
queryAlarmDetail({
devList: this.detail.devIds,
@@ -115,6 +127,7 @@ export default {
</script>
<style lang="scss" scoped>
@import '../index.scss';
.detail {
padding: 20rpx 0;
@@ -130,60 +143,102 @@ export default {
font-weight: 700;
}
}
.collapseTop {
padding: 10rpx 0;
margin-left: 15px;
.name {
font-size: 28rpx;
font-weight: 700;
color: #333333;
}
}
.frequency {
display: flex;
font-size: 28rpx;
// color: #666666;
}
}
.textBox {
// border-bottom: 1px solid #eee;
font-size: 28rpx;
color: #666666;
text-indent: 2em;
}
.event-list {
// background: #fff;
padding-bottom: 10rpx;
// .event-icon {
// background-color: #376cf320;
// }
.zl-bgc {
background-color: #376cf320;
}
.jc-bgc {
background-color: #376cf320;
}
.zl-tag {
background-color: #007aff20;
color: #007aff;
}
.jc-tag {
background-color: #007aff20;
color: #007aff;
}
}
/deep/ .uni-collapse-item__title-box {
padding: 0 15px 0 0;
height: 56rpx;
line-height: 56rpx;
font-size: 26rpx !important;
color: #666666;
span {
font-size: 26rpx !important;
}
}
.textBox {
max-height: 120rpx;
overflow-y: auto;
}
.data-table {
margin-top: 10rpx;
background-color: #fff;
overflow: hidden;
.table-header,
.table-row {
display: flex;
justify-content: space-between;
padding: 15rpx 0rpx;
border-bottom: 1rpx solid #eee;
height: 20px;
text {
text-align: center;
font-size: 28rpx;
flex: 1;
}
}
.table-header {
padding: 0rpx;
padding-bottom: 10rpx;
}
}
</style>

View File

@@ -13,13 +13,11 @@
<view class="mb5"> 监测点名称{{ detail.lineName }}</view>
<view class="mb5" style="display: flex">
越限详情
<view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view></view
>
<view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view>
</view>
</view>
<view class="detail-content">
<view class="detail-content-title mb20"
>指标越限详情<text class="prompt">仅显示最严重的10组数据</text></view
>
<view class="detail-content-title mb20">指标越限详情<text class="prompt">仅显示最严重的10组数据</text></view>
<uni-collapse accordion v-model="collapseValue">
<uni-collapse-item :title="item.targetName" v-for="item in list">
@@ -35,7 +33,7 @@
</view>
<view class="table-row" v-for="value in item.harmDetailList">
<text>{{ value.statisticsTime }}</text>
<text>{{ value.valueType }}</text>
<text>{{ value.valueType || '/' }}</text>
<text v-if="!value.hasT">{{ value.dataA }}</text>
<text v-if="!value.hasT">{{ value.dataB }}</text>
<text v-if="!value.hasT">{{ value.dataC }}</text>
@@ -105,6 +103,7 @@ export default {
font-weight: 700;
}
}
.limit {
display: flex;
align-items: center;
@@ -112,46 +111,58 @@ export default {
width: 450rpx;
margin-left: auto;
}
.prompt {
font-size: 24rpx;
color: #111;
font-weight: 500;
}
}
.data-table {
margin-top: 20rpx;
background-color: #fff;
overflow: hidden;
color: #666;
.table-header,
.table-row {
display: flex;
justify-content: space-between;
padding: 20rpx 0rpx;
padding: 15rpx 0rpx;
height: 20px;
border-bottom: 1rpx solid #eee;
text {
width: 100rpx;
text-align: center;
font-size: 28rpx;
// color: #333;
&:nth-child(1) {
flex: 1;
}
&:nth-child(2) {
flex: 1;
}
}
}
.table-header {
padding: 0rpx;
padding-bottom: 10rpx;
}
}
/deep/ .uni-collapse-item__title-text {
font-weight: 700;
span {
font-size: 28rpx;
}
}
.details {
max-height: 70px;
overflow-y: auto;

View File

@@ -16,42 +16,28 @@
<view class="mb5" v-if="detail.evtParamPhase"> 相别{{ detail.evtParamPhase }}</view>
</view>
<view class="detail-tabs">
<uni-segmented-control
:current="detailTab"
active-color="#376cf3"
:values="['波形图', 'ITIC', 'F47']"
@clickItem="onDetailTabChange"
/>
<uni-segmented-control :current="detailTab" active-color="#376cf3" :values="['波形图', 'ITIC', 'F47']"
@clickItem="onDetailTabChange" />
</view>
<view v-if="detailTab == 0">
<view class="detail-content">
<view class="detail-content-title mb20">瞬时波形图</view>
<image
style="width: 100%"
:src="detail.instantPics"
mode="widthFix"
v-if="detail.instantPics"
@click="previewImage(detail.instantPics)"
/>
<image style="width: 100%" :src="detail.instantPics" mode="widthFix" v-if="detail.instantPics"
@click="previewImage(detail.instantPics)" />
<text v-else>暂无</text>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">RMS波形图</view>
<image
style="width: 100%"
:src="detail.rmsPics"
mode="widthFix"
v-if="detail.rmsPics"
@click="previewImage(detail.rmsPics)"
/>
<image style="width: 100%" :src="detail.rmsPics" mode="widthFix" v-if="detail.rmsPics"
@click="previewImage(detail.rmsPics)" />
<text v-else>暂无</text>
</view>
</view>
<view v-if="detailTab == 1" class="chart-wrapper">
<ITIC :store="eventStore" style="min-height: 600rpx;" />
<ITIC :store="eventStore" style="height: calc(100vh - 360px);" />
</view>
<view v-if="detailTab == 2" class="chart-wrapper">
<F47 :store="eventStore" style="min-height: 600rpx;" />
<F47 :store="eventStore" style="height: calc(100vh - 360px);" />
</view>
</view>
</Cn-page>
@@ -143,4 +129,10 @@ export default {
padding: 20rpx;
}
}
.segmented-control {
flex: 1;
margin-right: 24rpx;
height: 60rpx;
}
</style>

View File

@@ -4,8 +4,8 @@
<view class="transientBox">
<view class="statistics pd20">
<view
class="box"
:class="{ boxClick: item.label == filterValue }"
class="box boxClick"
:class="{ boxClick1: item.label == filterValue }"
v-for="item in list"
@click="
filterValue = item.label
@@ -235,7 +235,7 @@ export default {
jump(item) {
let str = JSON.stringify(item).replace(/%/g, '百分比')
item.status = '1'
item.isRead = '1'
uni.navigateTo({ url: '/pages/message1/comp/steadyStateDetails?detail=' + encodeURIComponent(str) })
},

View File

@@ -17,7 +17,7 @@
<text class="label">{{ item.label }}</text>
</view>
</view>
<view class="smallLabel"> </view>
<!-- <view class="smallLabel"> </view> -->
</view>
<!-- 卡片 -->
<scroll-view
@@ -112,6 +112,10 @@ export default {
type: Object,
// default: () => {},
},
sortIndex: {
type: [Number,String],
// default: () => {},
},
},
mixins: [list],
data() {
@@ -150,7 +154,7 @@ export default {
this.store = this.DataSource('/cs-harmonic-boot/eventUser/queryEventpage')
this.store.params.type = 0
// this.store.params.pageSize = 10000
this.store.params.sortField = this.sort
this.store.params.sortField = this.sortIndex
this.store.params.engineeringid = this.selectValue.engineeringId
this.store.params.projectId = this.selectValue.projectId
this.store.params.deviceId = this.selectValue.deviceId
@@ -224,7 +228,9 @@ export default {
uni.navigateTo({ url: '/pages/message1/comp/transientDetails?detail=' + encodeURIComponent(str) })
},
setSort(index) {
this.sort = index
console.log(123,this.sortIndex);
// this.sort = index
this.init()
},
// 下拉

View File

@@ -1,361 +1,350 @@
<template>
<Cn-page :loading="loading" noPadding>
<view slot="body">
<view class="detail">
<view class="header">
<view class="header-title"
>{{ project.name }}
<!-- <view class="header-title-extra">用能</view> -->
</view>
<view class="header-des">项目描述{{ project.description }}</view>
</view>
<view class="nav">
<view
class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
</view>
</view>
<view class="content device" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0">
<!-- <uni-card
:title="item.equipmentName"
:sub-title="'创建时间' + item.createTime"
:extra="item.mac"
v-for="item in store.data"
:key="item.equipmentId"
@click="goDevice(item)"
padding="0"
:thumbnail="deviceIcon(item.runStatus)"
>
</uni-card> -->
<Cn-device-card v-for="(item, index) in store.data" :device="item" :key="index">
</Cn-device-card>
<Cn-empty v-if="store.empty"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
<!-- <view style="padding: 0 20rpx" v-show="navMenuActive == 1">-->
<!-- <uni-list>-->
<!-- <uni-list-item-->
<!-- title="张三"-->
<!-- note="2023-02-10 14:55"-->
<!-- thumb="/static/head.png"-->
<!-- thumb-size="lg"-->
<!-- >-->
<!-- </uni-list-item>-->
<!-- <uni-list-item-->
<!-- title="李四"-->
<!-- note="2023-02-10 14:55"-->
<!-- thumb="/static/head.png"-->
<!-- thumb-size="lg"-->
<!-- >-->
<!-- </uni-list-item>-->
<!-- </uni-list>-->
<!-- </view>-->
<view style="padding: 0 20rpx" v-show="navMenuActive == 1">
<!-- <image
class="gplot gplot-box"
mode="aspectFill"
:src="item.filePath"
v-for="(item, key) in topologyDiagramPage"
:key="key"
/> -->
<uni-file-picker
ref="filePicker"
v-model="topologyDiagramPage"
:sourceType="['album']"
:auto-upload="false"
@select="addAppTopologyDiagram"
@delete="deleteTopologyDiagramPage"
readonly
></uni-file-picker>
</view>
</view>
<uni-fab
ref="fab"
direction="vertical"
horizontal="right"
vertical="bottom"
:content="content"
@trigger="trigger"
v-if="content.length"
/>
<uni-popup ref="share" type="share" background-color="#fff">
<uni-popup-share title="分享到"></uni-popup-share>
</uni-popup>
</view>
</view>
</Cn-page>
</template>
<script>
import list from '../../common/js/list'
import {
queryTopologyDiagramPage,
deleteAppTopologyDiagram,
addAppTopologyDiagram,
deleteProject,
} from '../../common/api/project'
export default {
mixins: [list],
data() {
return {
loading: false,
project: {},
navMenuList: [
{
text: '设备',
},
// {
// text: '用户',
// },
{
text: '拓扑图',
},
],
content: [],
navHeight: 0,
navMenuActive: 0,
topologyDiagramPage: [],
}
},
methods: {
deviceIcon(e) {
let str = ''
switch (e) {
case 1:
str = '/static/device_bad.png'
break
case 2:
str = '/static/device.png'
break
default:
str = '/static/device.png'
break
}
return str
},
addAppTopologyDiagram(e) {
console.log(e)
addAppTopologyDiagram(
{
projectId: this.project.id,
topologyDiagramName: e.tempFiles[0].name,
},
e.tempFiles[0].path,
).then((res) => {
console.log(res)
if (res.length > 1) {
const result = JSON.parse(res[1].data)
console.log(result)
if (result.code === 'A0000') {
this.topologyDiagramPage.push({
name: result.name,
extname: 'img',
url: result.filePath,
...result,
})
} else {
this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1)
uni.showToast({
title: result.message,
icon: 'none',
})
}
} else {
uni.showToast({
title: '上传失败',
icon: 'none',
})
this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1)
}
})
},
deleteTopologyDiagramPage(e) {
console.log(e)
deleteAppTopologyDiagram(e.tempFile.id).then((res) => {
console.log(res)
})
},
trigger(e) {
console.log(this.$refs)
if (e.item.text == '移交') {
uni.navigateTo({
url: '/pages/project/transfer',
})
} else if (e.item.text == '分享') {
this.$refs.share.open()
} else if (e.item.text == '编辑') {
uni.navigateTo({
url: '/pages/project/new?project=' + encodeURIComponent(JSON.stringify(this.project)),
})
} else if (e.item.text == '删除') {
uni.showModal({
title: '提示',
content: '删除项目后不可恢复,是否继续?',
success: (res) => {
if (res.confirm) {
deleteProject(this.project.id).then((res) => {
this.$util.toast('删除成功')
this.$util.refreshPrePage()
})
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
}
},
navMenuClick(index) {
this.navMenuActive = index
},
goUserDetail() {
uni.navigateTo({
url: '/pages/mine/userDetail',
})
},
del() {
console.log('del')
uni.showModal({
title: '提示',
content: '确定要移除该成员吗?',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
},
goDevice(item) {
uni.navigateTo({
url: '/pages/device/APF/detail?id=' + item.equipmentId,
})
},
init() {
this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject')
this.store.params.projectId = this.project.id
this.store.reload()
queryTopologyDiagramPage({
projectId: this.project.id,
}).then((res) => {
console.log(res)
this.topologyDiagramPage = res.data.records.map((item) => {
return {
name: item.name,
extname: 'img',
url: this.$config.static + item.filePath,
...item,
}
})
})
},
},
onLoad(option) {
let userInfo = uni.getStorageSync('userInfo')
// this.content.push({
// iconPath: '/static/share.png',
// text: '编辑',
// })
// this.content.push({
// iconPath: '/static/delate.png',
// text: '删除',
// })
// this.content.push({
// iconPath: '/static/transfer.png',
// text: '移交',
// })
// this.content.push({
// iconPath: '/static/share.png',
// text: '分享',
// })
if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') {
this.content.push(
{
iconPath: '/static/share.png',
text: '编辑',
},
{
iconPath: '/static/delate.png',
text: '删除',
},
)
}
setTimeout(() => {
// 获取nav高度
uni.createSelectorQuery()
.select('.nav')
.boundingClientRect((rect) => {
this.navHeight = rect.height
})
.exec()
}, 1000)
console.log(option.project)
this.project = JSON.parse(decodeURIComponent(option.project))
this.project.topologyDiagramPaths.forEach((item) => {
item.filePath = this.$config.static + item.filePath
})
this.init()
// uni.setNavigationBarTitle({ title: this.project })
},
}
</script>
<style lang="scss">
.detail {
.content {
box-sizing: border-box;
padding-bottom: 20rpx;
}
.header {
padding: 20rpx 20rpx 0;
.header-title {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 40rpx;
margin-bottom: 10rpx;
.header-title-extra {
font-size: 24rpx;
color: #666;
padding-right: 10rpx;
}
}
.header-des {
font-size: 28rpx;
color: #666;
}
}
.footer-btn {
padding: 0 20rpx;
height: 50rpx;
background-color: #007aff;
font-size: 24rpx;
color: #fff;
text-align: center;
line-height: 50rpx;
border-radius: 10rpx;
}
/deep/ .is-add {
background-color: #fff;
}
}
.gplot {
box-sizing: border-box;
position: relative;
width: 100%;
border: 8rpx solid #ccc;
}
</style>
<template>
<Cn-page :loading="loading" noPadding>
<view slot="body">
<view class="detail">
<view class="header">
<view class="header-title"
>{{ project.name }}
<!-- <view class="header-title-extra">用能</view> -->
</view>
<view class="header-des">项目描述{{ project.description }}</view>
</view>
<view class="nav">
<view
class="nav-menu"
:class="{ 'nav-menu-active': navMenuActive == index }"
v-for="(item, index) in navMenuList"
:key="index"
@click="navMenuClick(index)"
>{{ item.text }}
</view>
</view>
<view class="content device" :style="{ minHeight: 'calc(100vh - ' + navHeight + 'px)' }">
<view v-show="navMenuActive == 0">
<!-- <uni-card
:title="item.equipmentName"
:sub-title="'创建时间' + item.createTime"
:extra="item.mac"
v-for="item in store.data"
:key="item.equipmentId"
@click="goDevice(item)"
padding="0"
:thumbnail="deviceIcon(item.runStatus)"
>
</uni-card> -->
<Cn-device-card v-for="(item, index) in store.data" :device="item" :key="index">
<template v-slot:title>
<view class="star-icon">
<uni-icons type="search" size="25" color="#376cf3"></uni-icons>
</view>
</template>
</Cn-device-card>
<Cn-empty v-if="store.empty"></Cn-empty>
<uni-load-more
v-if="store.status == 'loading' || (store.data && store.data.length > 0)"
:status="store.status"
></uni-load-more>
</view>
<view style="padding: 0 20rpx" v-show="navMenuActive == 1">
<!-- <image
class="gplot gplot-box"
mode="aspectFill"
:src="item.filePath"
v-for="(item, key) in topologyDiagramPage"
:key="key"
/> -->
<uni-file-picker
ref="filePicker"
v-model="topologyDiagramPage"
:sourceType="['album']"
:auto-upload="false"
@select="addAppTopologyDiagram"
@delete="deleteTopologyDiagramPage"
readonly
></uni-file-picker>
</view>
</view>
<uni-fab
ref="fab"
direction="vertical"
horizontal="right"
vertical="bottom"
:content="content"
@trigger="trigger"
v-if="content.length"
/>
<uni-popup ref="share" type="share" background-color="#fff">
<uni-popup-share title="分享到"></uni-popup-share>
</uni-popup>
</view>
</view>
</Cn-page>
</template>
<script>
import list from '../../common/js/list'
import {
queryTopologyDiagramPage,
deleteAppTopologyDiagram,
addAppTopologyDiagram,
deleteProject,
} from '../../common/api/project'
export default {
mixins: [list],
data() {
return {
loading: false,
project: {},
navMenuList: [
{
text: '设备',
},
// {
// text: '用户',
// },
{
text: '拓扑图',
},
],
content: [],
navHeight: 0,
navMenuActive: 0,
topologyDiagramPage: [],
}
},
methods: {
deviceIcon(e) {
let str = ''
switch (e) {
case 1:
str = '/static/device_bad.png'
break
case 2:
str = '/static/device.png'
break
default:
str = '/static/device.png'
break
}
return str
},
addAppTopologyDiagram(e) {
console.log(e)
addAppTopologyDiagram(
{
projectId: this.project.id,
topologyDiagramName: e.tempFiles[0].name,
},
e.tempFiles[0].path,
).then((res) => {
console.log(res)
if (res.length > 1) {
const result = JSON.parse(res[1].data)
console.log(result)
if (result.code === 'A0000') {
this.topologyDiagramPage.push({
name: result.name,
extname: 'img',
url: result.filePath,
...result,
})
} else {
this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1)
uni.showToast({
title: result.message,
icon: 'none',
})
}
} else {
uni.showToast({
title: '上传失败',
icon: 'none',
})
this.$refs.filePicker.clearFiles(this.topologyDiagramPage.length - 1)
}
})
},
deleteTopologyDiagramPage(e) {
console.log(e)
deleteAppTopologyDiagram(e.tempFile.id).then((res) => {
console.log(res)
})
},
trigger(e) {
console.log(this.$refs)
if (e.item.text == '移交') {
uni.navigateTo({
url: '/pages/project/transfer',
})
} else if (e.item.text == '分享') {
this.$refs.share.open()
} else if (e.item.text == '编辑') {
uni.navigateTo({
url: '/pages/project/new?project=' + encodeURIComponent(JSON.stringify(this.project)),
})
} else if (e.item.text == '删除') {
uni.showModal({
title: '提示',
content: '删除项目后不可恢复,是否继续?',
success: (res) => {
if (res.confirm) {
deleteProject(this.project.id).then((res) => {
this.$util.toast('删除成功')
this.$util.refreshPrePage()
})
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
}
},
navMenuClick(index) {
this.navMenuActive = index
},
goUserDetail() {
uni.navigateTo({
url: '/pages/mine/userDetail',
})
},
del() {
console.log('del')
uni.showModal({
title: '提示',
content: '确定要移除该成员吗?',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
},
})
},
goDevice(item) {
uni.navigateTo({
url: '/pages/device/APF/detail?id=' + item.equipmentId,
})
},
init() {
this.store = this.DataSource('/cs-device-boot/EquipmentDelivery/queryEquipmentByProject')
this.store.params.projectId = this.project.id
this.store.reload()
queryTopologyDiagramPage({
projectId: this.project.id,
}).then((res) => {
console.log(res)
this.topologyDiagramPage = res.data.records.map((item) => {
return {
name: item.name,
extname: 'img',
url: this.$config.static + item.filePath,
...item,
}
})
})
},
},
onLoad(option) {
let userInfo = uni.getStorageSync('userInfo')
// this.content.push({
// iconPath: '/static/share.png',
// text: '编辑',
// })
// this.content.push({
// iconPath: '/static/delate.png',
// text: '删除',
// })
// this.content.push({
// iconPath: '/static/transfer.png',
// text: '移交',
// })
// this.content.push({
// iconPath: '/static/share.png',
// text: '分享',
// })
if (userInfo.authorities == 'engineering_user' || userInfo.authorities == 'app_vip_user') {
this.content.push(
{
iconPath: '/static/share.png',
text: '编辑',
},
{
iconPath: '/static/delate.png',
text: '删除',
},
)
}
setTimeout(() => {
// 获取nav高度
uni.createSelectorQuery()
.select('.nav')
.boundingClientRect((rect) => {
this.navHeight = rect.height
})
.exec()
}, 1000)
console.log(option.project)
this.project = JSON.parse(decodeURIComponent(option.project))
this.project.topologyDiagramPaths.forEach((item) => {
item.filePath = this.$config.static + item.filePath
})
this.init()
// uni.setNavigationBarTitle({ title: this.project })
},
}
</script>
<style lang="scss">
.detail {
.content {
box-sizing: border-box;
padding-bottom: 20rpx;
}
.header {
padding: 20rpx 20rpx 0;
.header-title {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 40rpx;
margin-bottom: 10rpx;
.header-title-extra {
font-size: 24rpx;
color: #666;
padding-right: 10rpx;
}
}
.header-des {
font-size: 28rpx;
color: #666;
}
}
.footer-btn {
padding: 0 20rpx;
height: 50rpx;
background-color: #007aff;
font-size: 24rpx;
color: #fff;
text-align: center;
line-height: 50rpx;
border-radius: 10rpx;
}
/deep/ .is-add {
background-color: #fff;
}
}
.gplot {
box-sizing: border-box;
position: relative;
width: 100%;
border: 8rpx solid #ccc;
}
</style>

View File

@@ -8,7 +8,8 @@
<uni-search-bar v-model="store.params.searchValue" clearButton="none" bgColor="#fff" placeholder="请输入关键词"
@input="store.search()"></uni-search-bar>
<view class="message">
<uni-card class="boxClick" :title="item.name" @click="jump(item)" extra="🔍"
<!-- extra="🔍" -->
<uni-card class="boxClick" :title="item.name" @click="jump(item)"
v-for="(item, index) in store.data" :key="index" :style="{ marginTop: index === 0 ? '0' : '' }">
<view class="term-list-bottom">
<view class="term-list-bottom-item">