post.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
  2. import { FileService } from '../../../modules/files/file.service';
  3. import { ErrorSchema } from '../../../utils/errorHandler';
  4. import { AppDataSource } from '../../../data-source';
  5. import { AuthContext } from '../../../types/context';
  6. import { authMiddleware } from '../../../middleware/auth.middleware';
  7. // 创建分片上传策略请求Schema
  8. const CreateMultipartUploadPolicyDto = z.object({
  9. fileKey: z.string().openapi({
  10. description: '文件键名',
  11. example: 'documents/report.pdf'
  12. }),
  13. totalSize: z.coerce.number().int().positive().openapi({
  14. description: '文件总大小(字节)',
  15. example: 10485760
  16. }),
  17. partSize: z.coerce.number().int().positive().openapi({
  18. description: '分片大小(字节)',
  19. example: 5242880
  20. }),
  21. type: z.string().max(50).nullable().optional().openapi({
  22. description: '文件类型',
  23. example: 'application/pdf'
  24. }),
  25. name: z.string().max(255).openapi({
  26. description: '文件名称',
  27. example: '项目计划书.pdf'
  28. })
  29. });
  30. // 创建分片上传策略路由定义
  31. const createMultipartUploadPolicyRoute = createRoute({
  32. method: 'post',
  33. path: '/',
  34. middleware: [authMiddleware],
  35. request: {
  36. body: {
  37. content: {
  38. 'application/json': { schema: CreateMultipartUploadPolicyDto }
  39. }
  40. }
  41. },
  42. responses: {
  43. 200: {
  44. description: '生成分片上传策略成功',
  45. content: {
  46. 'application/json': {
  47. schema: z.object({
  48. uploadId: z.string().openapi({
  49. description: '分片上传ID',
  50. example: '123e4567-e89b-12d3-a456-426614174000'
  51. }),
  52. bucket: z.string().openapi({
  53. description: '存储桶名称',
  54. example: 'my-bucket'
  55. }),
  56. key: z.string().openapi({
  57. description: '文件键名',
  58. example: 'documents/report.pdf'
  59. }),
  60. host: z.string().openapi({
  61. description: 'MinIO主机地址',
  62. example: 'minio.example.com'
  63. }),
  64. partUrls: z.array(z.string()).openapi({
  65. description: '分片上传URL列表',
  66. example: [
  67. 'https://minio.example.com/my-bucket/documents/report.pdf?uploadId=123e4567-e89b-12d3-a456-426614174000&partNumber=1',
  68. 'https://minio.example.com/my-bucket/documents/report.pdf?uploadId=123e4567-e89b-12d3-a456-426614174000&partNumber=2'
  69. ]
  70. })
  71. })
  72. }
  73. }
  74. },
  75. 400: {
  76. description: '请求参数错误',
  77. content: { 'application/json': { schema: ErrorSchema } }
  78. },
  79. 500: {
  80. description: '服务器错误',
  81. content: { 'application/json': { schema: ErrorSchema } }
  82. }
  83. }
  84. });
  85. // 创建路由实例
  86. const app = new OpenAPIHono<AuthContext>().openapi(createMultipartUploadPolicyRoute, async (c) => {
  87. try {
  88. const data = await c.req.json();
  89. const user = c.get('user');
  90. // 计算分片数量
  91. const partCount = Math.ceil(data.totalSize / data.partSize);
  92. // 创建文件服务实例
  93. const fileService = new FileService(AppDataSource);
  94. const result = await fileService.createMultipartUploadPolicy({
  95. ...data,
  96. uploadUserId: user.id
  97. }, partCount);
  98. return c.json({
  99. uploadId: result.uploadId,
  100. bucket: result.bucket,
  101. key: result.key,
  102. host: `${process.env.MINIO_USE_SSL ? 'https' : 'http'}://${process.env.MINIO_ENDPOINT}:${process.env.MINIO_PORT}`,
  103. partUrls: result.uploadUrls
  104. }, 200);
  105. } catch (error) {
  106. const message = error instanceof Error ? error.message : '生成分片上传策略失败';
  107. return c.json({ code: 500, message }, 500);
  108. }
  109. });
  110. export default app;