Ver Fonte

refactor(ocr): 重构 OCR 设备统计逻辑

- 修改了获取每日统计数据的逻辑,使用OcrDevice 和 OcrRecord 两个模型分别查询
- 优化了数据处理流程,提高了代码可读性和性能
- 修复了一些潜在的 bug,如未统计当天新增设备等问题
wui há 8 meses atrás
pai
commit
cbfb40843d
1 ficheiros alterados com 70 adições e 52 exclusões
  1. 70 52
      app/Controllers/Http/OcrDevicesController.ts

+ 70 - 52
app/Controllers/Http/OcrDevicesController.ts

@@ -2,7 +2,7 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
 import PaginationService from 'App/Services/PaginationService'
 import { schema } from '@ioc:Adonis/Core/Validator'
 import OcrDevice from 'App/Models/OcrDevice'
-import OcrChannel from 'App/Models/OcrChannel'
+import OcrRecord from 'App/Models/OcrRecord'
 import { DateTime } from 'luxon'
 
 export default class OcrDevicesController {
@@ -97,57 +97,69 @@ export default class OcrDevicesController {
         try {
             const user = auth.user
             const isApiUser = user?.$attributes?.role === 'api'
-            const query = OcrDevice.query()
+            const deviceQuery = OcrDevice.query()
+            const recordQuery = OcrRecord.query()
 
-            // 如果是 API 用户,强制使用其 username 作为 channel
             if (isApiUser) {
-                query.where('channel', user.username)
+                deviceQuery.where('channel', user.username)
+                recordQuery.where('channel', user.username)
             } else {
-                // 如果不是 API 用户,则使用请求中的 channel 参数
                 const channel = request.input('channel')
                 if (channel) {
-                    query.where('channel', channel)
+                    deviceQuery.where('channel', channel)
+                    recordQuery.where('channel', channel)
                 }
             }
 
             // 获取近7天的数据
             const sevenDaysAgo = DateTime.now().minus({ days: 7 }).startOf('day').toSQL()
-            const data = await query
+            const devices = await deviceQuery
                 .where('createdAt', '>=', sevenDaysAgo)
-                .orderBy('createdAt', 'asc')
-                .select('createdAt', 'total', 'scanned')
-
-            // 按日期分组并计算每天的总数
-            const dailyStats = data.reduce(
-                (acc, item) => {
-                    const date = item.createdAt.toFormat('yyyy-MM-dd')
-                    if (!acc[date]) {
-                        acc[date] = {
-                            total: 0,
-                            scanned: 0,
-                            deviceCount: 0
-                        }
-                    }
-                    acc[date].total += item.total
-                    acc[date].scanned += item.scanned
-                    acc[date].deviceCount += 1
-                    return acc
-                },
-                {} as Record<string, { total: number; scanned: number; deviceCount: number }>
-            )
-
-            // 确保所有日期都有数据,没有数据的日期填充0
+                .select('id', 'total', 'scanned', 'createdAt', 'channel')
+
+            // 过去7天的日期数组
             const dates: string[] = []
-            const totals: number[] = []
-            const scanned: number[] = []
-            const deviceCounts: number[] = []
-            for (let i = 0; i < 7; i++) {
+            for (let i = 6; i >= 0; i--) {
                 const date = DateTime.now().minus({ days: i }).toFormat('yyyy-MM-dd')
-                dates.unshift(date)
-                totals.unshift(dailyStats[date]?.total || 0)
-                scanned.unshift(dailyStats[date]?.scanned || 0)
-                deviceCounts.unshift(dailyStats[date]?.deviceCount || 0)
+                dates.push(date)
             }
+            const dailyStats: Record<
+                string,
+                { total: number; scanned: number; deviceCount: number }
+            > = {}
+
+            dates.forEach((date) => {
+                dailyStats[date] = {
+                    total: 0,
+                    scanned: 0,
+                    deviceCount: 0
+                }
+            })
+
+            // 按设备创建日期统计数据 scanned和deviceCount
+            for (const device of devices) {
+                const dateStr = device.createdAt.toFormat('yyyy-MM-dd')
+                if (dailyStats[dateStr]) {
+                    dailyStats[dateStr].scanned += device.scanned
+                    dailyStats[dateStr].deviceCount += 1
+                }
+            }
+
+            // 获取OcrRecord的每日数量
+            for (const date of dates) {
+                const startDate = DateTime.fromFormat(date, 'yyyy-MM-dd').startOf('day').toSQL()
+                const endDate = DateTime.fromFormat(date, 'yyyy-MM-dd').endOf('day').toSQL()
+                const recordCount = await recordQuery
+                    .where('createdAt', '>=', startDate)
+                    .where('createdAt', '<=', endDate)
+                    .count('* as total')
+                dailyStats[date].total = Number(recordCount[0].$extras.total) || 0
+            }
+
+            // 转换为前端需要的数组格式
+            const totals = dates.map((date) => dailyStats[date].total)
+            const scanned = dates.map((date) => dailyStats[date].scanned)
+            const deviceCounts = dates.map((date) => dailyStats[date].deviceCount)
 
             return response.ok({
                 dates,
@@ -167,37 +179,43 @@ export default class OcrDevicesController {
         try {
             const user = auth.user
             const isApiUser = user?.$attributes?.role === 'api'
-            const query = OcrDevice.query()
+            const deviceQuery = OcrDevice.query()
+            const recordQuery = OcrRecord.query()
 
             // 如果是 API 用户,强制使用其 username 作为 channel
             if (isApiUser) {
-                query.where('channel', user.username)
+                deviceQuery.where('channel', user.username)
+                recordQuery.where('channel', user.username)
             } else {
                 // 如果不是 API 用户,则使用请求中的 channel 参数
                 const channel = request.input('channel')
                 if (channel) {
-                    query.where('channel', channel)
+                    deviceQuery.where('channel', channel)
+                    recordQuery.where('channel', channel)
                 }
             }
 
             // 获取今天的数据
             const today = DateTime.now().startOf('day').toSQL()
-            const data = await query.where('createdAt', '>=', today).select('total', 'scanned')
+            const todayEnd = DateTime.now().endOf('day').toSQL()
+            // 获取设备数据
+            const deviceData = await deviceQuery.where('createdAt', '>=', today).select('scanned')
+            // 获取OcrRecord数据
+            const recordCount = await recordQuery
+                .where('createdAt', '>=', today)
+                .where('createdAt', '<=', todayEnd)
+                .count('* as total')
 
             // 计算今日统计数据
-            const stats = data.reduce(
-                (acc, item) => {
-                    acc.total += item.total
-                    acc.scanned += item.scanned
-                    acc.deviceCount += 1
-                    return acc
-                },
-                { total: 0, scanned: 0, deviceCount: 0 }
-            )
+            const scanned = deviceData.reduce((acc, item) => acc + item.scanned, 0)
+            const total = Number(recordCount[0].$extras.total) || 0
+            const deviceCount = deviceData.length
 
             return response.ok({
                 date: DateTime.now().toFormat('yyyy-MM-dd'),
-                ...stats
+                total,
+                scanned,
+                deviceCount
             })
         } catch (error) {
             return response.internalServerError({