routes_xunlian_codes.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import { Hono } from 'hono'
  2. import type { Variables, WithAuth } from "./middlewares.ts";
  3. export function createXunlianCodesRoutes(withAuth: WithAuth) {
  4. const xunlianCodesRoutes = new Hono<{ Variables: Variables }>()
  5. // 获取训练码列表
  6. xunlianCodesRoutes.get('/', withAuth, async (c) => {
  7. try {
  8. const apiClient = c.get('apiClient')
  9. const page = Number(c.req.query('page')) || 1
  10. const pageSize = Number(c.req.query('pageSize')) || 10
  11. const offset = (page - 1) * pageSize
  12. const search = c.req.query('search') || ''
  13. let query = apiClient.database.table('xunlian_codes')
  14. .orderBy('id', 'desc')
  15. if (search) {
  16. query = query.where('code', 'like', `%${search}%`)
  17. }
  18. const total = await query.clone().count()
  19. const codes = await query.select('id', 'code', 'status', 'created_at', 'updated_at')
  20. .limit(pageSize).offset(offset)
  21. return c.json({
  22. data: codes,
  23. pagination: {
  24. total: Number(total),
  25. current: page,
  26. pageSize
  27. }
  28. })
  29. } catch (error) {
  30. console.error('获取训练码列表失败:', error)
  31. return c.json({ error: '获取训练码列表失败' }, 500)
  32. }
  33. })
  34. // 获取单个训练码详情
  35. xunlianCodesRoutes.get('/:id', withAuth, async (c) => {
  36. try {
  37. const id = Number(c.req.param('id'))
  38. if (!id || isNaN(id)) {
  39. return c.json({ error: '无效的训练码ID' }, 400)
  40. }
  41. const apiClient = c.get('apiClient')
  42. const code = await apiClient.database.table('xunlian_codes')
  43. .where('id', id)
  44. .select('id', 'code', 'status', 'created_at', 'updated_at')
  45. .first()
  46. if (!code) {
  47. return c.json({ error: '训练码不存在' }, 404)
  48. }
  49. return c.json({
  50. data: code,
  51. message: '获取训练码详情成功'
  52. })
  53. } catch (error) {
  54. console.error('获取训练码详情失败:', error)
  55. return c.json({ error: '获取训练码详情失败' }, 500)
  56. }
  57. })
  58. // 创建训练码
  59. xunlianCodesRoutes.post('/', withAuth, async (c) => {
  60. try {
  61. const apiClient = c.get('apiClient')
  62. const body = await c.req.json()
  63. // 验证必填字段
  64. const { code } = body
  65. if (!code) {
  66. return c.json({ error: '缺少训练码' }, 400)
  67. }
  68. // 检查训练码是否已存在
  69. const existingCode = await apiClient.database.table('xunlian_codes')
  70. .where('code', code)
  71. .first()
  72. if (existingCode) {
  73. return c.json({ error: '训练码已存在' }, 400)
  74. }
  75. // 创建训练码
  76. const [id] = await apiClient.database.table('xunlian_codes').insert({
  77. code,
  78. status: 'active', // 默认激活状态
  79. created_at: new Date(),
  80. updated_at: new Date()
  81. })
  82. const newCode = await apiClient.database.table('xunlian_codes')
  83. .where('id', id)
  84. .select('id', 'code', 'status', 'created_at')
  85. .first()
  86. return c.json({
  87. data: newCode,
  88. message: '创建训练码成功'
  89. })
  90. } catch (error) {
  91. console.error('创建训练码失败:', error)
  92. return c.json({ error: '创建训练码失败' }, 500)
  93. }
  94. })
  95. // 更新训练码
  96. xunlianCodesRoutes.put('/:id', withAuth, async (c) => {
  97. try {
  98. const id = Number(c.req.param('id'))
  99. if (!id || isNaN(id)) {
  100. return c.json({ error: '无效的训练码ID' }, 400)
  101. }
  102. const apiClient = c.get('apiClient')
  103. const body = await c.req.json()
  104. // 验证必填字段
  105. const { code } = body
  106. if (!code) {
  107. return c.json({ error: '缺少训练码' }, 400)
  108. }
  109. // 检查训练码是否存在
  110. const existingCode = await apiClient.database.table('xunlian_codes')
  111. .where('id', id)
  112. .first()
  113. if (!existingCode) {
  114. return c.json({ error: '训练码不存在' }, 404)
  115. }
  116. // 如果修改了训练码,检查新训练码是否已被使用
  117. if (code !== existingCode.code) {
  118. const codeWithSameName = await apiClient.database.table('xunlian_codes')
  119. .where('code', code)
  120. .whereNot('id', id.toString())
  121. .first()
  122. if (codeWithSameName) {
  123. return c.json({ error: '训练码已存在' }, 400)
  124. }
  125. }
  126. // 更新训练码信息
  127. const updateData = {
  128. code,
  129. updated_at: new Date()
  130. }
  131. await apiClient.database.table('xunlian_codes')
  132. .where('id', id)
  133. .update(updateData)
  134. const updatedCode = await apiClient.database.table('xunlian_codes')
  135. .where('id', id)
  136. .select('id', 'code', 'status', 'created_at')
  137. .first()
  138. return c.json({
  139. data: updatedCode,
  140. message: '更新训练码成功'
  141. })
  142. } catch (error) {
  143. console.error('更新训练码失败:', error)
  144. return c.json({ error: '更新训练码失败' }, 500)
  145. }
  146. })
  147. // 删除训练码
  148. xunlianCodesRoutes.delete('/:id', withAuth, async (c) => {
  149. try {
  150. const id = Number(c.req.param('id'))
  151. if (!id || isNaN(id)) {
  152. return c.json({ error: '无效的训练码ID' }, 400)
  153. }
  154. const apiClient = c.get('apiClient')
  155. // 检查训练码是否存在
  156. const existingCode = await apiClient.database.table('xunlian_codes')
  157. .where('id', id)
  158. .first()
  159. if (!existingCode) {
  160. return c.json({ error: '训练码不存在' }, 404)
  161. }
  162. // 删除训练码
  163. await apiClient.database.table('xunlian_codes')
  164. .where('id', id)
  165. .delete()
  166. return c.json({
  167. message: '删除训练码成功',
  168. id
  169. })
  170. } catch (error) {
  171. console.error('删除训练码失败:', error)
  172. return c.json({ error: '删除训练码失败' }, 500)
  173. }
  174. })
  175. // 批量生成训练码
  176. xunlianCodesRoutes.post('/batch-generate', withAuth, async (c) => {
  177. try {
  178. const apiClient = c.get('apiClient')
  179. const body = await c.req.json()
  180. const { count, prefix } = body
  181. if (!count || count <= 0) {
  182. return c.json({ error: '无效的生成数量' }, 400)
  183. }
  184. const codes = []
  185. const now = new Date()
  186. for (let i = 0; i < count; i++) {
  187. const code = prefix ? `${prefix}-${generateRandomCode(8)}` : generateRandomCode(10)
  188. codes.push({
  189. code,
  190. status: 'active',
  191. created_at: now,
  192. updated_at: now
  193. })
  194. }
  195. // 批量插入
  196. await apiClient.database.table('xunlian_codes').insert(codes)
  197. return c.json({
  198. message: `成功生成${count}个训练码`,
  199. count
  200. })
  201. } catch (error) {
  202. console.error('批量生成训练码失败:', error)
  203. return c.json({ error: '批量生成训练码失败' }, 500)
  204. }
  205. })
  206. // 更新训练码状态
  207. xunlianCodesRoutes.put('/:id/status', withAuth, async (c) => {
  208. try {
  209. const id = Number(c.req.param('id'))
  210. if (!id || isNaN(id)) {
  211. return c.json({ error: '无效的训练码ID' }, 400)
  212. }
  213. const apiClient = c.get('apiClient')
  214. const body = await c.req.json()
  215. const { status } = body
  216. if (!status || !['active', 'inactive', 'used'].includes(status)) {
  217. return c.json({ error: '无效的状态值' }, 400)
  218. }
  219. // 检查训练码是否存在
  220. const existingCode = await apiClient.database.table('xunlian_codes')
  221. .where('id', id)
  222. .first()
  223. if (!existingCode) {
  224. return c.json({ error: '训练码不存在' }, 404)
  225. }
  226. // 更新状态
  227. await apiClient.database.table('xunlian_codes')
  228. .where('id', id)
  229. .update({
  230. status,
  231. updated_at: new Date()
  232. })
  233. return c.json({
  234. message: '更新训练码状态成功',
  235. id,
  236. status
  237. })
  238. } catch (error) {
  239. console.error('更新训练码状态失败:', error)
  240. return c.json({ error: '更新训练码状态失败' }, 500)
  241. }
  242. })
  243. return xunlianCodesRoutes
  244. }
  245. // 生成随机训练码
  246. function generateRandomCode(length: number) {
  247. const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  248. let result = ''
  249. for (let i = 0; i < length; i++) {
  250. result += chars.charAt(Math.floor(Math.random() * chars.length))
  251. }
  252. return result
  253. }