OcrDevicesController.ts 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
  2. import PaginationService from 'App/Services/PaginationService'
  3. import { schema } from '@ioc:Adonis/Core/Validator'
  4. import OcrDevice from 'App/Models/OcrDevice'
  5. import OcrRecord from 'App/Models/OcrRecord'
  6. import OcrChannel from 'App/Models/OcrChannel'
  7. import { DateTime } from 'luxon'
  8. import * as console from 'node:console'
  9. import Database from '@ioc:Adonis/Lucid/Database'
  10. export default class OcrDevicesController {
  11. private paginationService = new PaginationService(OcrDevice)
  12. public async index({ request, auth }: HttpContextContract) {
  13. const user = auth.user
  14. const isApiUser = user?.$attributes?.role === 'api'
  15. const requestData = request.all()
  16. if (isApiUser) {
  17. requestData.channel = user.username
  18. }
  19. return await this.paginationService.paginate(request.all())
  20. }
  21. public async store({ request, bouncer }: HttpContextContract) {
  22. // await bouncer.authorize('admin')
  23. const data = await request.validate({
  24. schema: schema.create({
  25. id: schema.string(),
  26. platform: schema.string(),
  27. channel: schema.string(),
  28. deviceInfo: schema.string.optional(),
  29. total: schema.number(),
  30. scanned: schema.number(),
  31. ipAddress: schema.string.optional()
  32. })
  33. })
  34. const clientIp = request.ip()
  35. if (!data.ipAddress) {
  36. data.ipAddress = clientIp
  37. }
  38. const device = await OcrDevice.findBy('id', data.id)
  39. let ocrDevice: OcrDevice
  40. if (device) {
  41. device.merge(data)
  42. ocrDevice = await device.save()
  43. } else {
  44. ocrDevice = await OcrDevice.create(data)
  45. }
  46. // 更新渠道统计数据
  47. await this.updateNums(data.channel)
  48. return ocrDevice
  49. }
  50. private async updateNums(channel: string) {
  51. if (channel) {
  52. const ocrChannel = await OcrChannel.findBy('name', channel)
  53. if (ocrChannel) {
  54. const deviceCount = await OcrDevice.query()
  55. .where('channel', channel)
  56. .count('* as total')
  57. const recordCount = await OcrRecord.query()
  58. .where('channel', channel)
  59. .count('* as total')
  60. const scanSum = await OcrDevice.query()
  61. .where('channel', channel)
  62. .sum('scanned as total')
  63. ocrChannel.deviceNum = Number(deviceCount[0].$extras.total || 0)
  64. ocrChannel.recordNum = Number(recordCount[0].$extras.total || 0)
  65. ocrChannel.scanNum = Number(scanSum[0].$extras.total || 0)
  66. await ocrChannel.save()
  67. }
  68. }
  69. }
  70. public async show({ params, bouncer }: HttpContextContract) {
  71. await bouncer.authorize('admin')
  72. return await OcrDevice.findOrFail(params.id)
  73. }
  74. public async plusTotal({ request, response }: HttpContextContract) {
  75. try {
  76. const device = await OcrDevice.findBy('id', request.param('id'))
  77. if (!device) {
  78. return response.notFound({ message: `未找到ID为 ${request.param('id')} 的OCR设备` })
  79. }
  80. device.total += 1
  81. await device.save()
  82. return response.ok(device)
  83. } catch (error) {
  84. return response.internalServerError({
  85. message: '更新设备记录数量时发生错误',
  86. error: error.message
  87. })
  88. }
  89. }
  90. public async plusScanned({ request, response }: HttpContextContract) {
  91. const scanCount = Number(request.param('scanCount'))
  92. if (isNaN(scanCount)) {
  93. return response.badRequest({ message: 'scanCount 参数必须是有效数字' })
  94. }
  95. try {
  96. const device = await OcrDevice.findBy('id', request.param('id'))
  97. if (!device) {
  98. return response.notFound({
  99. message: `未找到 ID 为 ${request.param('id')} 的 OCR 设备`
  100. })
  101. }
  102. device.scanned += scanCount
  103. await device.save()
  104. return response.ok(device)
  105. } catch (error) {
  106. return response.internalServerError({
  107. message: '更新设备扫描数量时发生错误',
  108. error: error.message
  109. })
  110. }
  111. }
  112. public async getStatistics({ request, response, auth }: HttpContextContract) {
  113. try {
  114. const user = auth.user
  115. const isApiUser = user?.$attributes?.role === 'api'
  116. const deviceQuery = OcrDevice.query()
  117. const recordQuery = OcrRecord.query()
  118. if (isApiUser) {
  119. deviceQuery.where('channel', user.username)
  120. recordQuery.where('channel', user.username)
  121. } else {
  122. const channel = request.input('channel')
  123. if (channel) {
  124. deviceQuery.where('channel', channel)
  125. recordQuery.where('channel', channel)
  126. }
  127. }
  128. // 获取近7天的数据
  129. const sevenDaysAgo = DateTime.now().minus({ days: 7 }).startOf('day').toSQL()
  130. const devices = await deviceQuery
  131. .where('createdAt', '>=', sevenDaysAgo)
  132. .select('id', 'total', 'scanned', 'createdAt', 'channel')
  133. // 过去7天的日期数组
  134. const dates: string[] = []
  135. for (let i = 6; i >= 0; i--) {
  136. const date = DateTime.now().minus({ days: i }).toFormat('yyyy-MM-dd')
  137. dates.push(date)
  138. }
  139. const dailyStats: Record<
  140. string,
  141. { total: number; scanned: number; deviceCount: number }
  142. > = {}
  143. dates.forEach((date) => {
  144. dailyStats[date] = {
  145. total: 0,
  146. scanned: 0,
  147. deviceCount: 0
  148. }
  149. })
  150. // 按设备创建日期统计数据 scanned和deviceCount
  151. for (const device of devices) {
  152. const dateStr = device.createdAt.toFormat('yyyy-MM-dd')
  153. if (dailyStats[dateStr]) {
  154. dailyStats[dateStr].scanned += device.scanned
  155. dailyStats[dateStr].deviceCount += 1
  156. }
  157. }
  158. // 获取OcrRecord的每日数量
  159. for (const date of dates) {
  160. const startDate = DateTime.fromFormat(date, 'yyyy-MM-dd').startOf('day').toSQL()
  161. const endDate = DateTime.fromFormat(date, 'yyyy-MM-dd').endOf('day').toSQL()
  162. const recordCount = await Database.from('ocr_records')
  163. .where('created_at', '>=', startDate)
  164. .where('created_at', '<=', endDate)
  165. .count('* as total')
  166. dailyStats[date].total = Number(recordCount[0].total) || 0
  167. }
  168. // 转换为前端需要的数组格式
  169. const totals = dates.map((date) => dailyStats[date].total)
  170. const scanned = dates.map((date) => dailyStats[date].scanned)
  171. const deviceCounts = dates.map((date) => dailyStats[date].deviceCount)
  172. return response.ok({
  173. dates,
  174. total: totals,
  175. scanned: scanned,
  176. deviceCount: deviceCounts
  177. })
  178. } catch (error) {
  179. return response.internalServerError({
  180. message: '获取设备统计数据时发生错误',
  181. error: error.message
  182. })
  183. }
  184. }
  185. public async getTodayStatistics({ request, response, auth }: HttpContextContract) {
  186. try {
  187. const user = auth.user
  188. const isApiUser = user?.$attributes?.role === 'api'
  189. const deviceQuery = OcrDevice.query()
  190. const recordQuery = OcrRecord.query()
  191. // 如果是 API 用户,强制使用其 username 作为 channel
  192. if (isApiUser) {
  193. deviceQuery.where('channel', user.username)
  194. recordQuery.where('channel', user.username)
  195. } else {
  196. // 如果不是 API 用户,则使用请求中的 channel 参数
  197. const channel = request.input('channel')
  198. if (channel) {
  199. deviceQuery.where('channel', channel)
  200. recordQuery.where('channel', channel)
  201. }
  202. }
  203. // 获取今天的数据
  204. const today = DateTime.now().startOf('day').toSQL()
  205. const todayEnd = DateTime.now().endOf('day').toSQL()
  206. // 获取设备数据
  207. const deviceData = await deviceQuery.where('createdAt', '>=', today).select('scanned')
  208. // 获取OcrRecord数据
  209. const recordCount = await Database.from('ocr_records')
  210. .where('created_at', '>=', today)
  211. .where('created_at', '<=', todayEnd)
  212. .count('* as total')
  213. // 计算今日统计数据
  214. const scanned = deviceData.reduce((acc, item) => acc + item.scanned, 0)
  215. const total = Number(recordCount[0].total) || 0
  216. const deviceCount = deviceData.length
  217. return response.ok({
  218. date: DateTime.now().toFormat('yyyy-MM-dd'),
  219. total,
  220. scanned,
  221. deviceCount
  222. })
  223. } catch (error) {
  224. return response.internalServerError({
  225. message: '获取今日统计数据时发生错误',
  226. error: error.message
  227. })
  228. }
  229. }
  230. }