routes_messages.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import { Hono } from 'hono'
  2. import type { Variables, WithAuth } from "./middlewares.ts";
  3. import { MessageType, MessageStatus } from '../client/share/types.ts'
  4. export function createMessagesRoutes(withAuth: WithAuth) {
  5. const messagesRoutes = new Hono<{ Variables: Variables }>()
  6. // 发送消息
  7. messagesRoutes.post('/', withAuth, async (c) => {
  8. try {
  9. const apiClient = c.get('apiClient')
  10. const { title, content, type, receiver_ids } = await c.req.json()
  11. if (!title || !content || !type || !receiver_ids?.length) {
  12. return c.json({ error: '缺少必要参数' }, 400)
  13. }
  14. // 创建消息
  15. const user = c.get('user')
  16. if (!user) return c.json({ error: '未授权访问' }, 401)
  17. const [messageId] = await apiClient.database.table('messages').insert({
  18. title,
  19. content,
  20. type,
  21. sender_id: user.id,
  22. sender_name: user.username,
  23. created_at: apiClient.database.fn.now(),
  24. updated_at: apiClient.database.fn.now()
  25. })
  26. // 关联用户消息
  27. const userMessages = receiver_ids.map((userId: number) => ({
  28. user_id: userId,
  29. message_id: messageId,
  30. status: MessageStatus.UNREAD,
  31. created_at: apiClient.database.fn.now(),
  32. updated_at: apiClient.database.fn.now()
  33. }))
  34. await apiClient.database.table('user_messages').insert(userMessages)
  35. return c.json({
  36. message: '消息发送成功',
  37. data: { id: messageId }
  38. }, 201)
  39. } catch (error) {
  40. console.error('发送消息失败:', error)
  41. return c.json({ error: '发送消息失败' }, 500)
  42. }
  43. })
  44. // 获取用户消息列表
  45. messagesRoutes.get('/', withAuth, async (c) => {
  46. try {
  47. const apiClient = c.get('apiClient')
  48. const page = Number(c.req.query('page')) || 1
  49. const pageSize = Number(c.req.query('pageSize')) || 20
  50. const type = c.req.query('type')
  51. const status = c.req.query('status')
  52. const user = c.get('user')
  53. if (!user) return c.json({ error: '未授权访问' }, 401)
  54. const query = apiClient.database.table('user_messages as um')
  55. .select('m.*', 'um.status as user_status', 'um.read_at', 'um.id as user_message_id')
  56. .leftJoin('messages as m', 'um.message_id', 'm.id')
  57. .where('um.user_id', user.id)
  58. .where('um.is_deleted', 0)
  59. .orderBy('m.created_at', 'desc')
  60. .limit(pageSize)
  61. .offset((page - 1) * pageSize)
  62. if (type) query.where('m.type', type)
  63. if (status) query.where('um.status', status)
  64. const countQuery = query.clone()
  65. const messages = await query
  66. // 获取总数用于分页
  67. const total = await countQuery.count()
  68. const totalCount = Number(total)
  69. const totalPages = Math.ceil(totalCount / pageSize)
  70. return c.json({
  71. data: messages,
  72. pagination: {
  73. total: totalCount,
  74. current: page,
  75. pageSize,
  76. totalPages
  77. }
  78. })
  79. } catch (error) {
  80. console.error('获取消息列表失败:', error)
  81. return c.json({ error: '获取消息列表失败' }, 500)
  82. }
  83. })
  84. // 获取消息详情
  85. messagesRoutes.get('/:id', withAuth, async (c) => {
  86. try {
  87. const apiClient = c.get('apiClient')
  88. const messageId = c.req.param('id')
  89. const user = c.get('user')
  90. if (!user) return c.json({ error: '未授权访问' }, 401)
  91. const message = await apiClient.database.table('user_messages as um')
  92. .select('m.*', 'um.status as user_status', 'um.read_at')
  93. .leftJoin('messages as m', 'um.message_id', 'm.id')
  94. .where('um.user_id', user.id)
  95. .where('um.message_id', messageId)
  96. .first()
  97. if (!message) {
  98. return c.json({ error: '消息不存在或无权访问' }, 404)
  99. }
  100. // 标记为已读
  101. if (message.user_status === MessageStatus.UNREAD) {
  102. const user = c.get('user')
  103. if (!user) return c.json({ error: '未授权访问' }, 401)
  104. await apiClient.database.table('user_messages')
  105. .where('user_id', user.id)
  106. .where('message_id', messageId)
  107. .update({
  108. status: MessageStatus.READ,
  109. read_at: apiClient.database.fn.now(),
  110. updated_at: apiClient.database.fn.now()
  111. })
  112. }
  113. return c.json({
  114. message: '获取消息成功',
  115. data: message
  116. })
  117. } catch (error) {
  118. console.error('获取消息详情失败:', error)
  119. return c.json({ error: '获取消息详情失败' }, 500)
  120. }
  121. })
  122. // 删除消息(软删除)
  123. messagesRoutes.delete('/:id', withAuth, async (c) => {
  124. try {
  125. const apiClient = c.get('apiClient')
  126. const user = c.get('user')
  127. if (!user) return c.json({ error: '未授权访问' }, 401)
  128. const messageId = c.req.param('id')
  129. await apiClient.database.table('user_messages')
  130. .where('user_id', user.id)
  131. .where('message_id', messageId)
  132. .update({
  133. is_deleted: 1,
  134. updated_at: apiClient.database.fn.now()
  135. })
  136. return c.json({ message: '消息已删除' })
  137. } catch (error) {
  138. console.error('删除消息失败:', error)
  139. return c.json({ error: '删除消息失败' }, 500)
  140. }
  141. })
  142. // 获取未读消息数量
  143. messagesRoutes.get('/count/unread', withAuth, async (c) => {
  144. try {
  145. const apiClient = c.get('apiClient')
  146. const user = c.get('user')
  147. if (!user) return c.json({ error: '未授权访问' }, 401)
  148. const count = await apiClient.database.table('user_messages')
  149. .where('user_id', user.id)
  150. .where('status', MessageStatus.UNREAD)
  151. .where('is_deleted', 0)
  152. .count()
  153. return c.json({ count: Number(count) })
  154. } catch (error) {
  155. console.error('获取未读消息数失败:', error)
  156. return c.json({ error: '获取未读消息数失败' }, 500)
  157. }
  158. })
  159. // 标记消息为已读
  160. messagesRoutes.post('/:id/read', withAuth, async (c) => {
  161. try {
  162. const apiClient = c.get('apiClient')
  163. const user = c.get('user')
  164. if (!user) return c.json({ error: '未授权访问' }, 401)
  165. const messageId = c.req.param('id')
  166. await apiClient.database.table('user_messages')
  167. .where('user_id', user.id)
  168. .where('message_id', messageId)
  169. .update({
  170. status: MessageStatus.READ,
  171. read_at: apiClient.database.fn.now(),
  172. updated_at: apiClient.database.fn.now()
  173. })
  174. return c.json({ message: '消息已标记为已读' })
  175. } catch (error) {
  176. console.error('标记消息为已读失败:', error)
  177. return c.json({ error: '标记消息为已读失败' }, 500)
  178. }
  179. })
  180. return messagesRoutes
  181. }