修改测试问题

This commit is contained in:
guanj
2026-06-29 11:01:44 +08:00
parent f008bcb4b8
commit 1d73755a43
56 changed files with 2875 additions and 2702 deletions

View File

@@ -1,86 +1,70 @@
<template>
<view>
<uni-load-more status="loading" v-if="IOData.length == 0"></uni-load-more>
<view class="basic" v-else>
<view class="grid-card">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>温度
</text>
<view class="grid-card-content-4">
<template v-for="item in renderData">
<view class="item item-title">{{ item[0].clDid }}
<template v-if="item[0].clDid"> (°C)</template>
<view class="basic mt10" v-else>
<view class="params-wrap">
<view class="section-title-row">
<view class="section-title">
<view class="grid-card-title-with-icon"></view>
<text>温度</text>
</view>
</view>
<view class="params-section">
<view
v-for="(rowItems, rowIdx) in chunkedChildren(temperatureCards)"
:key="'temp-' + 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="param-value-wrap">
<text class="param-value">{{ child.value }}</text>
</view>
</view>
<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 }}
<template v-if="item[2].clDid"> (°C)</template>
</view>
<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>
<view class="item">{{ item[1].clDid ? Math.round(item[1].value) || '-' : '' }}</view>
<view class="item">{{ item[2].clDid ? Math.round(item[2].value) || '-' : '' }}</view>
<view class="item">{{ item[3].clDid ? Math.round(item[3].value) || '-' : '' }}</view>
</template>
</view>
</view>
</view>
<!-- 运维管理员工程用户 可看 -->
<view class="grid-card"
v-if="(userInfo.authorities == 'operation_manager' || userInfo.authorities == 'engineering_user') && moduleData.length > 0">
<view class="grid-card-title">
<text><view class="grid-card-title-with-icon"></view>状态</text>
<view class="params-wrap" v-if="showModuleSection">
<view class="section-title-row">
<view class="section-title">
<view class="grid-card-title-with-icon"></view>
<text>状态</text>
</view>
</view>
<view class="grid-card-content-4">
<template v-for="(item, index) in moduleData">
<view class="item item-title">{{ item[0].moduleName }}
<template v-if="item[0].moduleName"></template>
<view class="params-section">
<view
v-for="(rowItems, rowIdx) in chunkedChildren(moduleCards)"
:key="'module-' + 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="param-value-wrap">
<text
class="param-value"
:class="{ 'param-value--offline': child.value === '离线' }"
>{{ child.value }}</text>
</view>
</view>
<view class="item item-title">{{ item[1].moduleName }}
<template v-if="item[1].moduleName"></template>
</view>
<view class="item item-title">{{ item[2].moduleName }}
<template v-if="item[2].moduleName"></template>
</view>
<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'" /> -->
<view class="item">{{ item[0].moduleState }}</view>
<view class="item">{{ item[1].moduleState }}</view>
<view class="item">{{ item[2].moduleState }}</view>
<view class="item">{{ item[3].moduleState }}</view>
</template>
</view>
</view>
</view>
<!-- <view class="grid-card">-->
<!-- <view class="grid-card-title">干接点</view>-->
<!-- <view class="grid-card-content-4">-->
<!-- <view class="item item-title">干接点1</view>-->
<!-- <view class="item item-title">干接点2</view>-->
<!-- <view class="item item-title"></view>-->
<!-- <view class="item item-title"></view>-->
<!-- <view class="item">正常</view>-->
<!-- <view class="item">正常</view>-->
<!-- <view class="item"></view>-->
<!-- <view class="item"></view>-->
<!-- </view>-->
<!-- </view>-->
</view>
</view>
</template>
<script>
import { getModuleState } from '@/common/api/harmonic.js'
export default {
props: {
IOData: {
type: Array,
default: () => {
return []
},
default: () => [],
},
ndid: {
type: String,
@@ -90,87 +74,174 @@ export default {
return {
list: [],
userInfo: {},
flag: false,
}
},
computed: {
renderData() {
let arr = []
// 把IOData转换成每4个一组的二维数组
for (let i = 0; i < this.IOData.length; i += 4) {
this.IOData.slice(i, i + 4).forEach((item) => {
if (Number.isInteger(item.value) || item.value == '') {
} else {
item.value = (item.value - 0).toFixed(2)
const arr = []
const data = this.IOData || []
for (let i = 0; i < data.length; i += 4) {
const group = data.slice(i, i + 4).map((item) => {
const next = { ...item }
if (!Number.isInteger(next.value) && next.value !== '') {
next.value = (next.value - 0).toFixed(2)
}
return next
})
arr.push(this.IOData.slice(i, i + 4))
}
// 把每组的长度补齐到4
arr.forEach((item) => {
if (item.length < 4) {
let length = 4 - item.length
for (let i = 0; i < length; i++) {
item.push({})
}
while (group.length < 4) {
group.push({})
}
})
arr.push(group)
}
return arr
},
moduleData() {
let arr = []
// 把IOData转换成每4个一组的二维数组
const arr = []
for (let i = 0; i < this.list.length; i += 4) {
arr.push(this.list.slice(i, i + 4))
}
// 把每组的长度补齐到4
arr.forEach((item) => {
if (item.length < 4) {
let length = 4 - item.length
for (let i = 0; i < length; i++) {
item.push({})
}
const group = this.list.slice(i, i + 4)
while (group.length < 4) {
group.push({})
}
})
console.warn(arr)
arr.push(group)
}
return arr
},
temperatureCards() {
const cards = []
this.renderData.forEach((row) => {
row.forEach((item) => {
if (!item.clDid) return
cards.push({
name: `${item.clDid} (°C)`,
value: Math.round(item.value) ,
})
})
})
return cards
},
moduleCards() {
const cards = []
this.moduleData.forEach((row) => {
row.forEach((item) => {
if (!item.moduleName) return
cards.push({
name: item.moduleName,
value: item.moduleState ,
})
})
})
return cards
},
showModuleSection() {
return (
(this.userInfo.authorities === 'operation_manager' ||
this.userInfo.authorities === 'engineering_user') &&
this.moduleCards.length > 0
)
},
},
mounted() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.info()
},
methods: {
info() {
getModuleState({
id: this.ndid,
}).then((res) => {
this.list = res.data
this.list = res.data || []
})
},
},
mounted() {
this.userInfo = uni.getStorageSync(this.$cacheKey.userInfo)
this.info()
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.basic {
.params-wrap {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 20rpx 20rpx 0;
}
.section-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.grid-card-title-with-icon {
display: inline-flex;
align-items: center;
position: relative;
padding-left: 20rpx;
width: 8rpx;
height: 28rpx;
margin-right: 12rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 28rpx;
background: $uni-theme-color;
border-radius: 3rpx;
.params-section {
padding: 16rpx 16rpx 20rpx;
}
.double-row {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.param-group {
min-width: 0;
background: #f3f3f3;
border-radius: 16rpx;
padding: 16rpx 8rpx 12rpx;
}
.param-title {
font-size: 26rpx;
color: #666666;
margin-bottom: 8rpx;
padding-left: 4rpx;
}
.param-value-wrap {
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.param-value {
font-size: 28rpx;
font-weight: 700;
color: #333;
&--offline {
color: #ff3b30;
}
}
}

View File

@@ -1,115 +1,105 @@
<template>
<view>
<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">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>电网电流
</text>
<view class="grid-card-content-3">
<view class="item item-title">名称</view>
<view class="item item-title">有效值(A)</view>
<view class="item item-title">畸变率(%)</view>
<template v-for="(item, index) in renderData.电网电流">
<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 class="item">{{
item['Apf_ThdA_Sys(%)'] > 0 ? item['Apf_ThdA_Sys(%)'].toFixed(2) : item['Apf_ThdA_Sys(%)']
}}</view>
</template>
<uni-load-more status="loading" v-if="!isDataReady"></uni-load-more>
<view class="basic mt10" v-else>
<view class="params-wrap" v-for="(section, ind) in sections" :key="section.title">
<view class="section-title-row">
<view class="section-title">
<view class="grid-card-title-with-icon"></view>
<text>{{ section.title }}</text>
</view>
<view class="legend-row" v-if="ind == 0">
<view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<view class="legend-dot" :style="{ background: phase.color }" />
<text class="legend-text">{{ phase.name }}</text>
</view>
</view>
</view>
</view>
<view class="grid-card">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>电网电压
</text>
<view class="grid-card-content-4">
<view class="item item-title">名称</view>
<view class="item item-title">电压(V)</view>
<view class="item item-title">频率(Hz)</view>
<view class="item item-title">畸变率(%)</view>
<template v-for="(item, index) in renderData.电网电压">
<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 class="item">{{
item['Apf_Freq(Hz)'] > 0 ? item['Apf_Freq(Hz)'].toFixed(2) : item['Apf_Freq(Hz)']
}}</view>
<view class="item">{{
item['Apf_ThdU_Sys(%)'] > 0 ? item['Apf_ThdU_Sys(%)'].toFixed(2) : item['Apf_ThdU_Sys(%)']
}}</view>
</template>
</view>
</view>
<view class="grid-card">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>负载电流
</text>
<view class="grid-card-content-3">
<view class="item item-title">名称</view>
<view class="item item-title">有效值(A)</view>
<view class="item item-title">畸变率(%)</view>
<template v-for="(item, index) in renderData.负载电流">
<view class="item">{{ item.phase }}</view>
<view class="item">{{
item['Apf_RmsI_Load(A)'] > 0
? item['Apf_RmsI_Load(A)'].toFixed(2)
: item['Apf_RmsI_Load(A)']
}}</view>
<view class="item">{{
item['Apf_ThdA_Load(%)'] > 0
? item['Apf_ThdA_Load(%)'].toFixed(2)
: item['Apf_ThdA_Load(%)']
}}</view>
</template>
</view>
</view>
<view class="grid-card">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>补偿电流
</text>
<view class="grid-card-content-3">
<view class="item item-title">名称</view>
<view class="item item-title">有效值(A)</view>
<view class="item item-title">负载率(%)</view>
<template v-for="(item, index) in renderData.补偿电流">
<view class="item">{{ item.phase }}</view>
<view class="item">{{
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)']
}}</view>
<view class="item">{{
item['load_Rate'] == 3.1415926
? '-'
: item['load_Rate'] > 0
? item['load_Rate'].toFixed(2)
: item['load_Rate']
}}</view>
</template>
<view class="params-section">
<view v-for="(rowItems, rowIdx) in chunkedChildren(getSectionCards(section))" :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: phaseColors[0].color }">{{
child.A
}}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[1].color }">{{
child.B
}}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[2].color }">{{
child.C
}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
const SECTIONS = [
{
title: '电网电流',
dataKey: '电网电流',
metrics: [
{ label: '有效值(A)', field: 'Apf_RmsI_Sys(A)' },
{ label: '畸变率(%)', field: 'Apf_ThdA_Sys(%)' },
],
},
{
title: '电网电压',
dataKey: '电网电压',
metrics: [
{ label: '电压(V)', field: 'Apf_PhV_Sys(V)' },
{ label: '频率(Hz)', field: 'Apf_Freq(Hz)' },
{ label: '畸变率(%)', field: 'Apf_ThdU_Sys(%)' },
],
},
{
title: '负载电流',
dataKey: '负载电流',
metrics: [
{ label: '有效值(A)', field: 'Apf_RmsI_Load(A)' },
{ label: '畸变率(%)', field: 'Apf_ThdA_Load(%)' },
],
},
{
title: '补偿电流',
dataKey: '补偿电流',
metrics: [
{ label: '有效值(A)', field: 'Apf_RmsI_TolOut(A)' },
{ label: '负载率(%)', field: 'load_Rate' },
],
},
]
export default {
props: {
basicData: {
type: Array,
default: () => [],
},
},
data() {
return {
sections: SECTIONS,
phaseColors: [
{ name: 'A相', color: '#F1B22E' },
{ name: 'B相', color: '#2BA471' },
{ name: 'C相', color: '#D54941' },
],
renderData: {
电网电流: [],
电网电压: [],
@@ -119,101 +109,209 @@ export default {
},
}
},
props: {
basicData: {
type: Array,
default: () => {
return []
},
computed: {
isDataReady() {
return (
this.renderData.电网电流.length > 0 &&
this.renderData.电网电压.length > 0 &&
this.renderData.负载电流.length > 0 &&
this.renderData.补偿电流.length > 0
)
},
},
watch: {
basicData: {
handler: function (newVal, oldVal) {
newVal.forEach((item) => {
if (item.phase === 'avg') {
return
}
let key = ''
switch (item.statisticalName) {
case 'Apf_RmsI_Sys(A)':
key = '电网电流'
break
case 'Apf_ThdA_Sys(%)':
key = '电网电流'
break
case 'Apf_PhV_Sys(V)':
key = '电网电压'
break
case 'Apf_Freq(Hz)':
key = '电网电压'
break
case 'Apf_ThdU_Sys(%)':
key = '电网电压'
break
case 'Apf_RmsI_Load(A)':
key = '负载电流'
break
case 'Apf_ThdA_Load(%)':
key = '负载电流'
break
case 'Apf_RmsI_TolOut(A)':
key = '补偿电流'
break
case 'Apf_PhV_Sys(V)':
key = '补偿电流'
break
case 'Apf_PhV_Sys(V)':
key = '补偿电流'
break
case 'load_Rate':
key = '补偿电流'
break
default:
key = '未知'
break
}
let index = this.renderData[key].findIndex((item2) => {
return item2.phase === item.phase
handler(newVal) {
this.renderData = {
电网电流: [],
电网电压: [],
负载电流: [],
补偿电流: [],
未知: [],
}
; (newVal || []).forEach((item) => {
if (item.phase === 'avg') {
return
}
const key = this.getDataKey(item.statisticalName)
const index = this.renderData[key].findIndex((item2) => item2.phase === item.phase)
if (index > -1) {
this.renderData[key][index][item.statisticalName] = item.statisticalData
} else {
this.renderData[key].push({
phase: item.phase,
[item.statisticalName]: item.statisticalData,
})
}
})
if (index > -1) {
this.renderData[key][index][item.statisticalName] = item.statisticalData //
} else {
this.renderData[key].push({
phase: item.phase,
[item.statisticalName]: item.statisticalData, //,
})
}
})
console.log(this.renderData)
},
deep: true,
immediate: true,
},
},
methods: {},
methods: {
getDataKey(statisticalName) {
switch (statisticalName) {
case 'Apf_RmsI_Sys(A)':
case 'Apf_ThdA_Sys(%)':
return '电网电流'
case 'Apf_PhV_Sys(V)':
case 'Apf_Freq(Hz)':
case 'Apf_ThdU_Sys(%)':
return '电网电压'
case 'Apf_RmsI_Load(A)':
case 'Apf_ThdA_Load(%)':
return '负载电流'
case 'Apf_RmsI_TolOut(A)':
case 'load_Rate':
return '补偿电流'
default:
return '未知'
}
},
getSectionCards(section) {
const list = this.renderData[section.dataKey] || []
return section.metrics.map((metric) => ({
name: metric.label,
A: this.getPhaseValue(list, metric.field, 'A'),
B: this.getPhaseValue(list, metric.field, 'B'),
C: this.getPhaseValue(list, metric.field, 'C'),
}))
},
getPhaseValue(list, field, phase) {
const item = list.find(
(row) => String(row.phase || '').toUpperCase() === phase,
)
return this.formatValue(item[field])
},
formatValue(value) {
if (value == 3.1415926) return '-'
if (value === undefined || value === null || value === '') return '-'
const num = Number(value)
if (Number.isNaN(num)) return value
return num > 0 ? num.toFixed(2) : num
},
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.basic {
.params-wrap {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 20rpx 20rpx 0;
}
.section-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.grid-card-title-with-icon {
display: inline-flex;
align-items: center;
position: relative;
padding-left: 20rpx;
width: 8rpx;
height: 28rpx;
margin-right: 12rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 28rpx;
background: $uni-theme-color;
border-radius: 3rpx;
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #666666;
}
.params-section {
padding: 16rpx 16rpx 20rpx;
}
.double-row {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.param-group {
min-width: 0;
background: #f3f3f3;
border-radius: 16rpx;
padding: 16rpx 8rpx 12rpx;
}
.param-title {
font-size: 26rpx;
color: #666666;
margin-bottom: 8rpx;
padding-left: 4rpx;
}
.phase-vertical {
display: flex;
align-items: stretch;
}
.phase-item-vertical {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-value-vertical {
font-size: 28rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
}
</style>

View File

@@ -1,119 +1,119 @@
<template>
<view>
<uni-data-checkbox multiple v-model="checkbox" :localdata="hobby"></uni-data-checkbox>
<view class="charts-box">
<qiun-data-charts ontouch onzoom type="line" :opts="opts" :chartData="chartData" />
</view>
</view>
</template>
<script>
export default {
data () {
return {
checkbox: [0, 1, 2],
hobby: [{
text: '电网电压1',
value: 0
}, {
text: '电网电压2',
value: 1
}, {
text: '电网电压3',
value: 2
}, {
text: '电网电压3',
value: 4
}],
chartData: {},
//您可以通过修改 config-ucharts.js 文件中下标为 ['line'] 的节点来配置全局默认参数,如都是默认参数,此处可以不传 opts 。实际应用过程中 opts 只需传入与全局默认参数中不一致的【某一个属性】即可实现同类型的图表显示不同的样式,达到页面简洁的需求。
opts: {
color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"],
padding: [15, 15, 0, 0],
dataLabel: false,
dataPointShape: false,
enableScroll: true,
legend: {},
xAxis: {
disableGrid: true,
itemCount: 10240,
},
yAxis: {
gridType: "dash",
dashLength: 2,
data: [
{
min: -100,
max: 100
}
]
},
// extra: {
// line: {
// type: "curve",
// width: 2,
// activeType: "hollow",
// linearType: "custom"
// }
// }
},
testDataA: [],
testDataB: [],
testDataC: [],
testCategories: []
};
},
mounted () {
this.getServerData();
},
methods: {
touchmove (e) {
console.log(e)
},
getServerData () {
//模拟从服务器获取数据时的延时
setTimeout(() => {
this.testDataA = [80, 60, 95, 50, 95]
this.testDataB = [95, 50, 50, 95, 50]
this.testDataC = [50, 60, 40, 50, 60]
this.testCategories = ["0", "90", "180", "270", "360"]
for (let index = 0; index < 9; index++) {
this.testDataA.push(...this.testDataA)
this.testDataB.push(...this.testDataB)
this.testDataC.push(...this.testDataC)
this.testCategories.push(...this.testCategories)
}
//模拟服务器返回数据,如果数据格式和标准格式不同,需自行按下面的格式拼接
let res = {
categories: this.testCategories,
series: [
{
name: "成交量A",
data: this.testDataA
},
// {
// name: "成交量B",
// data: this.testDataB
// },
// {
// name: "成交量C",
// data: this.testDataC
// }
]
};
this.chartData = JSON.parse(JSON.stringify(res));
}, 500);
},
}
};
</script>
<style scoped>
/* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */
.charts-box {
margin-top: 20rpx;
width: 100%;
height: 300px;
}
<template>
<view>
<uni-data-checkbox multiple v-model="checkbox" :localdata="hobby"></uni-data-checkbox>
<view class="charts-box">
<qiun-data-charts ontouch onzoom type="line" :opts="opts" :chartData="chartData" />
</view>
</view>
</template>
<script>
export default {
data () {
return {
checkbox: [0, 1, 2],
hobby: [{
text: '电网电压1',
value: 0
}, {
text: '电网电压2',
value: 1
}, {
text: '电网电压3',
value: 2
}, {
text: '电网电压3',
value: 4
}],
chartData: {},
//您可以通过修改 config-ucharts.js 文件中下标为 ['line'] 的节点来配置全局默认参数,如都是默认参数,此处可以不传 opts 。实际应用过程中 opts 只需传入与全局默认参数中不一致的【某一个属性】即可实现同类型的图表显示不同的样式,达到页面简洁的需求。
opts: {
color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"],
padding: [15, 15, 0, 0],
dataLabel: false,
dataPointShape: false,
enableScroll: true,
legend: {},
xAxis: {
disableGrid: true,
itemCount: 10240,
},
yAxis: {
gridType: "dash",
dashLength: 2,
data: [
{
min: -100,
max: 100
}
]
},
// extra: {
// line: {
// type: "curve",
// width: 2,
// activeType: "hollow",
// linearType: "custom"
// }
// }
},
testDataA: [],
testDataB: [],
testDataC: [],
testCategories: []
};
},
mounted () {
this.getServerData();
},
methods: {
touchmove (e) {
console.log(e)
},
getServerData () {
//模拟从服务器获取数据时的延时
setTimeout(() => {
this.testDataA = [80, 60, 95, 50, 95]
this.testDataB = [95, 50, 50, 95, 50]
this.testDataC = [50, 60, 40, 50, 60]
this.testCategories = ["0", "90", "180", "270", "360"]
for (let index = 0; index < 9; index++) {
this.testDataA.push(...this.testDataA)
this.testDataB.push(...this.testDataB)
this.testDataC.push(...this.testDataC)
this.testCategories.push(...this.testCategories)
}
//模拟服务器返回数据,如果数据格式和标准格式不同,需自行按下面的格式拼接
let res = {
categories: this.testCategories,
series: [
{
name: "成交量A",
data: this.testDataA
},
// {
// name: "成交量B",
// data: this.testDataB
// },
// {
// name: "成交量C",
// data: this.testDataC
// }
]
};
this.chartData = JSON.parse(JSON.stringify(res));
}, 500);
},
}
};
</script>
<style scoped>
/* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */
.charts-box {
margin-top: 20rpx;
width: 100%;
height: 300px;
}
</style>

View File

@@ -1,64 +1,92 @@
<template>
<view>
<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">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>电网侧
</text>
<view class="grid-card-content-5">
<view class="item item-title">名称</view>
<view class="item item-title">有功功率(kW)</view>
<view class="item item-title">无功功率(kVar)</view>
<view class="item item-title">视在功率(kVA)</view>
<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) }}
<uni-load-more status="loading" v-if="!isDataReady"></uni-load-more>
<view class="basic mt10" v-else>
<view class="params-wrap" v-for="(section, ind) in sections" :key="section.title">
<view class="section-title-row">
<view class="section-title">
<view class="grid-card-title-with-icon"></view>
<text>{{ section.title }}</text>
</view>
<view class="legend-row" v-if="ind == 0">
<view class="legend-item" v-for="phase in phaseColors" :key="phase.name">
<view class="legend-dot" :style="{ background: phase.color }" />
<text class="legend-text">{{ phase.name }}</text>
</view>
<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>
<view class="item">{{ item['Apf_PF_Sys(null)'] || '-' }}</view>
</template>
</view>
</view>
</view>
<view class="grid-card">
<text>
<view class="grid-card-title grid-card-title-with-icon"></view>负载侧
</text>
<view class="grid-card-content-5">
<view class="item item-title">名称</view>
<view class="item item-title">有功功率(kW)</view>
<view class="item item-title">无功功率(kVar)</view>
<view class="item item-title">视在功率(kVA)</view>
<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="params-section">
<view v-for="(rowItems, rowIdx) in chunkedChildren(getSectionCards(section))" :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: phaseColors[0].color }">{{
child.A
}}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[1].color }">{{
child.B
}}</text>
</view>
<view class="phase-divider" />
<view class="phase-item-vertical">
<text class="phase-value-vertical" :style="{ color: phaseColors[2].color }">{{
child.C
}}</text>
</view>
</view>
</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_PF_Load(null)'] || '-' }}</view>
</template>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
const SECTIONS = [
{
title: '电网侧',
dataKey: '电网侧',
metrics: [
{ label: '有功功率(kW)', field: 'Apf_P_Sys(W)', divide: 1000 },
{ label: '无功功率(kVar)', field: 'Apf_Q_Sys(Var)', divide: 1000 },
{ label: '视在功率(kVA)', field: 'Apf_S_Sys(VA)', divide: 1000 },
{ label: '功率因数', field: 'Apf_PF_Sys(null)' },
],
},
{
title: '负载侧',
dataKey: '负载侧',
metrics: [
{ label: '有功功率(kW)', field: 'Apf_P_Load(W)', divide: 1000 },
{ label: '无功功率(kVar)', field: 'Apf_Q_Load(Var)', divide: 1000 },
{ label: '视在功率(kVA)', field: 'Apf_S_Load(VA)', divide: 1000 },
{ label: '功率因数', field: 'Apf_PF_Load(null)' },
],
},
]
export default {
props: {
basicData: {
type: Array,
default: () => [],
},
},
data() {
return {
sections: SECTIONS,
phaseColors: [
{ name: 'A相', color: '#F1B22E' },
{ name: 'B相', color: '#2BA471' },
{ name: 'C相', color: '#D54941' },
],
renderData: {
电网侧: [],
负载侧: [],
@@ -66,92 +94,210 @@ export default {
},
}
},
props: {
basicData: {
type: Array,
default: () => {
return []
},
computed: {
isDataReady() {
return this.renderData.电网侧.length > 0 && this.renderData.负载侧.length > 0
},
},
watch: {
basicData: {
handler: function (newVal, oldVal) {
newVal.forEach((item) => {
if (item.phase === 'avg') {
return
}
let key = ''
switch (item.statisticalName) {
case 'Apf_P_Sys(W)':
key = '电网侧'
break
case 'Apf_Q_Sys(Var)':
key = '电网侧'
break
case 'Apf_S_Sys(VA)':
key = '电网侧'
break
case 'Apf_PF_Sys(null)':
key = '电网侧'
break
case 'Apf_P_Load(W)':
key = '负载侧'
break
case 'Apf_Q_Load(Var)':
key = '负载侧'
break
case 'Apf_S_Load(VA)':
key = '负载侧'
break
case 'Apf_PF_Load(null)':
key = '负载侧'
break
default:
key = '未知'
break
}
let index = this.renderData[key].findIndex((item2) => {
return item2.phase === item.phase
handler(newVal) {
this.renderData = {
电网侧: [],
负载侧: [],
未知: [],
}
; (newVal || []).forEach((item) => {
if (item.phase === 'avg') {
return
}
const key = this.getDataKey(item.statisticalName)
const index = this.renderData[key].findIndex((item2) => item2.phase === item.phase)
if (index > -1) {
this.renderData[key][index][item.statisticalName] = this.normalizeStatisticalData(
item.statisticalData,
)
} else {
this.renderData[key].push({
phase: item.phase,
[item.statisticalName]: this.normalizeStatisticalData(item.statisticalData),
})
}
})
if (index > -1) {
this.renderData[key][index][item.statisticalName] = item.statisticalData || '-'
} else {
this.renderData[key].push({
phase: item.phase,
[item.statisticalName]: item.statisticalData || '-',
})
}
})
console.log(this.renderData)
},
deep: true,
immediate: true,
},
},
methods: {},
methods: {
getDataKey(statisticalName) {
switch (statisticalName) {
case 'Apf_P_Sys(W)':
case 'Apf_Q_Sys(Var)':
case 'Apf_S_Sys(VA)':
case 'Apf_PF_Sys(null)':
return '电网侧'
case 'Apf_P_Load(W)':
case 'Apf_Q_Load(Var)':
case 'Apf_S_Load(VA)':
case 'Apf_PF_Load(null)':
return '负载侧'
default:
return '未知'
}
},
getSectionCards(section) {
const list = this.renderData[section.dataKey] || []
return section.metrics.map((metric) => ({
name: metric.label,
A: this.getPhaseValue(list, metric, 'A'),
B: this.getPhaseValue(list, metric, 'B'),
C: this.getPhaseValue(list, metric, 'C'),
}))
},
getPhaseValue(list, metric, phase = 'A') {
const item = list.find((row) => String(row.phase || '').toUpperCase() === phase)
return item ? this.formatValue(item[metric.field], metric.divide) : '-'
},
normalizeStatisticalData(value) {
if (value == 3.1415926 || value === null || value === '') {
return '-'
}
return value
},
formatValue(value, divide) {
if (value == 3.1415926 || value === null || value === '' || value === '-') {
return '-'
}
const num = Number(value)
if (Number.isNaN(num)) return value
if (divide) {
// return (num / divide).toFixed(2)
return num != 0 ? (num / divide).toFixed(2) : num
}
return num
},
chunkedChildren(children) {
const result = []
for (let i = 0; i < children.length; i += 2) {
result.push(children.slice(i, i + 2))
}
return result
},
},
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.basic {
.params-wrap {
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12rpx;
padding: 20rpx 20rpx 0;
}
.section-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.grid-card-title-with-icon {
display: inline-flex;
align-items: center;
position: relative;
padding-left: 20rpx;
width: 8rpx;
height: 28rpx;
margin-right: 12rpx;
background: $uni-theme-color;
border-radius: 3rpx;
}
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 28rpx;
background: $uni-theme-color;
border-radius: 3rpx;
.legend-row {
display: flex;
gap: 20rpx;
align-items: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
}
.legend-text {
font-size: 24rpx;
color: #666666;
}
.params-section {
padding: 16rpx 16rpx 20rpx;
}
.double-row {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.param-group {
min-width: 0;
background: #f3f3f3;
border-radius: 16rpx;
padding: 16rpx 8rpx 12rpx;
}
.param-title {
font-size: 26rpx;
color: #666666;
margin-bottom: 8rpx;
padding-left: 4rpx;
}
.phase-vertical {
display: flex;
align-items: stretch;
}
.phase-item-vertical {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 4rpx;
}
.phase-value-vertical {
font-size: 28rpx;
font-weight: 700;
}
.phase-divider {
width: 1px;
background: #d2d2d2;
margin: 8rpx 0;
}
}
</style>

View File

@@ -1,24 +1,14 @@
<template>
<view>
<uni-load-more status="loading" v-if="basicData.length == 0"></uni-load-more>
<view class="xieBo">
<uni-load-more status="loading" v-if="loading"></uni-load-more>
<view v-else>
<div class="header-form">
<uni-data-select
v-model="parity"
:localdata="parityOption"
@change="initEcharts"
style="flex: 1"
:clear="false"
></uni-data-select>
<uni-data-select v-model="parity" :localdata="parityOption" @change="initEcharts" style="flex: 1"
:clear="false"></uni-data-select>
<!-- <uni-data-checkbox v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"></uni-data-checkbox> -->
<uni-data-select
v-model="dataRadio"
:localdata="dataOptions"
@change="initEcharts"
style="flex: 2; margin-left: 20rpx"
:clear="false"
></uni-data-select>
<uni-data-select v-model="dataRadio" :localdata="dataOptions" @change="initEcharts"
style="flex: 2; margin-left: 20rpx" :clear="false"></uni-data-select>
</div>
<view class="charts-box">
<!-- <view class="data-time">{{ time }}</view> -->
@@ -54,6 +44,7 @@ export default {
value: 1,
},
],
loading: true,
parity: 2,
time: '',
dataOptions: [],
@@ -216,7 +207,6 @@ export default {
watch: {
basicData: {
handler(newVal, oldVal) {
console.log(this.basicData)
let basicData = JSON.parse(JSON.stringify(this.basicData))
// this.dataRadio = 0
this.renderData = {
@@ -284,9 +274,9 @@ export default {
})
})
this.dataOptions = dataOptions
console.log(dataOptions)
this.initEcharts()
this.loading = false
this.time = this.$util.parseTime(this.dataTime - 8 * 60 * 60)
},
deep: true,
@@ -365,13 +355,29 @@ export default {
}, 100)
},
},
mounted() {
this.loading = true
setTimeout(() => {
this.loading = false
}, 5000)
},
}
</script>
<style lang="scss">
.xieBo {
margin-top: 10rpx;
background-color: #fff;
padding: 20rpx;
border-radius: 10rpx;
}
.charts-box {
margin-top: 20rpx;
height: 100vh;
.data-time {
position: absolute;
right: 20rpx;
@@ -379,6 +385,7 @@ export default {
font-size: 24rpx;
}
}
.header-form {
display: flex;
}