db.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. note: r.note || '',
  35. imageUrl: r.image_urls?.[0] || (r.image_stored_name ? `/uploads/${r.image_stored_name}` : null),
  36. imageUrls: r.image_urls?.length ? r.image_urls : (r.image_stored_name ? [`/uploads/${r.image_stored_name}`] : []),
  37. audioUrls: r.audio_urls?.length ? r.audio_urls : (r.audio?.length ? r.audio.map((a: any) => a.url) : [])
  38. })
  39. export const mapDeliverable = (r: any) => ({
  40. id: r.id,
  41. courseId: r.course_id,
  42. episodeId: r.episode_id || null,
  43. originalName: r.original_name,
  44. size: Number(r.size),
  45. mimeType: r.mime_type,
  46. url: `/uploads/${r.stored_name}`,
  47. createdAt: r.created_at
  48. })
  49. export const mapEpisode = (r: any, assets: any[] = [], deliverables: any[] = []) => ({
  50. id: r.id,
  51. courseId: r.course_id,
  52. episodeNumber: Number(r.episode_number) || 1,
  53. title: r.title,
  54. summary: r.summary || '',
  55. lectureNotes: r.lecture_notes || '',
  56. createdAt: r.created_at,
  57. updatedAt: r.updated_at,
  58. assets: assets.map(mapAsset),
  59. deliverables: deliverables.map(mapDeliverable)
  60. })
  61. export const mapCourse = (
  62. r: any,
  63. assets: any[] = [],
  64. instructors: any[] = [],
  65. deliverables: any[] = [],
  66. creatorUser: any = null,
  67. episodes: any[] = []
  68. ) => {
  69. const mappedAssets = assets.map(mapAsset)
  70. const mappedDeliverables = deliverables.map(mapDeliverable)
  71. // 为每个分集关联专属的 assets 与 deliverables
  72. const mappedEpisodes = episodes.map((epRow) => {
  73. const epAssets = assets.filter((a) => a.episode_id === epRow.id)
  74. const epDeliverables = deliverables.filter((d) => d.episode_id === epRow.id)
  75. return mapEpisode(epRow, epAssets, epDeliverables)
  76. })
  77. return {
  78. id: r.id,
  79. organizationId: r.organization_id || null,
  80. organizationName: r.organization_name || null,
  81. userId: r.user_id,
  82. name: r.name,
  83. description: r.description || '',
  84. status: r.status,
  85. productionNotes: r.production_notes || '',
  86. estimatedMinutes: Number(r.estimated_minutes) || 1,
  87. estimatedPoints: Number(r.estimated_points) || 1000,
  88. actualPoints: r.actual_points == null ? null : Number(r.actual_points),
  89. pointsCharged: Boolean(r.points_charged),
  90. progressEvents: (r.progress_events || []).map((event: any) => ({
  91. id: event.id,
  92. actorType: event.actor_type,
  93. eventType: event.event_type,
  94. title: event.title,
  95. description: event.description || '',
  96. metadata: event.metadata || {},
  97. createdAt: event.created_at
  98. })),
  99. createdAt: r.created_at,
  100. updatedAt: r.updated_at,
  101. submittedAt: r.submitted_at || null,
  102. completedAt: r.completed_at || null,
  103. assets: mappedAssets,
  104. episodes: mappedEpisodes,
  105. instructors: instructors.map(mapInstructor),
  106. digitalInstructorId: r.digital_instructor_id || null,
  107. digitalInstructorSnapshot: r.digital_instructor_snapshot || null,
  108. deliverables: mappedDeliverables,
  109. creator: creatorUser ? mapUser(creatorUser) : (r.user_phone ? {
  110. id: r.user_id,
  111. phone: r.user_phone,
  112. role: r.user_role || 'USER',
  113. organization: '',
  114. wechat: r.user_wechat || '',
  115. contactName: r.user_contact_name || '',
  116. bio: r.user_bio || '',
  117. createdAt: r.user_created_at
  118. } : undefined)
  119. }
  120. }