schema.prisma 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. generator client {
  2. provider = "prisma-client-js"
  3. }
  4. datasource db {
  5. provider = "mysql"
  6. url = env("DATABASE_URL")
  7. }
  8. model User {
  9. id Int @id @default(autoincrement())
  10. phone String? @unique
  11. openid String? @unique
  12. nickname String @default("用户")
  13. avatar String @default("")
  14. memberLevel Int @default(0)
  15. memberExpireAt DateTime?
  16. dailyUsage Int @default(0)
  17. lastUsageDate String @default("")
  18. createdAt DateTime @default(now())
  19. updatedAt DateTime @updatedAt
  20. usedAudioMinutes Int @default(0)
  21. costLimit Float @default(0)
  22. quotaReserved Float @default(0)
  23. subscriptionResetDate DateTime?
  24. comments Comment[]
  25. drafts Draft[]
  26. favorites Favorite[]
  27. notifications Notification[]
  28. orders Order[]
  29. playRecords PlayRecord[]
  30. playlists Playlist[]
  31. signRecords SignRecord[]
  32. subscriptions Subscription[]
  33. tokenBalance TokenBalance?
  34. tokenUsages TokenUsage[]
  35. preferences UserPreference?
  36. shareRecords ShareRecord[]
  37. invitesSent InviteRecord[] @relation("InviterRelation")
  38. invitesReceived InviteRecord[] @relation("InviteeRelation")
  39. @@index([phone])
  40. @@index([openid])
  41. }
  42. model Order {
  43. id Int @id @default(autoincrement())
  44. userId Int
  45. orderNo String @unique
  46. planId Int?
  47. productType String
  48. amount Decimal @db.Decimal(10, 2)
  49. status String @default("pending")
  50. paymentMethod String?
  51. paymentId String?
  52. paidAt DateTime?
  53. createdAt DateTime @default(now())
  54. updatedAt DateTime @updatedAt
  55. plan SubscriptionPlan? @relation(fields: [planId], references: [id])
  56. user User @relation(fields: [userId], references: [id])
  57. tokenUsages TokenUsage[]
  58. @@index([userId, createdAt])
  59. @@index([orderNo])
  60. @@index([status])
  61. @@index([planId], map: "Order_planId_fkey")
  62. }
  63. model PlayRecord {
  64. id Int @id @default(autoincrement())
  65. userId Int
  66. chapterId Int
  67. progress Float @default(0)
  68. duration Float @default(0)
  69. updatedAt DateTime @updatedAt
  70. createdAt DateTime @default(now())
  71. chapter BookChapter @relation(fields: [chapterId], references: [id])
  72. user User @relation(fields: [userId], references: [id])
  73. @@unique([userId, chapterId])
  74. @@index([userId])
  75. @@index([chapterId])
  76. }
  77. model UserPreference {
  78. id Int @id @default(autoincrement())
  79. userId Int @unique
  80. playSpeed Float @default(1)
  81. quality String @default("standard")
  82. theme String @default("light")
  83. defaultVoiceId String? @default("cherry")
  84. defaultVolume Int @default(50)
  85. autoPlayNext Boolean @default(true)
  86. wifiOnlyDownload Boolean @default(false)
  87. updatedAt DateTime @updatedAt
  88. createdAt DateTime @default(now())
  89. user User @relation(fields: [userId], references: [id])
  90. }
  91. model Favorite {
  92. id Int @id @default(autoincrement())
  93. userId Int
  94. bookId Int
  95. createdAt DateTime @default(now())
  96. book Book @relation(fields: [bookId], references: [id], onDelete: Cascade)
  97. user User @relation(fields: [userId], references: [id])
  98. @@unique([userId, bookId])
  99. @@index([userId])
  100. @@index([bookId])
  101. }
  102. model Comment {
  103. id Int @id @default(autoincrement())
  104. userId Int
  105. chapterId Int
  106. content String @db.Text
  107. rating Int
  108. createdAt DateTime @default(now())
  109. chapter BookChapter @relation(fields: [chapterId], references: [id])
  110. user User @relation(fields: [userId], references: [id])
  111. @@index([chapterId])
  112. @@index([userId])
  113. }
  114. model Notification {
  115. id String @id @default(uuid())
  116. userId Int
  117. title String
  118. content String @db.Text
  119. isRead Boolean @default(false)
  120. createdAt DateTime @default(now())
  121. user User @relation(fields: [userId], references: [id])
  122. @@index([userId])
  123. }
  124. model Book {
  125. id Int @id @default(autoincrement())
  126. userId Int?
  127. title String
  128. subtitle String?
  129. description String @db.Text
  130. coverUrl String?
  131. targetAudience String @default("通用")
  132. style String @default("专业严谨")
  133. bookScale String @default("1000")
  134. totalChapters Int @default(10)
  135. estimatedWords Int @default(0)
  136. progress Int @default(0)
  137. isPublished Boolean @default(false)
  138. outlineJson String? @db.LongText
  139. foreword String? @db.Text
  140. afterword String? @db.Text
  141. errorMsg String? @db.Text
  142. createdAt DateTime @default(now())
  143. updatedAt DateTime @updatedAt
  144. failedStage String? @db.VarChar(30)
  145. genStage String @default("draft")
  146. bookAnalysis String? @db.Text
  147. chapters BookChapter[]
  148. favorites Favorite[]
  149. videoProjects VideoProject[]
  150. @@index([userId])
  151. @@index([createdAt])
  152. }
  153. model BookChapter {
  154. id Int @id @default(autoincrement())
  155. bookId Int
  156. parentId Int @default(0)
  157. level Int @default(1)
  158. number Int
  159. title String
  160. summary String? @db.Text
  161. keyPoints String? @db.Text
  162. estimatedWords Int @default(1000)
  163. content String? @db.LongText
  164. wordCount Int @default(0)
  165. contentError String? @db.Text
  166. generatedAt DateTime?
  167. audioUrl String? @db.Text
  168. audioDuration Int @default(0)
  169. videoUrl String? @db.Text
  170. videoDuration Int?
  171. isPublic Boolean @default(false)
  172. genStage String @default("idle")
  173. lrcLyrics String? @db.Text
  174. contentCheck String? @db.Text
  175. book Book @relation(fields: [bookId], references: [id], onDelete: Cascade)
  176. comments Comment[]
  177. playRecords PlayRecord[]
  178. playlistItems PlaylistItem[]
  179. ttsTasks TtsTask[]
  180. videoProjects VideoProject[]
  181. @@unique([bookId, parentId, level, number])
  182. @@index([bookId])
  183. @@index([bookId, parentId])
  184. @@index([bookId, level])
  185. }
  186. model VideoProject {
  187. id Int @id @default(autoincrement())
  188. userId Int?
  189. title String
  190. description String?
  191. coverUrl String?
  192. configJson String? @db.LongText
  193. outputUrl String?
  194. duration Int?
  195. fileSize Int?
  196. bookId Int?
  197. chapterId Int?
  198. status String @default("draft")
  199. progress Int @default(0)
  200. errorMsg String? @db.Text
  201. createdAt DateTime @default(now())
  202. updatedAt DateTime @updatedAt
  203. book Book? @relation(fields: [bookId], references: [id])
  204. chapter BookChapter? @relation(fields: [chapterId], references: [id])
  205. @@index([userId, status])
  206. @@index([createdAt])
  207. @@index([bookId], map: "VideoProject_bookId_fkey")
  208. @@index([chapterId], map: "VideoProject_chapterId_fkey")
  209. }
  210. model SearchHistory {
  211. id Int @id @default(autoincrement())
  212. userId Int
  213. keyword String
  214. createdAt DateTime @default(now())
  215. @@index([userId, createdAt])
  216. @@index([userId])
  217. }
  218. model HotSearch {
  219. id Int @id @default(autoincrement())
  220. keyword String
  221. count Int @default(0)
  222. sort Int @default(0)
  223. createdAt DateTime @default(now())
  224. updatedAt DateTime @updatedAt
  225. @@index([sort])
  226. @@index([count])
  227. }
  228. model SignRecord {
  229. id Int @id @default(autoincrement())
  230. userId Int
  231. createdAt DateTime @default(now())
  232. user User @relation(fields: [userId], references: [id])
  233. @@unique([userId, createdAt])
  234. @@index([userId, createdAt])
  235. }
  236. model SubscriptionPlan {
  237. id Int @id @default(autoincrement())
  238. name String
  239. level Int @default(0)
  240. priceMonthly Decimal @default(0.00) @db.Decimal(10, 2)
  241. priceYearly Decimal @default(0.00) @db.Decimal(10, 2)
  242. description String? @db.Text
  243. features String? @db.Text
  244. isRecommended Boolean @default(false)
  245. isActive Boolean @default(true)
  246. sortOrder Int @default(0)
  247. dailyGenerations Int @default(3)
  248. perGenerationLimit Int @default(2000)
  249. monthlyTokens Int @default(10000)
  250. monthlyMinutes Int @default(30)
  251. yearlyTokens Int?
  252. voiceOptions Int @default(5)
  253. audioQuality String @default("standard")
  254. apiAccess Boolean @default(false)
  255. batchProcessing Boolean @default(false)
  256. teamManagement Boolean @default(false)
  257. overageEnabled Boolean @default(false)
  258. overagePrice Decimal @default(0.000) @db.Decimal(10, 3)
  259. createdAt DateTime @default(now())
  260. updatedAt DateTime @updatedAt
  261. orders Order[]
  262. subscriptions Subscription[]
  263. @@index([level])
  264. @@index([isActive, sortOrder])
  265. }
  266. model Subscription {
  267. id Int @id @default(autoincrement())
  268. userId Int
  269. planId Int
  270. startDate DateTime
  271. endDate DateTime
  272. status String @default("active")
  273. autoRenew Boolean @default(false)
  274. createdAt DateTime @default(now())
  275. updatedAt DateTime @updatedAt
  276. plan SubscriptionPlan @relation(fields: [planId], references: [id])
  277. user User @relation(fields: [userId], references: [id])
  278. @@index([userId, status])
  279. @@index([userId, endDate])
  280. @@index([planId], map: "Subscription_planId_fkey")
  281. }
  282. model TokenUsage {
  283. id Int @id @default(autoincrement())
  284. userId Int
  285. type String
  286. amount Int @default(0)
  287. contentLength Int @default(0)
  288. orderId Int?
  289. description String? @db.Text
  290. createdAt DateTime @default(now())
  291. order Order? @relation(fields: [orderId], references: [id])
  292. user User @relation(fields: [userId], references: [id])
  293. @@index([userId, createdAt])
  294. @@index([userId, type])
  295. @@index([orderId], map: "TokenUsage_orderId_fkey")
  296. }
  297. model TokenBalance {
  298. id Int @id @default(autoincrement())
  299. userId Int @unique
  300. totalTokens Int @default(0)
  301. usedTokens Int @default(0) // 总消耗
  302. packTokens Int @default(0) // 积分包购买的Token总数
  303. usedPackTokens Int @default(0) // 积分包已消耗的Token数
  304. resetDate DateTime?
  305. createdAt DateTime @default(now())
  306. updatedAt DateTime @updatedAt
  307. user User @relation(fields: [userId], references: [id])
  308. @@index([userId])
  309. }
  310. model VideoMaterial {
  311. id Int @id @default(autoincrement())
  312. userId Int?
  313. type String
  314. name String
  315. url String @db.Text
  316. thumbnail String?
  317. tags String? @db.Text
  318. category String?
  319. duration Int?
  320. size Int?
  321. width Int?
  322. height Int?
  323. createdAt DateTime @default(now())
  324. updatedAt DateTime @updatedAt
  325. @@index([userId, type])
  326. @@index([type, category])
  327. }
  328. model AudioRecord {
  329. id Int @id @default(autoincrement())
  330. userId Int?
  331. audioId String @unique
  332. title String @default("未命名音频")
  333. text String? @db.LongText
  334. wordCount Int @default(0)
  335. voiceId String @default("cherry")
  336. voiceParams String?
  337. audioUrl String? @db.Text
  338. audioDuration Int @default(0)
  339. audioSize Int @default(0)
  340. status String @default("processing")
  341. errorMsg String? @db.Text
  342. createdAt DateTime @default(now())
  343. updatedAt DateTime @updatedAt
  344. bookId Int?
  345. provider String? // TTS 供应商: bailian / edge / mock
  346. @@index([userId])
  347. @@index([audioId])
  348. @@index([bookId])
  349. }
  350. model TtsTask {
  351. id Int @id @default(autoincrement())
  352. taskType String @default("tts") @db.VarChar(20) // "tts" | "content"
  353. chapterId Int
  354. bookId Int?
  355. userId Int?
  356. contentHash String @db.VarChar(64)
  357. content String? @db.LongText
  358. status String @default("pending")
  359. audioUrl String? @db.Text
  360. audioDuration Int @default(0)
  361. errorMsg String? @db.Text
  362. retryCount Int @default(0)
  363. maxRetries Int @default(3)
  364. voiceId String @default("default")
  365. startedAt DateTime?
  366. completedAt DateTime?
  367. createdAt DateTime @default(now())
  368. updatedAt DateTime @updatedAt
  369. chapter BookChapter @relation(fields: [chapterId], references: [id], onDelete: Cascade)
  370. @@index([taskType, status, createdAt])
  371. @@index([chapterId, contentHash])
  372. @@index([contentHash, chapterId])
  373. }
  374. model AiCallLog {
  375. id Int @id @default(autoincrement())
  376. callType String @db.VarChar(20) // llm_chat | llm_tools | tts_synthesize | tts_create | tts_poll
  377. provider String @db.VarChar(30) // minimax | bailian | volcengine
  378. model String @db.VarChar(50) // MiniMax-M2.7 | cosyvoice-v3-flash | qwen3-tts-instruct-flash
  379. userId Int?
  380. bookId Int?
  381. chapterId Int?
  382. textLen Int @default(0) // 输入文本长度(字符数)
  383. prompt String? @db.LongText // 提示词内容(LLM only)
  384. inputTokens Int @default(0) // 输入 Token 数
  385. outputTokens Int @default(0) // 输出 Token 数
  386. estimatedCost Float @default(0) // 估算成本(元)
  387. duration Int @default(0) // 耗时(ms)
  388. success Boolean @default(true)
  389. errorMsg String? @db.Text
  390. createdAt DateTime @default(now())
  391. @@index([callType, createdAt])
  392. @@index([provider, createdAt])
  393. @@index([userId, createdAt])
  394. @@index([bookId])
  395. @@index([createdAt])
  396. }
  397. model PlatformAccount {
  398. id Int @id @default(autoincrement())
  399. userId Int
  400. platform String
  401. nickname String @default("")
  402. avatar String @default("")
  403. cookies String @db.Text
  404. headers String? @db.Text
  405. isValid Boolean @default(true)
  406. expireTime DateTime?
  407. createdAt DateTime @default(now())
  408. updatedAt DateTime @updatedAt
  409. @@unique([userId, platform])
  410. @@index([userId])
  411. @@index([platform])
  412. }
  413. model PublishTask {
  414. id Int @id @default(autoincrement())
  415. userId Int
  416. videoProjectId Int
  417. platform String
  418. title String @db.Text
  419. description String? @db.Text
  420. tags String? @db.Text
  421. coverUrl String? @db.Text
  422. videoUrl String? @db.Text
  423. status String @default("pending")
  424. errorMsg String? @db.Text
  425. publishedUrl String? @db.Text
  426. createdAt DateTime @default(now())
  427. updatedAt DateTime @updatedAt
  428. @@index([userId, platform])
  429. @@index([status])
  430. }
  431. model Draft {
  432. id Int @id @default(autoincrement())
  433. userId Int
  434. type String
  435. title String? @db.Text
  436. content String? @db.LongText
  437. metadata String? @db.Text
  438. autoSavedAt DateTime?
  439. createdAt DateTime @default(now())
  440. updatedAt DateTime @updatedAt
  441. user User @relation(fields: [userId], references: [id])
  442. @@index([userId, type])
  443. @@index([userId, updatedAt])
  444. }
  445. model Playlist {
  446. id Int @id @default(autoincrement())
  447. userId Int
  448. name String
  449. description String? @db.Text
  450. createdAt DateTime @default(now())
  451. updatedAt DateTime @updatedAt
  452. user User @relation(fields: [userId], references: [id])
  453. items PlaylistItem[]
  454. @@index([userId])
  455. }
  456. model PlaylistItem {
  457. id Int @id @default(autoincrement())
  458. playlistId Int
  459. chapterId Int?
  460. audioId String?
  461. order Int @default(0)
  462. chapter BookChapter? @relation(fields: [chapterId], references: [id])
  463. playlist Playlist @relation(fields: [playlistId], references: [id], onDelete: Cascade)
  464. @@index([playlistId, order])
  465. @@index([chapterId], map: "PlaylistItem_chapterId_fkey")
  466. }
  467. model Feedback {
  468. id String @id @default(uuid())
  469. type String
  470. title String @db.Text
  471. content String @db.Text
  472. contact String @db.Text
  473. screenshotUrls String @db.Text
  474. status String @default("submitted")
  475. createdAt DateTime @default(now())
  476. updatedAt DateTime @updatedAt
  477. @@index([type])
  478. @@index([status])
  479. @@index([createdAt])
  480. }
  481. model ShareRecord {
  482. id Int @id @default(autoincrement())
  483. userId Int
  484. audioId Int
  485. platform String
  486. shareCode String
  487. rewarded Boolean @default(false)
  488. createdAt DateTime @default(now())
  489. user User @relation(fields: [userId], references: [id])
  490. @@index([userId])
  491. @@index([shareCode])
  492. @@index([createdAt])
  493. }
  494. model InviteRecord {
  495. id Int @id @default(autoincrement())
  496. inviterId Int
  497. inviteeId Int @unique
  498. shareCode String?
  499. rewarded Boolean @default(false)
  500. rewardAmount Int @default(10000)
  501. createdAt DateTime @default(now())
  502. inviter User @relation("InviterRelation", fields: [inviterId], references: [id])
  503. invitee User @relation("InviteeRelation", fields: [inviteeId], references: [id])
  504. @@index([inviterId])
  505. @@index([shareCode])
  506. }
  507. model TokenPackPurchase {
  508. id Int @id @default(autoincrement())
  509. userId Int
  510. packMinutes Int
  511. quantity Int
  512. unitPrice Float
  513. totalAmount Float
  514. addedQuota Float
  515. createdAt DateTime @default(now())
  516. }