db.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import pg from 'pg'
  2. const { Pool } = pg
  3. export const pool = new Pool({
  4. connectionString: process.env.DATABASE_URL || 'postgresql://xinghen:xinghen@localhost:5432/xinghen'
  5. })
  6. export const mapUser = (r: any) => ({
  7. id: r.id,
  8. phone: r.phone,
  9. role: r.role || 'USER',
  10. organization: '',
  11. wechat: r.wechat || '',
  12. contactName: r.contact_name || '',
  13. bio: r.bio || '',
  14. pointsBalance: Number(r.points_balance) || 0,
  15. mustChangePassword: Boolean(r.must_change_password),
  16. createdAt: r.created_at,
  17. updatedAt: r.updated_at
  18. })
  19. export const mapAsset = (r: any) => ({
  20. id: r.id,
  21. courseId: r.course_id,
  22. episodeId: r.episode_id || null,
  23. originalName: r.original_name,
  24. size: Number(r.size),
  25. mimeType: r.mime_type,
  26. url: `/uploads/${r.stored_name}`,
  27. createdAt: r.created_at
  28. })
  29. export const mapInstructor = (r: any) => ({
  30. id: r.id,
  31. name: r.name,
  32. organization: r.organization || '',
  33. introduction: r.introduction || '',
  34. imageUrl: r.image_urls?.[0] || (r.image_stored_name ? `/uploads/${r.image_stored_name}` : null),
  35. imageUrls: r.image_urls?.length ? r.image_urls : (r.image_stored_name ? [`/uploads/${r.image_stored_name}`] : [])
  36. })
  37. export const mapDeliverable = (r: any) => ({
  38. id: r.id,
  39. courseId: r.course_id,
  40. episodeId: r.episode_id || null,
  41. originalName: r.original_name,
  42. size: Number(r.size),
  43. mimeType: r.mime_type,
  44. url: `/uploads/${r.stored_name}`,
  45. createdAt: r.created_at
  46. })
  47. export const mapEpisode = (r: any, assets: any[] = [], deliverables: any[] = []) => ({
  48. id: r.id,
  49. courseId: r.course_id,
  50. episodeNumber: Number(r.episode_number) || 1,
  51. title: r.title,
  52. summary: r.summary || '',
  53. lectureNotes: r.lecture_notes || '',
  54. createdAt: r.created_at,
  55. updatedAt: r.updated_at,
  56. assets: assets.map(mapAsset),
  57. deliverables: deliverables.map(mapDeliverable)
  58. })
  59. export const mapCourse = (
  60. r: any,
  61. assets: any[] = [],
  62. instructors: any[] = [],
  63. deliverables: any[] = [],
  64. creatorUser: any = null,
  65. episodes: any[] = []
  66. ) => {
  67. const mappedAssets = assets.map(mapAsset)
  68. const mappedDeliverables = deliverables.map(mapDeliverable)
  69. // 为每个分集关联专属的 assets 与 deliverables
  70. const mappedEpisodes = episodes.map((epRow) => {
  71. const epAssets = assets.filter((a) => a.episode_id === epRow.id)
  72. const epDeliverables = deliverables.filter((d) => d.episode_id === epRow.id)
  73. return mapEpisode(epRow, epAssets, epDeliverables)
  74. })
  75. return {
  76. id: r.id,
  77. organizationId: r.organization_id || null,
  78. organizationName: r.organization_name || null,
  79. userId: r.user_id,
  80. name: r.name,
  81. category: r.category || '',
  82. description: r.description || '',
  83. status: r.status,
  84. productionNotes: r.production_notes || '',
  85. estimatedMinutes: Number(r.estimated_minutes) || 1,
  86. estimatedPoints: Number(r.estimated_points) || 1000,
  87. actualPoints: r.actual_points == null ? null : Number(r.actual_points),
  88. pointsCharged: Boolean(r.points_charged),
  89. progressEvents: (r.progress_events || []).map((event: any) => ({
  90. id: event.id,
  91. actorType: event.actor_type,
  92. eventType: event.event_type,
  93. title: event.title,
  94. description: event.description || '',
  95. metadata: event.metadata || {},
  96. createdAt: event.created_at
  97. })),
  98. createdAt: r.created_at,
  99. updatedAt: r.updated_at,
  100. submittedAt: r.submitted_at || null,
  101. completedAt: r.completed_at || null,
  102. assets: mappedAssets,
  103. episodes: mappedEpisodes,
  104. instructors: instructors.map(mapInstructor),
  105. digitalInstructorId: r.digital_instructor_id || null,
  106. digitalInstructorSnapshot: r.digital_instructor_snapshot || null,
  107. deliverables: mappedDeliverables,
  108. creator: creatorUser ? mapUser(creatorUser) : (r.user_phone ? {
  109. id: r.user_id,
  110. phone: r.user_phone,
  111. role: r.user_role || 'USER',
  112. organization: '',
  113. wechat: r.user_wechat || '',
  114. contactName: r.user_contact_name || '',
  115. bio: r.user_bio || '',
  116. createdAt: r.user_created_at
  117. } : undefined)
  118. }
  119. }