|
|
@@ -127,37 +127,125 @@ export default class OcrDevicesController {
|
|
|
try {
|
|
|
const user = auth.user
|
|
|
const isApiUser = user?.$attributes?.role === 'api'
|
|
|
- const deviceQuery = OcrDevice.query()
|
|
|
- const recordQuery = OcrRecord.query()
|
|
|
|
|
|
- if (isApiUser) {
|
|
|
- deviceQuery.where('channel', user.username)
|
|
|
- recordQuery.where('channel', user.username)
|
|
|
+ // 获取开始日期和结束日期,默认为不包括今天的最近七天
|
|
|
+ let startDate = request.input(
|
|
|
+ 'startDate',
|
|
|
+ DateTime.now().minus({ days: 7 }).startOf('day').toFormat('yyyy-MM-dd HH:mm:ss')
|
|
|
+ )
|
|
|
+ let endDate = request.input(
|
|
|
+ 'endDate',
|
|
|
+ DateTime.now().minus({ days: 1 }).endOf('day').toFormat('yyyy-MM-dd HH:mm:ss')
|
|
|
+ )
|
|
|
+
|
|
|
+ // 处理可能的不同日期格式
|
|
|
+ let startDateTime: DateTime
|
|
|
+ let endDateTime: DateTime
|
|
|
+
|
|
|
+ // 尝试解析开始日期
|
|
|
+ if (startDate.includes(' ')) {
|
|
|
+ // 如果包含空格,假设是完整的日期时间格式
|
|
|
+ startDateTime = DateTime.fromFormat(startDate, 'yyyy-MM-dd HH:mm:ss')
|
|
|
+ if (!startDateTime.isValid) {
|
|
|
+ // 尝试其他可能的格式
|
|
|
+ startDateTime = DateTime.fromISO(startDate)
|
|
|
+ }
|
|
|
} else {
|
|
|
- const channel = request.input('channel')
|
|
|
- if (channel) {
|
|
|
- deviceQuery.where('channel', channel)
|
|
|
- recordQuery.where('channel', channel)
|
|
|
+ // 只有日期部分
|
|
|
+ startDateTime = DateTime.fromFormat(startDate, 'yyyy-MM-dd').startOf('day')
|
|
|
+ startDate = startDateTime.toFormat('yyyy-MM-dd HH:mm:ss')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 尝试解析结束日期
|
|
|
+ if (endDate.includes(' ')) {
|
|
|
+ // 如果包含空格,假设是完整的日期时间格式
|
|
|
+ endDateTime = DateTime.fromFormat(endDate, 'yyyy-MM-dd HH:mm:ss')
|
|
|
+ if (!endDateTime.isValid) {
|
|
|
+ // 尝试其他可能的格式
|
|
|
+ endDateTime = DateTime.fromISO(endDate)
|
|
|
}
|
|
|
+ } else {
|
|
|
+ // 只有日期部分,设置为当天结束
|
|
|
+ endDateTime = DateTime.fromFormat(endDate, 'yyyy-MM-dd').endOf('day')
|
|
|
+ endDate = endDateTime.toFormat('yyyy-MM-dd HH:mm:ss')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证日期是否有效
|
|
|
+ if (!startDateTime.isValid || !endDateTime.isValid) {
|
|
|
+ return response.badRequest({
|
|
|
+ message: '无效的日期格式',
|
|
|
+ details: {
|
|
|
+ startDate: startDateTime.isValid ? '有效' : '无效',
|
|
|
+ endDate: endDateTime.isValid ? '有效' : '无效'
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
- // 获取近7天的数据
|
|
|
- const sevenDaysAgo = DateTime.now().minus({ days: 7 }).startOf('day').toSQL()
|
|
|
- const devices = await deviceQuery
|
|
|
- .where('createdAt', '>=', sevenDaysAgo)
|
|
|
- .select('id', 'total', 'scanned', 'createdAt', 'channel')
|
|
|
+ // 计算日期之间的天数差
|
|
|
+ const diffInDays = Math.max(1, Math.ceil(endDateTime.diff(startDateTime, 'days').days))
|
|
|
|
|
|
- // 过去7天的日期数组
|
|
|
+ console.log('日期调试信息:', {
|
|
|
+ startDate,
|
|
|
+ endDate,
|
|
|
+ startDateTime: startDateTime.toISO(),
|
|
|
+ endDateTime: endDateTime.toISO(),
|
|
|
+ diffInDays
|
|
|
+ })
|
|
|
+
|
|
|
+ // 生成日期数组
|
|
|
const dates: string[] = []
|
|
|
- for (let i = 6; i >= 0; i--) {
|
|
|
- const date = DateTime.now().minus({ days: i }).toFormat('yyyy-MM-dd')
|
|
|
+ for (let i = 0; i < diffInDays; i++) {
|
|
|
+ const date = startDateTime.plus({ days: i }).toFormat('yyyy-MM-dd')
|
|
|
dates.push(date)
|
|
|
}
|
|
|
- const dailyStats: Record<
|
|
|
- string,
|
|
|
- { total: number; scanned: number; deviceCount: number }
|
|
|
- > = {}
|
|
|
|
|
|
+ // 准备查询条件
|
|
|
+ let channelCondition = {}
|
|
|
+ if (isApiUser) {
|
|
|
+ channelCondition = { channel: user.username }
|
|
|
+ } else if (request.input('channel')) {
|
|
|
+ channelCondition = { channel: request.input('channel') }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用SQL直接获取每日设备统计数据
|
|
|
+ const deviceStatsQuery = Database.from('ocr_devices')
|
|
|
+ .select(
|
|
|
+ Database.raw("DATE_FORMAT(created_at, '%Y-%m-%d') as date"),
|
|
|
+ Database.raw('COUNT(id) as device_count'),
|
|
|
+ Database.raw('SUM(scanned) as scanned_count')
|
|
|
+ )
|
|
|
+ .whereBetween('created_at', [startDate, endDate])
|
|
|
+ .groupBy('date')
|
|
|
+ .orderBy('date', 'asc')
|
|
|
+
|
|
|
+ // 添加渠道条件
|
|
|
+ if (Object.keys(channelCondition).length > 0) {
|
|
|
+ deviceStatsQuery.where(channelCondition)
|
|
|
+ }
|
|
|
+
|
|
|
+ const deviceStats = await deviceStatsQuery
|
|
|
+
|
|
|
+ // 使用SQL直接获取每日记录统计数据
|
|
|
+ const recordStatsQuery = Database.from('ocr_records')
|
|
|
+ .select(
|
|
|
+ Database.raw("DATE_FORMAT(created_at, '%Y-%m-%d') as date"),
|
|
|
+ Database.raw('COUNT(id) as record_count')
|
|
|
+ )
|
|
|
+ .whereBetween('created_at', [startDate, endDate])
|
|
|
+ .groupBy('date')
|
|
|
+ .orderBy('date', 'asc')
|
|
|
+
|
|
|
+ // 添加渠道条件
|
|
|
+ if (Object.keys(channelCondition).length > 0) {
|
|
|
+ recordStatsQuery.where(channelCondition)
|
|
|
+ }
|
|
|
+
|
|
|
+ const recordStats = await recordStatsQuery
|
|
|
+
|
|
|
+ // 合并结果
|
|
|
+ const dailyStats = {}
|
|
|
+
|
|
|
+ // 初始化所有日期的统计数据
|
|
|
dates.forEach((date) => {
|
|
|
dailyStats[date] = {
|
|
|
total: 0,
|
|
|
@@ -166,25 +254,20 @@ export default class OcrDevicesController {
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- // 按设备创建日期统计数据 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
|
|
|
+ // 填充设备统计数据
|
|
|
+ deviceStats.forEach((stat) => {
|
|
|
+ if (dailyStats[stat.date]) {
|
|
|
+ dailyStats[stat.date].scanned = Number(stat.scanned_count) || 0
|
|
|
+ dailyStats[stat.date].deviceCount = Number(stat.device_count) || 0
|
|
|
}
|
|
|
- }
|
|
|
+ })
|
|
|
|
|
|
- // 获取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 Database.from('ocr_records')
|
|
|
- .where('created_at', '>=', startDate)
|
|
|
- .where('created_at', '<=', endDate)
|
|
|
- .count('* as total')
|
|
|
- dailyStats[date].total = Number(recordCount[0].total) || 0
|
|
|
- }
|
|
|
+ // 填充记录统计数据
|
|
|
+ recordStats.forEach((stat) => {
|
|
|
+ if (dailyStats[stat.date]) {
|
|
|
+ dailyStats[stat.date].total = Number(stat.record_count) || 0
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
// 转换为前端需要的数组格式
|
|
|
const totals = dates.map((date) => dailyStats[date].total)
|
|
|
@@ -210,46 +293,59 @@ export default class OcrDevicesController {
|
|
|
const user = auth.user
|
|
|
const isApiUser = user?.$attributes?.role === 'api'
|
|
|
const deviceQuery = OcrDevice.query()
|
|
|
- const recordQuery = OcrRecord.query()
|
|
|
|
|
|
- // 如果是 API 用户,强制使用其 username 作为 channel
|
|
|
+ // 如果是API用户,强制使用其username作为channel
|
|
|
if (isApiUser) {
|
|
|
deviceQuery.where('channel', user.username)
|
|
|
- recordQuery.where('channel', user.username)
|
|
|
} else {
|
|
|
- // 如果不是 API 用户,则使用请求中的 channel 参数
|
|
|
+ // 如果不是API用户,则使用请求中的channel参数
|
|
|
const channel = request.input('channel')
|
|
|
if (channel) {
|
|
|
deviceQuery.where('channel', channel)
|
|
|
- recordQuery.where('channel', channel)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 获取今天的数据
|
|
|
- const today = DateTime.now().startOf('day').toSQL()
|
|
|
- const todayEnd = DateTime.now().endOf('day').toSQL()
|
|
|
+ // 获取指定日期的数据,默认为今天
|
|
|
+ const targetDate = request.input('date', DateTime.now().toFormat('yyyy-MM-dd'))
|
|
|
+ const dayStart = DateTime.fromFormat(targetDate, 'yyyy-MM-dd').startOf('day').toSQL()
|
|
|
+ const dayEnd = DateTime.fromFormat(targetDate, 'yyyy-MM-dd').endOf('day').toSQL()
|
|
|
+
|
|
|
// 获取设备数据
|
|
|
- const deviceData = await deviceQuery.where('createdAt', '>=', today).select('scanned')
|
|
|
+ const deviceData = await deviceQuery
|
|
|
+ .where('createdAt', '>=', dayStart)
|
|
|
+ .where('createdAt', '<=', dayEnd)
|
|
|
+ .select('scanned')
|
|
|
+
|
|
|
// 获取OcrRecord数据
|
|
|
const recordCount = await Database.from('ocr_records')
|
|
|
- .where('created_at', '>=', today)
|
|
|
- .where('created_at', '<=', todayEnd)
|
|
|
+ .where('created_at', '>=', dayStart)
|
|
|
+ .where('created_at', '<=', dayEnd)
|
|
|
+ .where(function (query) {
|
|
|
+ if (isApiUser) {
|
|
|
+ query.where('channel', user.username)
|
|
|
+ } else {
|
|
|
+ const channel = request.input('channel')
|
|
|
+ if (channel) {
|
|
|
+ query.where('channel', channel)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
.count('* as total')
|
|
|
|
|
|
- // 计算今日统计数据
|
|
|
+ // 计算统计数据
|
|
|
const scanned = deviceData.reduce((acc, item) => acc + item.scanned, 0)
|
|
|
const total = Number(recordCount[0].total) || 0
|
|
|
const deviceCount = deviceData.length
|
|
|
|
|
|
return response.ok({
|
|
|
- date: DateTime.now().toFormat('yyyy-MM-dd'),
|
|
|
+ date: targetDate,
|
|
|
total,
|
|
|
scanned,
|
|
|
deviceCount
|
|
|
})
|
|
|
} catch (error) {
|
|
|
return response.internalServerError({
|
|
|
- message: '获取今日统计数据时发生错误',
|
|
|
+ message: '获取统计数据时发生错误',
|
|
|
error: error.message
|
|
|
})
|
|
|
}
|