package data
|
|
import (
|
"fmt"
|
"regexp"
|
"ruleModelEngine/config"
|
"ruleModelEngine/db"
|
"strings"
|
"time"
|
)
|
|
// 计算抓拍天数
|
func CalculateCaptureDays(details []db.CaptureDetail) (int, int) {
|
// 使用 map 来存储每天是否有抓拍记录
|
captureMap := make(map[string]bool)
|
//pointDate := ""
|
//pointTime := ""
|
//pointDirection := ""
|
overnightCount := 0
|
for i, detail := range details {
|
// 解析抓拍日期
|
layout := "2006-01-02 15:04:05"
|
captureTime, err := time.Parse(layout, detail.CaptureDate)
|
if err != nil {
|
fmt.Println("解析抓拍日期时出错:", err)
|
continue
|
}
|
//fmt.Println(captureTime, detail.Direction)
|
// 获取日期部分
|
date := captureTime.Format("2006-01-02")
|
//time := captureTime.Format("15:04:05")
|
// 在 map 中标记这一天有抓拍记录
|
captureMap[date] = true
|
if i == len(details)-1 {
|
break
|
}
|
|
// 第一个验证条件:当前为 in,时间在下午 16 点以后
|
currTime, _ := time.Parse("2006-01-02 15:04:05", detail.CaptureDate)
|
if detail.Direction == "in" && currTime.Hour() >= 16 {
|
// 第二个验证条件:下一个为 out,时间在上午 5 点之后 12 点之前
|
nextDetail := details[i+1]
|
nextTime, _ := time.Parse("2006-01-02 15:04:05", nextDetail.CaptureDate)
|
nextDay := nextTime.AddDate(0, 0, -1).Format("2006-01-02")
|
if nextDetail.Direction == "out" && nextTime.Hour() >= 5 && nextTime.Hour() < 12 && nextDay == detail.CaptureDate[:10] {
|
overnightCount++
|
}
|
}
|
}
|
|
// 统计有抓拍记录的天数
|
captureDays := 0
|
for range captureMap {
|
captureDays++
|
}
|
|
return captureDays, overnightCount
|
}
|
|
// 设置状态
|
func SetStatus(captureDays int, rules []db.PersonnelStatusRule) string {
|
for _, rule := range rules {
|
if captureDays >= rule.DetectionDaysStart && captureDays <= rule.DetectionDaysEnd {
|
return rule.Name
|
}
|
}
|
return rules[1].Name
|
}
|
|
// 获取常用地址
|
func getfrAddress(pointAddress map[string]int) string {
|
maxCount := 0
|
maxCountAddress := ""
|
re1F, _ := regexp.Compile(`\b1F\b`)
|
reNoF, _ := regexp.Compile(`^[^F]*$`)
|
reNegF := regexp.MustCompile(`-`)
|
for address, count := range pointAddress {
|
matchFlag1F := re1F.MatchString(address)
|
matchFlagNoF := reNoF.MatchString(address)
|
matchFlagNegF := reNegF.MatchString(address)
|
if address == "" || matchFlag1F || matchFlagNoF || matchFlagNegF {
|
continue
|
}
|
if count > maxCount {
|
maxCount = count
|
maxCountAddress = address
|
}
|
}
|
return maxCountAddress
|
}
|
|
// SetFrequentAddress 方法计算出现最频繁的出行地址并设置为常用地址
|
func GetFrequentAddress(captureDetail []db.CaptureDetail) string {
|
// 统计每个出行地址的出现次数
|
//pointDate 靶标日期,pointAddress靶标地址
|
pointDate := ""
|
pointAddress := make(map[string]int, 0)
|
//dateAddress 按日期汇总单日常用地址
|
dateAddress := make(map[string]string, 0)
|
//floor1Address 后备地址,为1楼地址
|
floor1Address := ""
|
//captureDays 按日期去重统计总抓拍天数
|
captureDays := make(map[string]int, 0)
|
//frequentAddress 最终设置的常用地址
|
var frequentAddress string
|
//正则 判断地址是否包含1F字样,完全匹配
|
re1F, _ := regexp.Compile(`\b1F\b`)
|
reNoF, _ := regexp.Compile(`^[^F]*$`)
|
// 遍历所有抓拍数据
|
for index, detail := range captureDetail {
|
//fmt.Println("抓拍地址:", detail.CaptureAddress)
|
//fmt.Println("抓拍日期:", detail.CaptureDate)
|
//dateStr截取的日期,为YYYY-MM-DD
|
dateStr := strings.Split(detail.CaptureDate, " ")[0]
|
//去重统计抓拍天数 captureDays
|
captureDays[dateStr]++
|
//匹配是否是1F
|
matchFlag1F := re1F.MatchString(detail.CaptureAddress)
|
matchFlagNoF := reNoF.MatchString(detail.CaptureAddress)
|
if matchFlag1F {
|
//如果是, 提前设置好备用地址 floor1Address = detail.CaptureAddress
|
floor1Address = detail.CaptureAddress
|
}
|
if matchFlagNoF && floor1Address == "" {
|
//如果是, 提前设置好备用地址 floor1Address = detail.CaptureAddress
|
floor1Address = detail.CaptureAddress
|
}
|
//fmt.Println("now floor1Address:", floor1Address,"\tnow detail CaptureAddress",detail.CaptureAddress)
|
//判断日期标是否满足条件 判断日期标是否为空,若为空表示是第一个元素,初始化日期靶标
|
if pointDate == "" {
|
//初始化日期靶标为当前日期
|
pointDate = dateStr
|
//把当前日期的
|
pointAddress[detail.CaptureAddress]++
|
//若为最后一条则计算单日常用地址
|
if index == len(captureDetail)-1 {
|
//fmt.Println("处理前pointAddress表:", pointAddress)
|
//这代表仅有一条数据,将会直接把当前地址加入dateAddress 日期汇总单日常用地址表内 下方continue会直接结束循环
|
//否则会初始化pointDate和pointAddress
|
dateAddress[pointDate] = detail.CaptureAddress
|
}
|
continue
|
}
|
//若日期标相等则为同一天
|
if pointDate == dateStr {
|
//pointAddress靶标日期数组对应楼层地址数+1
|
pointAddress[detail.CaptureAddress]++
|
//若为最后一条则计算单日常用地址
|
if index == len(captureDetail)-1 {
|
//fmt.Println("处理前pointAddress表:", pointAddress)
|
//计算单日常用地址 若地址内都为1F或者空地址,会返回空地址
|
dateAddress[pointDate] = getfrAddress(pointAddress)
|
continue
|
}
|
//不相等则为新的日期,首先计算出当日的常用地址,然后重新初始化日期标和地址标数组
|
} else {
|
//若为最后一条则计算单日常用地址
|
if index == len(captureDetail)-1 {
|
//把当前最后一条加入 pointAddress靶标地址
|
pointAddress[detail.CaptureAddress]++
|
//
|
//fmt.Println("处理前pointAddress表:", pointAddress)
|
//计算单日常用地址 若地址内都为1F或者空地址,会返回空地址
|
dateAddress[pointDate] = getfrAddress(pointAddress)
|
continue
|
}
|
//不为最后一条表示这是新的一天的抓拍地址数据,需要计算之前一天的单日常用地址
|
dateAddress[pointDate] = getfrAddress(pointAddress)
|
//初始化新的一天的靶标日期和pointAddress 靶标地址数组
|
pointDate = dateStr
|
pointAddress = make(map[string]int, 0)
|
}
|
}
|
//fmt.Println("抓拍地址待处理结构表:", dateAddress)
|
//fmt.Println("dareAddress len: ", len(dateAddress))
|
//判断抓拍的非1楼非空非地下的天数占比总天数
|
if float64(len(dateAddress))/float64(len(captureDays))*100 >= float64(config.Api.CapAddrDaysThreshold) {
|
//fmt.Println("非1楼非空抓拍占比: ", float64(len(dateAddress))/float64(len(captureDays))*100)
|
//初始化地址列表,按地址计数
|
addressCount := make(map[string]int)
|
//遍历之前汇总的单日常用地址列表
|
for _, address := range dateAddress {
|
//对应地址数+1
|
addressCount[address]++
|
}
|
//复制常用地址给最终结果,若地址内都为1F或者空地址,会返回空地址
|
frequentAddress = getfrAddress(addressCount)
|
} else {
|
//若不满足非1楼非空抓拍占比,则直接把备用地址(1F)赋值给最终结果
|
frequentAddress = floor1Address
|
}
|
//若存在满足非1楼非空抓拍占比,但是最终结果是空地址,则赋值备用地址(1F)为最终结果
|
if frequentAddress == "" {
|
frequentAddress = floor1Address
|
}
|
//fmt.Println("in address: ", inAddressCounts)
|
//fmt.Println("out address: ", outAddressCounts)
|
//fmt.Println("final address: ", frequentAddress)
|
return frequentAddress
|
}
|
|
// processData 函数处理数据,根据要求过滤掉数据并根据规则更新状态
|
func ProcessData(captureInfos []db.CaptureInfo, personStatus []*db.PersonStatus, ruleInfos []db.PersonnelStatusRule, statusNo map[string]int, communityID string) []db.PersonStatus {
|
filteredInfos := make([]db.PersonStatus, 0)
|
|
// 构建快速查找索引,方便查找对应的人员状态和规则
|
statusIndex := make(map[string]db.PersonStatus)
|
ruleIndex := make(map[string]db.PersonnelStatusRule)
|
|
for _, person := range personStatus {
|
statusIndex[person.DocumentNumber] = *person
|
}
|
|
for _, rule := range ruleInfos {
|
ruleIndex[rule.Name] = rule
|
}
|
//fmt.Println("statusIndex: ", statusIndex)
|
//fmt.Println("ruleIndex: ", ruleIndex)
|
// 处理每个抓拍信息
|
for _, info := range captureInfos {
|
//fmt.Println("info", info.DocumentNumber, info.Status, info.FrequentAddress)
|
//fmt.Println("person", statusIndex[info.DocumentNumber].DocumentNumber, statusIndex[info.DocumentNumber].Status, statusIndex[info.DocumentNumber].FrequentAddress)
|
// 检查是否存在对应的人员状态
|
person := statusIndex[info.DocumentNumber]
|
//fmt.Println("person: ", person.DocumentNumber, person.Status, person.FrequentAddress, person.LastAppearanceTime, person.LastAppearanceStatusTime)
|
// 判断状态和常用地址是否相等,如果相等则忽略
|
//if (info.Status == person.Status || info.CaptureDays <= ruleIndex[person.DocumentNumber].DetectionDaysEnd) &&
|
// info.FrequentAddress == person.FrequentAddress {
|
// continue
|
//}
|
// 更新过滤后的信息列表
|
//fmt.Println("LastAppearanceTime: ", person.LastAppearanceTime)
|
if statusNo[person.Status] > statusNo[info.Status] {
|
continue
|
}
|
filteredInfos = append(filteredInfos, db.PersonStatus{CommunityID: communityID, DocumentNumber: info.DocumentNumber, Status: info.Status, FrequentAddress: info.FrequentAddress, LastAppearanceStatusTime: person.LastAppearanceTime})
|
|
}
|
//fmt.Println("filteredInfos: ", filteredInfos)
|
return filteredInfos
|
}
|