Files
emsapp/pages/work/dtdc/index.vue
2026-01-15 17:51:09 +08:00

506 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<view class="search-icon" @click="openSearch">
<uni-icons type="search" size="25" color="#fff"></uni-icons>
</view>
<view class="list-container">
<view class="no-data" v-if="list.length === 0">暂无数据</view>
<uni-list v-else>
<uni-list-item v-for="(item,index) in list" :key="index+'dtdc'">
<template v-slot:header>
<view class="list-header">
单体编号:{{item.deviceId}}
<button type="primary" size="mini" class="charts-btn" @click="toDetail(item)">图表</button>
</view>
</template>
<template v-slot:body>
<view class="list-body">
<uni-row>
<uni-col :span="8">
<view>簇号</view>
</uni-col>
<uni-col :span="16">
<view class="right">{{item.clusterDeviceId || '-'}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>电压V</view>
</uni-col>
<uni-col :span="16">
<view class="right color">
<text @click="toDetail(item,'voltage')">{{item.voltage | formatNumber}}</text>
</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>温度</view>
</uni-col>
<uni-col :span="16">
<view class="right color">
<text
@click="toDetail(item,'temperature')">{{item.temperature | formatNumber}}</text>
</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>SOC%</view>
</uni-col>
<uni-col :span="16">
<view class="right color">
<text @click="toDetail(item,'soc')">{{item.soc | formatNumber}}</text>
</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>SOH%</view>
</uni-col>
<uni-col :span="16">
<view class="right color">
<text @click="toDetail(item,'soh')">{{item.soh | formatNumber}}</text>
</view>
</uni-col>
</uni-row>
</view>
</template>
</uni-list-item>
</uni-list>
</view>
<uni-popup ref="popup" type="center" :animation="false" :mask-click="false" :is-mask-click="false"
@maskClick="maskClick">
<view class="chart-popup" v-if="showChart">
<date-range-select ref="chartDateRangeSelect" @updateDate="updateChartDate"
style="margin-bottom: 10px;" />
<view class="chart-container">
<qiun-data-charts type="line" :reload="showChart" :optsWatch='false' :opts="options"
:chartData="chartsData" :ontouch="true" :inScrollView="true" :pageScrollTop="pageScrollTop" />
</view>
</view>
</uni-popup>
<uni-popup ref="searchPopup" type="center">
<view class="uni-pa-5 search-container">
<uni-forms ref="form">
<uni-forms-item label="电池堆">
<uni-data-select :clear="false" v-model="search.stackId" :localdata="stackOptions"
@change="changeStackId"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="电池簇">
<uni-data-select :clear="false" v-model="search.clusterId"
:localdata="clusterOptions"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="编号">
<uni-easyinput type="text" v-model="search.batteryId" placeholder="请输入编号" />
</uni-forms-item>
</uni-forms>
<view class="button-group" style="text-align: center;">
<button type="default" size="mini" @click="onReset">重置</button>
<button type="primary" size="mini" @click="onSearch" style="margin-left: 20px;">搜索</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import DateRangeSelect from './../DateRangeSelect.vue'
import {
getStackNameList,
getClusterNameList,
getClusterDataInfoList,
getSingleBatteryData
} from '@/api/ems/site.js'
import {
mapState
} from 'vuex'
export default {
components: {
DateRangeSelect
},
data() {
return {
pageNum: 1,
pageSize: 20,
total: 0,
stackOptions: [],
clusterOptions: [],
search: {
stackId: '',
clusterId: '',
batteryId: ''
},
list: [],
siteId: '',
pageScrollTop: 0,
// ucharts数据
showChart: false,
chartSearchData: {
},
options: {
duration: 0,
animation: false,
dataLabel: false,
enableScroll: true,
xAxis: {
scrollShow: true,
itemCount: 3,
disableGrid: true
},
},
range: [],
end: Date.now(),
loading: false,
chartsData: {},
// ucharts数据结束
}
},
onPageScroll(e) {
this.pageScrollTop = e.scrollTop
},
onReachBottom() {
if (this.list.length >= this.total) {
return console.log('数据已经加载完成')
}
this.pageNum += 1 //每次搜索从1开始搜索
this.getTableData()
},
methods: {
//ucharts方法
maskClick() {
this.showChart = false
this.$refs.popup.close()
},
chartOpen({
siteId,
clusterDeviceId,
deviceId
}, dataType) {
this.loading = false
this.chartSearchData = {
clusterDeviceId,
deviceId,
dataType
}
this.$refs.popup.open()
setTimeout(() => {
this.showChart = true
this.$nextTick(() => {
this.$refs.chartDateRangeSelect.init()
})
}, 500)
},
updateChartDate(data) {
this.range = data || []
this.getChartData()
},
getChartData() {
if (this.loading) return
this.loading = true;
const {
siteId,
chartSearchData: {
deviceId,
clusterDeviceId
},
range: [startDate = '', endDate = '']
} = this;
this.chartsData = {}
return getSingleBatteryData({
siteId,
deviceId,
clusterDeviceId,
startDate,
endDate
}).then(response => {
this.handledata(response?.data || [])
}).finally(() => {
this.loading = false;
})
},
handledata(data) {
let obj = {
voltage: '电压',
temperature: '温度',
soc: 'SOC',
soh: 'SOH',
},
categories = [],
dataTypeList = [],
{
dataType
} = this.chartSearchData
if (dataType) {
dataTypeList = [{
attr: dataType,
title: obj[dataType],
data: []
}]
} else {
dataTypeList = Object.entries(obj).map(([key, value]) => {
return {
attr: key,
title: value,
data: []
}
})
}
data.forEach(item => {
categories.push(item.dataTimestamp)
dataTypeList.forEach(i => {
i.data.push(item[i.attr] || undefined)
})
})
const series = dataTypeList.map(item => {
return {
"name": item.title,
"data": item.data
}
})
this.chartsData = JSON.parse(JSON.stringify({
categories,
series
}))
console.log('this.chartsData', this.chartsData)
},
//ucharts方法结束
openSearch() {
this.$refs.searchPopup.open()
},
closeSearch() {
this.$refs.searchPopup.close()
},
toDetail(item, dataType) {
const {
clusterDeviceId,
deviceId
} = item, {
siteId
} = this
// this.$refs.chart.open({
this.chartOpen({
siteId,
clusterDeviceId,
deviceId
}, dataType)
},
// 搜索
onSearch() {
this.pageNum = 1 //每次搜索从1开始搜索
this.getTableData(true)
this.closeSearch()
},
// 重置
// 清空搜索栏选中数据
// 清空电池簇列表,保留电池堆列表
onReset() {
this.search = {
stackId: '',
clusterId: '',
batteryId: ''
}
this.clusterOptions = []
this.pageNum = 1
this.getTableData(true)
this.closeSearch()
},
changeStackId(val) {
if (val) {
console.log('选择了电池堆,需要获取对应的电池簇', val, this.search.stackId)
this.search.clusterId = ''
this.getClusterList()
}
},
getStackList() {
getStackNameList({
siteId: this.siteId
}).then(response => {
this.stackOptions = JSON.parse(JSON.stringify(response?.data || [])).map(item => {
return {
text: item.deviceName,
value: item.id
}
})
})
},
getClusterList() {
getClusterNameList({
stackDeviceId: this.search.stackId,
siteId: this.siteId
}).then(response => {
this.clusterOptions = JSON.parse(JSON.stringify(response?.data || [])).map(item => {
return {
text: item.deviceName,
value: item.id
}
})
}).finally(() => {})
},
//表格数据
getTableData(reset = false) {
if (!reset && this.list.length === this.total) return
uni.showLoading()
if (reset) {
this.list = []
this.total = 0
}
const {
stackId: stackDeviceId,
clusterId: clusterDeviceId,
batteryId
} = this.search
const {
siteId,
pageNum,
pageSize
} = this
getClusterDataInfoList({
stackDeviceId,
clusterDeviceId,
batteryId,
siteId,
pageNum,
pageSize
}).then(response => {
this.list = this.list.concat(response?.rows?.[0]?.batteryList || []);
this.total = response?.total || 0
}).finally(() => {
uni.hideLoading()
})
},
},
mounted() {
// uni.showLoading()
this.siteId = this.$route.query.siteId || ''
this.getStackList()
this.getTableData(true)
}
}
</script>
<style lang="scss" scoped>
.container {
position: relative;
background: #f5f5f5;
.search-icon {
position: fixed;
bottom: 40rpx;
right: 40rpx;
z-index: 1;
height: 60rpx;
width: 60rpx;
background-color: #007aff;
border-radius: 100%;
line-height: 60rpx;
text-align: center;
}
.search-container {
background: #ffffff;
width: 360px;
padding: 15px 20px;
}
.list-container {
padding-top: 40rpx;
padding-bottom: 100rpx;
background: transparent;
::v-deep {
.uni-list {
background: transparent;
}
.uni-list-item {
padding: 10rpx 30rpx;
background-color: transparent !important;
}
.uni-list-item__container {
background-color: #ffffff;
padding: 0;
display: block;
border-radius: 10rpx;
box-shadow: 0 1px 16rpx 1px rgba($color: #a5a5a5, $alpha: 0.2);
}
.uni-list--border-top,
.uni-list--border-bottom,
.uni-list--border::after {
background-color: transparent;
}
}
.list-header {
border-radius: 14rpx 14rpx 0 0;
border-bottom: 1px solid #eee;
padding: 20rpx 30rpx;
font-weight: 700;
position: relative;
color: #333;
.charts-btn {
position: absolute;
top: 50%;
right: 20rpx;
transform: translateY(-50%);
background-color: #4c7af3;
}
}
.list-body {
padding: 10rpx 0;
>.uni-row {
font-size: 26rpx;
line-height: 36rpx;
color: #000;
padding: 12rpx 30rpx;
.left {
color: #333;
text-align: left;
}
.right {
text-align: right;
&.color {
color: #4c7af3;
font-weight: 700;
}
}
}
}
}
.chart-popup {
width: 720rpx;
background-color: #fff;
padding: 20rpx 30rpx;
.chart-container {
width: 100%;
height: 500rpx;
margin-top: 40rpx;
}
::v-deep {
uni-canvas {
height: 500rpx;
width: 100%;
}
}
}
}
</style>