|
@@ -2,7 +2,7 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
|
|
import PaginationService from 'App/Services/PaginationService'
|
|
import PaginationService from 'App/Services/PaginationService'
|
|
|
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
import { schema } from '@ioc:Adonis/Core/Validator'
|
|
|
import OcrDevice from 'App/Models/OcrDevice'
|
|
import OcrDevice from 'App/Models/OcrDevice'
|
|
|
-import OcrChannel from 'App/Models/OcrChannel'
|
|
|
|
|
|
|
+import OcrRecord from 'App/Models/OcrRecord'
|
|
|
import { DateTime } from 'luxon'
|
|
import { DateTime } from 'luxon'
|
|
|
|
|
|
|
|
export default class OcrDevicesController {
|
|
export default class OcrDevicesController {
|
|
@@ -97,57 +97,69 @@ export default class OcrDevicesController {
|
|
|
try {
|
|
try {
|
|
|
const user = auth.user
|
|
const user = auth.user
|
|
|
const isApiUser = user?.$attributes?.role === 'api'
|
|
const isApiUser = user?.$attributes?.role === 'api'
|
|
|
- const query = OcrDevice.query()
|
|
|
|
|
|
|
+ const deviceQuery = OcrDevice.query()
|
|
|
|
|
+ const recordQuery = OcrRecord.query()
|
|
|
|
|
|
|
|
- // 如果是 API 用户,强制使用其 username 作为 channel
|
|
|
|
|
if (isApiUser) {
|
|
if (isApiUser) {
|
|
|
- query.where('channel', user.username)
|
|
|
|
|
|
|
+ deviceQuery.where('channel', user.username)
|
|
|
|
|
+ recordQuery.where('channel', user.username)
|
|
|
} else {
|
|
} else {
|
|
|
- // 如果不是 API 用户,则使用请求中的 channel 参数
|
|
|
|
|
const channel = request.input('channel')
|
|
const channel = request.input('channel')
|
|
|
if (channel) {
|
|
if (channel) {
|
|
|
- query.where('channel', channel)
|
|
|
|
|
|
|
+ deviceQuery.where('channel', channel)
|
|
|
|
|
+ recordQuery.where('channel', channel)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 获取近7天的数据
|
|
// 获取近7天的数据
|
|
|
const sevenDaysAgo = DateTime.now().minus({ days: 7 }).startOf('day').toSQL()
|
|
const sevenDaysAgo = DateTime.now().minus({ days: 7 }).startOf('day').toSQL()
|
|
|
- const data = await query
|
|
|
|
|
|
|
+ const devices = await deviceQuery
|
|
|
.where('createdAt', '>=', sevenDaysAgo)
|
|
.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 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')
|
|
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({
|
|
return response.ok({
|
|
|
dates,
|
|
dates,
|
|
@@ -167,37 +179,43 @@ export default class OcrDevicesController {
|
|
|
try {
|
|
try {
|
|
|
const user = auth.user
|
|
const user = auth.user
|
|
|
const isApiUser = user?.$attributes?.role === 'api'
|
|
const isApiUser = user?.$attributes?.role === 'api'
|
|
|
- const query = OcrDevice.query()
|
|
|
|
|
|
|
+ const deviceQuery = OcrDevice.query()
|
|
|
|
|
+ const recordQuery = OcrRecord.query()
|
|
|
|
|
|
|
|
// 如果是 API 用户,强制使用其 username 作为 channel
|
|
// 如果是 API 用户,强制使用其 username 作为 channel
|
|
|
if (isApiUser) {
|
|
if (isApiUser) {
|
|
|
- query.where('channel', user.username)
|
|
|
|
|
|
|
+ deviceQuery.where('channel', user.username)
|
|
|
|
|
+ recordQuery.where('channel', user.username)
|
|
|
} else {
|
|
} else {
|
|
|
// 如果不是 API 用户,则使用请求中的 channel 参数
|
|
// 如果不是 API 用户,则使用请求中的 channel 参数
|
|
|
const channel = request.input('channel')
|
|
const channel = request.input('channel')
|
|
|
if (channel) {
|
|
if (channel) {
|
|
|
- query.where('channel', channel)
|
|
|
|
|
|
|
+ deviceQuery.where('channel', channel)
|
|
|
|
|
+ recordQuery.where('channel', channel)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 获取今天的数据
|
|
// 获取今天的数据
|
|
|
const today = DateTime.now().startOf('day').toSQL()
|
|
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({
|
|
return response.ok({
|
|
|
date: DateTime.now().toFormat('yyyy-MM-dd'),
|
|
date: DateTime.now().toFormat('yyyy-MM-dd'),
|
|
|
- ...stats
|
|
|
|
|
|
|
+ total,
|
|
|
|
|
+ scanned,
|
|
|
|
|
+ deviceCount
|
|
|
})
|
|
})
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
return response.internalServerError({
|
|
return response.internalServerError({
|