sunty
2024-09-03 b0f374409775bd30ed8f0dc8d47d015d3edc0abb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
package rule
 
import (
    "basic.com/valib/logger.git"
    "fmt"
    "math"
    "ruleModelEngine/db"
    "strings"
    "time"
)
 
func processResidentStatus(residents []db.Resident) []db.MoveInout {
    // 获取当前日期的年月日
    now := time.Now()
    currentDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
    moveInout := make([]db.MoveInout, 0)
 
    // 遍历Resident结构体切片
    for _, resident := range residents {
        //fmt.Println("gogogogo!!!!!!!!!!!!!!!!!!!!!!!!!!!")
        // 将字符串类型的时间转换为time.Time类型,并只保留年月日
        lastAppearanceTime := time.Unix(resident.LastAppearanceTime, 0)
        lastAppearanceDate := time.Date(lastAppearanceTime.Year(), lastAppearanceTime.Month(), lastAppearanceTime.Day(), 0, 0, 0, 0, lastAppearanceTime.Location())
        //lastAppearanceTime, err := time.Parse("2006-01-02", resident.LastAppearanceTime)
        datePart := strings.Split(resident.CreateAt, "T")[0]
        createdAt, err := time.Parse("2006-01-02", datePart)
        if err != nil {
            fmt.Println(err)
            // 处理时间解析错误
            // 可以选择跳过该条数据或者记录日志
            continue
        }
        // 计算LastAppearanceTime和CreateAt距离当前日期的天数
        daysSinceLastAppearance := currentDate.Sub(lastAppearanceDate).Hours() / 24
        daysSinceCreateAt := currentDate.Sub(createdAt).Hours() / 24
 
        moveType := "MoveIn"
        status := ""
        //fmt.Println("daysSinceLastAppearance: ", daysSinceLastAppearance)
        //fmt.Println("daysSinceCreateAt: ", daysSinceCreateAt)
        // 判断是否为疑似搬离或确认搬离
        if daysSinceLastAppearance > 15 {
            moveType = "MoveOut"
            status = "Pending"
        } else if daysSinceLastAppearance > 30 {
            moveType = "MoveOut"
            status = "Confirmed"
        }
 
        // 判断是否为疑似入住或确认入住
        if moveType == "MoveIn" {
            if daysSinceCreateAt > 15 {
                status = "Pending"
            } else if daysSinceCreateAt > 30 {
                status = "Confirmed"
            }
        }
 
        if status == "" {
            continue
        }
        //fmt.Println("status: ", status)
        moveInout = append(moveInout, db.MoveInout{
            DocumentNumber: resident.DocumentNumber,
            CommunityID:    resident.CommunityId,
            MoveInDate:     createdAt,           // 存储年月日
            MoveOutDate:    &lastAppearanceDate, // 存储年月日
            MoveType:       moveType,
            Status:         status,
        })
    }
 
    return moveInout
}
 
//func ProcessRuleEngine(personInfos []db.CaptureInfo, ruleInfo []db.PersonnelStatusRule, cmmunityID string) (bool, error) {
//    ruleInfoCheck := checkRuleValidity(ruleInfo)
//    if ruleInfoCheck == false {
//        logger.Error("规则库数据异常")
//        return false, errors.New("规则库数据异常")
//    }
//    fmt.Println("清洗前: ", len(personInfos))
//    logger.Info("规则算法执行完毕!!!")
//    return true, nil
//}
 
func CreateLinearModel(personInfos []db.CaptureInfo, communityID string, threshold float64, validDays int, labelId int) ([]db.Identity, []db.CaptureInfo) {
    identity := make([]db.Identity, 0)
    captureInfo := make([]db.CaptureInfo, 0)
    for _, info := range personInfos {
        if info.Status == "resident" {
            addrData := make(map[string]int)
            //fmt.Println("DocumentNumber: ", info.DocumentNumber)
            for _, addr := range info.CaptureDetail {
                if !strings.Contains(addr.CaptureAddress, "F") || addr.Direction == "in" {
                    continue
                }
                addrData[addr.CaptureAddress]++
            }
            if len(addrData) < 5 {
                captureInfo = append(captureInfo, info)
                continue
            }
            addrDataArray := mapIntToFloatSlice(addrData)
            derivative := firstDerivative(addrDataArray)
            //fmt.Println(addrData)
            stdDev := stdDeviation(derivative)
            if len(addrDataArray) > 10 {
                stdDev = stdDev / 2
            }
 
            if stdDev < threshold {
                //fmt.Println(addrDataArray)
                //fmt.Println("threshold: ", threshold)
                //fmt.Println("stdDev: ", stdDev)
                info.Status = "fieldworker"
                captureInfo = append(captureInfo, info)
                identity = append(identity, db.Identity{
                    CommunityID:    communityID,
                    DocumentNumber: info.DocumentNumber,
                    LabelId:        labelId,
                    ExpireTime:     GetCurrentDateAddDaysTimestamp(validDays)})
                continue
            }
            captureInfo = append(captureInfo, info)
        } else {
            captureInfo = append(captureInfo, info)
        }
 
    }
    //addressLinearData := []
    return identity, captureInfo
}
 
func totalDirection(personInfos []db.CaptureInfo) {
    // 统计每个地址的进出情况
    addrData := make(map[string]map[string]int) // 使用map[string]map[string]int来存储每个地址的进出情况
    for _, info := range personInfos {
        if info.Status == "resident" {
            for _, addr := range info.CaptureDetail {
                if !strings.Contains(addr.CaptureAddress, "F") {
                    continue
                }
                // 检查该地址是否已经在addrData中
                if _, ok := addrData[addr.CaptureAddress]; !ok {
                    addrData[addr.CaptureAddress] = make(map[string]int)
                }
                // 更新该地址的进出情况
                addrData[addr.CaptureAddress][addr.Direction]++
            }
        }
    }
    fmt.Println(addrData)
}
 
func CreateProcessModel(personInfos []db.CaptureInfo, days int, communityID string, labelManage []db.LabelManage) []db.Identity {
    labelIndexMap := make(map[string]int)
    for index, labelManageInfo := range labelManage {
        labelIndexMap[labelManageInfo.Name] = index
    }
    identity := make([]db.Identity, 0)
    for _, info := range personInfos {
        timeTOIndex := getIndexForTime(24 * 60)
        dateTOIndex := getIndexForDate(days)
        //fmt.Println(dateTOIndex)
        inModelMatrix := make([][]int, days)
        for i := range inModelMatrix {
            inModelMatrix[i] = make([]int, 24*60)
        }
        outModelMatrix := make([][]int, days)
        for i := range outModelMatrix {
            outModelMatrix[i] = make([]int, 24*60)
        }
        //fmt.Println("info: ", info)
        for _, captureInfo := range info.CaptureDetail {
            captrueDateTime := captureInfo.CaptureDate
            dateTimeObj, err := time.Parse("2006-01-02 15:04:05", captrueDateTime)
            if err != nil {
                logger.Error("Parse time error", err)
                continue
                //return n/**/il, err
            }
            if isWeekend(dateTimeObj) {
                continue
            }
            datePart := dateTimeObj.Format("2006-01-02")
            timePart := dateTimeObj.Format("15:04")
            switch captureInfo.Direction {
            case "out":
                outModelMatrix[dateTOIndex[datePart]][timeTOIndex[timePart]] = 1
            case "in":
                inModelMatrix[dateTOIndex[datePart]][timeTOIndex[timePart]] = 1
            default:
                continue
            }
        }
        countMaxRows, colS, colE := CountMaxRows(outModelMatrix, 30, 30)
        logger.Info("规律出勤时间段:", colS, colE, "\t次数: ", countMaxRows)
        if countMaxRows >= 10 {
            if info.Age <= 22 && info.Age >= 7 {
                lIndex := labelIndexMap["学生"]
                identity = append(identity, db.Identity{
                    CommunityID:    communityID,
                    DocumentNumber: info.DocumentNumber,
                    LabelId:        labelManage[lIndex].Id,
                    ExpireTime:     GetCurrentDateAddDaysTimestamp(labelManage[lIndex].ValidDays)})
            } else if info.Age >= 23 && info.Age <= 60 {
                lIndex := labelIndexMap["上班族"]
                identity = append(identity, db.Identity{
                    CommunityID:    communityID,
                    DocumentNumber: info.DocumentNumber,
                    LabelId:        labelManage[lIndex].Id,
                    ExpireTime:     GetCurrentDateAddDaysTimestamp(labelManage[lIndex].ValidDays)})
            } else if info.Age > 60 {
                lIndex := labelIndexMap["离退休人员"]
                identity = append(identity, db.Identity{
                    CommunityID:    communityID,
                    DocumentNumber: info.DocumentNumber,
                    LabelId:        labelManage[lIndex].Id,
                    ExpireTime:     GetCurrentDateAddDaysTimestamp(labelManage[lIndex].ValidDays)})
            }
            //fmt.Println("上班族", info.DocumentNumber, info.Age, countMaxRows, colS, colE)
        } else {
            countMaxRows, colS, colE := CountMaxRows(inModelMatrix, 30, 30)
            logger.Info("规律出勤时间段:", colS, colE, "\t次数: ", countMaxRows)
            if countMaxRows >= 10 {
                if info.Age <= 22 && info.Age >= 7 {
                    lIndex := labelIndexMap["学生"]
                    identity = append(identity, db.Identity{
                        CommunityID:    communityID,
                        DocumentNumber: info.DocumentNumber,
                        LabelId:        labelManage[lIndex].Id,
                        ExpireTime:     GetCurrentDateAddDaysTimestamp(labelManage[lIndex].ValidDays)})
                } else if info.Age >= 23 && info.Age <= 60 {
                    lIndex := labelIndexMap["上班族"]
                    identity = append(identity, db.Identity{
                        CommunityID:    communityID,
                        DocumentNumber: info.DocumentNumber,
                        LabelId:        labelManage[lIndex].Id,
                        ExpireTime:     GetCurrentDateAddDaysTimestamp(labelManage[lIndex].ValidDays)})
                } else if info.Age > 60 {
                    lIndex := labelIndexMap["离退休人员"]
                    identity = append(identity, db.Identity{
                        CommunityID:    communityID,
                        DocumentNumber: info.DocumentNumber,
                        LabelId:        labelManage[lIndex].Id,
                        ExpireTime:     GetCurrentDateAddDaysTimestamp(labelManage[lIndex].ValidDays)})
                }
                //fmt.Println("上班族", info.DocumentNumber, info.Age, countMaxRows, colS, colE)
            }
        }
 
        //fmt.Println("outModelMatrix: ", outModelMatrix)
        //fmt.Println("inModelMatrix: ", inModelMatrix)
    }
    return identity
}
 
// 计算一阶导数
func firstDerivative(data []float64) []float64 {
    n := len(data)
    derivative := make([]float64, n)
 
    for i := 0; i < n-1; i++ {
        derivative[i] = data[i+1] - data[i]
    }
 
    return derivative
}
 
// 计算导数的标准差
func stdDeviation(data []float64) float64 {
    n := len(data)
    mean := 0.0
 
    // 计算平均值
    for _, value := range data {
        mean += value
    }
    mean /= float64(n)
 
    // 计算方差
    sum := 0.0
    for _, value := range data {
        sum += math.Pow(value-mean, 2)
    }
    variance := sum / float64(n)
 
    return math.Sqrt(variance)
}
 
// 将 map[string]int 转换为 []float64
func mapIntToFloatSlice(addrData map[string]int) []float64 {
    var data []float64
 
    // 遍历 addrData,将其值转换为 float64 类型后添加到 data 中
    for _, v := range addrData {
        data = append(data, float64(v))
    }
 
    return data
}
 
// GetCurrentDateAddDaysTimestamp 返回当前日期加上指定天数后的时间戳(秒)
func GetCurrentDateAddDaysTimestamp(days int) int64 {
    // 获取当前时间
    now := time.Now()
 
    // 只保留年月日部分
    currentYear, currentMonth, currentDay := now.Date()
 
    // 构建当天零点时间
    zeroTime := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, now.Location())
 
    // 将天数转换为Duration类型
    duration := time.Duration(days) * 24 * time.Hour
 
    // 计算指定天数后的时间
    futureTime := zeroTime.Add(duration)
 
    // 返回时间戳(秒)
    return futureTime.Unix()
}
 
// 减去指定天数后的日期
func subtractDays(days int) time.Time {
    // 获取当前时间
    now := time.Now()
 
    // 减去指定天数
    previousDays := now.AddDate(0, 0, -days)
 
    return previousDays
}
 
// 判断给定日期是否是周末
func isWeekend(date time.Time) bool {
    dayOfWeek := date.Weekday()
    return dayOfWeek == time.Saturday || dayOfWeek == time.Sunday
}
 
// 获取个日期内总天数对应的索引
func getIndexForDate(days int) map[string]int {
    startDate := subtractDays(days)
    endDate := subtractDays(1)
    arraySize := days
    layout := "2006-01-02"
    dateTOIndex := make(map[string]int)
    for i := 0; i <= int(endDate.Sub(startDate).Hours()/24); i++ {
        date := startDate.AddDate(0, 0, i)
        offsetDays := int(date.Sub(startDate).Hours() / 24)
        arrayIndex := offsetDays % arraySize
        dateTOIndex[date.Format(layout)] = arrayIndex
    }
 
    return dateTOIndex
}
 
// 获取一天中每分钟的索引位置映射
func getIndexForTime(arraySize int) map[string]int {
    timeTOIndex := make(map[string]int)
 
    for i := 0; i < arraySize; i++ {
        hour := i / 60
        minute := i % 60
        timeStr := fmt.Sprintf("%02d:%02d", hour, minute)
        timeTOIndex[timeStr] = i
    }
 
    return timeTOIndex
}