riku
2021-12-01 d9a6f3c2503795f074ac602c24467f804417ad76
1. 新增用电量日分析功能
已修改7个文件
已添加3个文件
281 ■■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/dataprocess/AverageUtil.kt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/dataprocess/AvgPair.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/dataprocess/ElectricDailyAnalysis.kt 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/CompanyDeviceMapper.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/bean/ElectricDailyInfo.kt 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/eunm/ElectricityType.kt 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/ElectricityService.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/ElectricityServiceImpl.kt 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/ElectricityServiceImplTest.kt 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/dataprocess/AverageUtil.kt
@@ -2,7 +2,7 @@
/**
 * å‡å€¼è®¡ç®—工具,将一组连续数据转换为自定义周期的均值数据
 * è¦æ±‚传入的数据按照时间顺序排列,
 * è¦æ±‚传入的数据按照时间顺序正序排列,
 * @param onTag å®šä¹‰æ•°æ®æ ‡ç­¾èŽ·å–å›žè°ƒå‡½æ•°ï¼Œå½“å½“å‰æ•°æ®æ ‡ç­¾ä¸Žä¸Šä¸ªæ•°æ®æ ‡ç­¾ä¸åŒæ—¶ï¼Œå³è®¤ä¸ºä¸Šä¸€ç»„æ•°æ®ä¸ºåŒä¸€ç»„æ•°æ®ï¼Œéœ€æ±‚å‡ºå‡å€¼
 * @param onAvg å®šä¹‰å‡å€¼è®¡ç®—方法
 */
@@ -26,11 +26,11 @@
        // è®¡ç®—均值
        list.forEach {
            val tag = onTag(it)
            // ç¬¬ä¸€æ¡æ•°æ®å’Œtag相同时,将数据放入临时缓存列表
            // æ˜¯ç¬¬ä¸€æ¡æ•°æ®æˆ–tag相同时,将数据放入临时缓存列表
            if (lastTag == null || tag == lastTag) {
                dataSet.add(it)
            }
            // å½“tag不同时,计算之前数据的均值,同时情况临时数据缓存,添加当前的新数据
            // å½“tag不同时,计算之前数据的均值,同时清空临时数据缓存,添加当前的新数据
            else {
                result.add(onAvg(dataSet))
                dataSet.clear()
src/main/kotlin/com/flightfeather/uav/dataprocess/AvgPair.kt
@@ -2,9 +2,17 @@
import kotlin.math.round
/**
 * å‡å€¼è®¡ç®—中间量
 * @param t æ€»å’Œ
 * @param c æ€»æ•°
 */
data class AvgPair(
    var t: Float, var c: Int
){
    /**
     * è®¡ç®—结果
     */
    fun avg(): Float = if (c == 0) {
        0f
    } else {
src/main/kotlin/com/flightfeather/uav/dataprocess/ElectricDailyAnalysis.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package com.flightfeather.uav.dataprocess
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.domain.entity.CompanyDevice
import com.flightfeather.uav.domain.entity.ElectricMinuteValue
import com.flightfeather.uav.lightshare.bean.ElectricDailyInfo
import java.time.LocalDateTime
import java.time.ZoneId
/**
 * ç”¨ç”µé‡æ—¥åˆ†æž
 * Date 2021/12/1 14:53
 * Created by feiyu
 */
object ElectricDailyAnalysis {
    fun analysis(deviceList: List<CompanyDevice>, dataList: List<ElectricMinuteValue>): List<ElectricDailyInfo> {
        // è¿”回结果
        val result = mutableListOf<ElectricDailyInfo>()
        // æ¯æ—¥ç»Ÿè®¡ä¿¡æ¯
        val dailyInfoMap = mutableMapOf<String, ElectricDailyInfo>()
        // 1.数据准备
        val deviceMap = mutableMapOf<String, CompanyDevice>()
        val dataMap = mutableMapOf<String, MutableMap<String, MutableList<ElectricMinuteValue>>>()
        deviceList.forEach {
            // ç›‘测数据
            if (!dataMap.containsKey(it.cdDeviceCode)) {
                dataMap[it.cdDeviceCode] = mutableMapOf()
            }
            // è®¾å¤‡ä¿¡æ¯
            deviceMap[it.cdDeviceCode] = it
        }
        // 2.轮询数据,统计每日的各项特征
        dataList.forEach {
            // èŽ·å–æ—¥æœŸ
            val day = DateUtil.instance.dateToString(it.mvDataTime, DateUtil.DateStyle.YYYY_MM_DD) ?: ""
            // æ¯æ—¥å¯¹åº”一组数据
            if (dataMap[it.mvStatCode]?.containsKey(day) != true) dataMap[it.mvStatCode]?.put(day, mutableListOf())
            val dayList = dataMap[it.mvStatCode]?.get(day)!!
            dayList.add(it)
            // 2.1 æ ¹æ®æ•°æ®åˆ‡æ¢å½“前设备类型
            if (!dailyInfoMap.containsKey(day)) dailyInfoMap[day] = ElectricDailyInfo()
            val dayResult = dailyInfoMap[day]!!
            dayResult.day = day
            dayResult.changeType(deviceMap[it.mvStatCode])
            // 2.2 æ¯æ—¥èŽ·å–çš„é¦–ä¸ªæ•°æ®ï¼Œå³ä¸ºå½“æ—¥è¯¥è®¾å¤‡å¼€å¯æ—¶é—´
            if (dayList.size == 1) dayResult.setStartTime(it.mvDataTime)
            // 2.3 æ¯ä¸ªæ•°æ®ä¸ºåˆ†é’Ÿå‡å€¼ï¼Œæ€»æ•°ä»£è¡¨å¼€å¯æ—¶é•¿
            dayResult.addRunTime(1)
            // 2.4 ç»Ÿè®¡å½“日设备运行时段(小时)
            val hour = LocalDateTime.ofInstant(it.mvDataTime.toInstant(), ZoneId.systemDefault()).hour
            dayResult.addRunPeriod(hour)
        }
        // 2.5 ç»Ÿè®¡å„台设备每日结束时间及分析结果
        dataMap.forEach { (dCode, dayMap) ->
            dayMap.forEach { (day, list) ->
                dailyInfoMap[day]?.apply {
                    changeType(deviceMap[dCode])
                    setEndTime(list.last().mvDataTime)
                }
            }
        }
        dailyInfoMap.forEach { (_,v)-> result += v }
        return result
    }
}
src/main/kotlin/com/flightfeather/uav/domain/mapper/CompanyDeviceMapper.kt
@@ -5,4 +5,4 @@
import org.apache.ibatis.annotations.Mapper
@Mapper
interface CompanyDeviceMapper : MyMapper<CompanyDevice?>
interface CompanyDeviceMapper : MyMapper<CompanyDevice>
src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt
@@ -5,4 +5,4 @@
import org.apache.ibatis.annotations.Mapper
@Mapper
interface ElectricMinuteValueMapper : MyMapper<ElectricMinuteValue?>
interface ElectricMinuteValueMapper : MyMapper<ElectricMinuteValue>
src/main/kotlin/com/flightfeather/uav/lightshare/bean/ElectricDailyInfo.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
package com.flightfeather.uav.lightshare.bean
import com.flightfeather.uav.domain.entity.CompanyDevice
import com.flightfeather.uav.lightshare.eunm.ElectricityType
import java.util.*
/**
 * ç”¨ç”µé‡æ—¥åˆ†æžç»“æžœ
 * Date 2021/12/1 15:23
 * Created by feiyu
 */
class ElectricDailyInfo {
    var day: String = ""
    /***********产线设备ProductionLine, pl************/
    private var plDCode: String? = null  // è®¾å¤‡ç¼–号
    private var plSTime: Date? = null    // å¼€å¯æ—¶é—´
    private var plETime: Date? = null    // å…³é—­æ—¶é—´
    private var plRunTime: Int = 0    // è¿è¡Œæ—¶é•¿ï¼ˆåˆ†é’Ÿï¼‰
    private var plRunPeriod = mutableListOf<Int>()// è¿è¡Œæ—¶æ®µï¼ˆå°æ—¶ï¼‰
    /***********净化设备Purify, pf********************/
    private var pfDCode: String? = null
    private var pfSTime: Date? = null
    private var pfETime: Date? = null
    private var pfRunTime: Int = 0
    private var pfRunPeriod = mutableListOf<Int>()
    private var dailyResult: String = ""// å½“日分析结果描述
    // å½“前设备类型,用于插入数据时决定赋值字段
    private var deviceType: ElectricityType = ElectricityType.ProductionLine
    fun changeType(d: CompanyDevice?) {
        deviceType = when (d?.cdType) {
            ElectricityType.ProductionLine.value -> {
                plDCode = d.cdDeviceCode
                ElectricityType.ProductionLine
            }
            ElectricityType.Purify.value -> {
                pfDCode = d.cdDeviceCode
                ElectricityType.Purify
            }
            else -> ElectricityType.UnKnow
        }
    }
    fun setStartTime(date: Date) {
        when (deviceType) {
            ElectricityType.ProductionLine -> plSTime = date
            ElectricityType.Purify -> pfSTime = date
            else -> Unit
        }
    }
    fun setEndTime(date: Date) {
        when (deviceType) {
            ElectricityType.ProductionLine -> plETime = date
            ElectricityType.Purify -> pfETime = date
            else -> Unit
        }
    }
    /**
     * å¢žåŠ è¿è¡Œæ—¶é•¿
     */
    fun addRunTime(min: Int) {
        when (deviceType) {
            ElectricityType.ProductionLine -> plRunTime += min
            ElectricityType.Purify -> pfRunTime += min
            else -> Unit
        }
    }
    /**
     * æ·»åŠ è¿è¡Œæ—¶æ®µ(小时)
     */
    fun addRunPeriod(hour: Int) {
        when (deviceType) {
            ElectricityType.ProductionLine -> if (!plRunPeriod.contains(hour)) plRunPeriod += hour
            ElectricityType.Purify -> if (!pfRunPeriod.contains(hour)) pfRunPeriod += hour
            else -> Unit
        }
    }
    /**
     * ç»Ÿè®¡å¾—出当日分析结果
     */
    fun getResult() {
        // 1. è®¾å¤‡å¼€å¯å…³é—­æ˜¯å¦åˆè§„
//        val timeDiff =
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/eunm/ElectricityType.kt
@@ -8,5 +8,7 @@
    //产线设备
    ProductionLine(0),
    //净化设备
    Purify(1)
    Purify(1),
    //未知设备
    UnKnow(99),
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/ElectricityService.kt
@@ -3,6 +3,7 @@
import com.flightfeather.uav.domain.entity.ElectricMinuteValue
import com.flightfeather.uav.lightshare.bean.BaseResponse
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.lightshare.bean.ElectricDailyInfo
import com.flightfeather.uav.lightshare.bean.ElectricVo
interface ElectricityService {
@@ -13,5 +14,13 @@
    fun getByCompany(cId:String):BaseResponse<List<ElectricMinuteValue>>
    /**
     * èŽ·å–ä¼ä¸šç”¨ç”µé‡æ•´åˆæ•°æ®
     */
    fun getElectricityInfo(cId: String, startTime: String?, endTime: String?, page: Int?, perPage: Int?): BaseResponse<List<ElectricVo>>
    /**
     * ä¼ä¸šç”¨ç”µé‡æ—¥ç»Ÿè®¡ä¿¡æ¯
     */
    fun dailyStatistics(cId: String, startTime: String?, endTime: String?): BaseResponse<List<ElectricDailyInfo>>
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/ElectricityServiceImpl.kt
@@ -1,25 +1,26 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.dataprocess.ElectricDailyAnalysis
import com.flightfeather.uav.domain.entity.CompanyDevice
import com.flightfeather.uav.domain.entity.ElectricMinuteValue
import com.flightfeather.uav.domain.entity.toAirData
import com.flightfeather.uav.domain.mapper.CompanyDeviceMapper
import com.flightfeather.uav.domain.mapper.ElectricMinuteValueMapper
import com.flightfeather.uav.lightshare.bean.BaseResponse
import com.flightfeather.uav.lightshare.bean.DataHead
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.lightshare.bean.ElectricVo
import com.flightfeather.uav.lightshare.bean.*
import com.flightfeather.uav.lightshare.eunm.ElectricityType
import com.flightfeather.uav.lightshare.service.ElectricityService
import com.flightfeather.uav.socket.bean.AirData
import com.github.pagehelper.PageHelper
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.stereotype.Service
import tk.mybatis.mapper.entity.Example
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
import kotlin.math.round
@Service
@@ -29,11 +30,9 @@
    private var dateFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    private var dateFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
    private var dateFormatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
    override fun getMinuteData(
        deviceCode: String, startTime: String?,
        endTime: String?, page: Int?, perPage: Int?
    ): BaseResponse<List<ElectricMinuteValue>> {
    override fun getMinuteData(deviceCode: String, startTime: String?, endTime: String?, page: Int?, perPage: Int?): BaseResponse<List<ElectricMinuteValue>> {
        val perP = perPage ?: 60
        val p = page ?: 1
        val sTime = startTime?.let { dateFormatter.parse(it) }
@@ -277,6 +276,12 @@
        return BaseResponse(true, head = DataHead(pageInfo.pageNum, pageInfo.pages), data = result)
    }
    /**
     * èŽ·å–è®¾å¤‡å½“å‰è¿è¡ŒçŠ¶æ€
     * @param e è®¾å¤‡ç”¨ç”µé‡ç›‘测数据
     * @param d ä¼ä¸šè®¾å¤‡ä¿¡æ¯
     * @return æ•°æ®å¯¹åº”结果信息:<状态编号,状态描述,电流均值>
     */
    private fun getStatus(e: ElectricMinuteValue?, d: CompanyDevice?): Triple<String, String, Double> {
        var values = mutableListOf<Int>().apply {
            d?.cdLimits?.split(";")?.forEach {
@@ -305,4 +310,44 @@
        }
        return Triple(status.last(), statusNames.last(), avg)
    }
    override fun dailyStatistics(cId: String, startTime: String?, endTime: String?): BaseResponse<List<ElectricDailyInfo>> {
        // æ ¹æ®ä¼ä¸šid获取对应设备
        val devices = companyDeviceMapper.selectByExample(Example(CompanyDevice::class.java).apply {
            createCriteria().andEqualTo("cdCompanyId", cId)
        })
        val deviceCodeList = mutableListOf<String>()
        devices.forEach { it?.let { deviceCodeList.add(it.cdDeviceCode) }}
        val st:LocalDateTime
        val et:LocalDateTime
        // å½“没有开始或结束时间时,使用最新一条数据时间的当天作为统计时间
        if (startTime == null || endTime == null) {
            val em = electricMinuteValueMapper.selectOneByExample(Example(ElectricMinuteValue::class.java).apply {
                createCriteria().andIn("mvStatCode", deviceCodeList)
                orderBy("mvDataTime").desc()
            })
            val dataTime = LocalDateTime.ofInstant(em?.mvDataTime?.toInstant(), ZoneId.systemDefault())
            st = dataTime.withHour(0).withMinute(0).withSecond(0)
            et = dataTime.withHour(23).withMinute(59).withSecond(59)
        }
        // å½“有开始结束时间时,判断格式是否正确
        else {
            try {
                st = LocalDateTime.parse(startTime, dateFormatter3).withHour(0).withMinute(0).withSecond(0)
                et = LocalDateTime.parse(endTime, dateFormatter3).withHour(23).withMinute(59).withSecond(59)
            } catch (e: DateTimeParseException) {
                return BaseResponse(false, "时间格式错误,应为yyyy-MM-dd hh:mm:dd")
            }
        }
        val dataList = electricMinuteValueMapper.selectByExample(Example(ElectricMinuteValue::class.java).apply {
            createCriteria().andIn("mvStatCode", deviceCodeList)
                .andBetween("mvDataTime", st, et)
            orderBy("mvDataTime")
        })
        val result = ElectricDailyAnalysis.analysis(devices, dataList)
        return BaseResponse(true, data = result)
    }
}
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/ElectricityServiceImplTest.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.lightshare.service.ElectricityService
import org.junit.Test
import org.junit.Assert.*
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
/**
 * Date 2021/12/1 16:49
 * Created by feiyu
 */
@RunWith(SpringRunner::class)
@SpringBootTest
class ElectricityServiceImplTest {
    @Autowired
    lateinit var electricityService: ElectricityService
    @Test
    fun dailyStatistics() {
        val r = electricityService.dailyStatistics("J3euwNl19WZvH7iE", "2021-07-16 00:00:00", "2021-07-16 00:00:00")
        println(r)
    }
}