routes_messages.ts 6.7 KB

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