schema.prisma 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. voiceSpeed Float @default(1.0)
  143. createdAt DateTime @default(now())
  144. updatedAt DateTime @updatedAt
  145. failedStage String? @db.VarChar(30)
  146. genStage String @default("draft")
  147. bookAnalysis String? @db.Text
  148. autoGenerateContent Boolean @default(true)
  149. autoGenerateAudio Boolean @default(true)
  150. // 非错误的报告字段(与 errorMsg 分离,避免前端误判为失败)
  151. qualityReport String? @db.Text
  152. continuityReport String? @db.Text
  153. rewriteReport String? @db.Text
  154. chapters BookChapter[]
  155. favorites Favorite[]
  156. videoProjects VideoProject[]
  157. @@index([userId])
  158. @@index([createdAt])
  159. }
  160. model BookChapter {
  161. id Int @id @default(autoincrement())
  162. bookId Int
  163. parentId Int @default(0)
  164. level Int @default(1)
  165. number Int
  166. title String
  167. summary String? @db.Text
  168. keyPoints String? @db.Text
  169. estimatedWords Int @default(1000)
  170. content String? @db.LongText
  171. wordCount Int @default(0)
  172. contentError String? @db.Text
  173. generatedAt DateTime?
  174. audioUrl String? @db.Text
  175. audioDuration Int @default(0)
  176. videoUrl String? @db.Text
  177. videoDuration Int?
  178. isPublic Boolean @default(false)
  179. genStage String @default("idle")
  180. lrcLyrics String? @db.Text
  181. contentCheck String? @db.Text
  182. book Book @relation(fields: [bookId], references: [id], onDelete: Cascade)
  183. comments Comment[]
  184. playRecords PlayRecord[]
  185. playlistItems PlaylistItem[]
  186. ttsTasks TtsTask[]
  187. videoProjects VideoProject[]
  188. @@unique([bookId, parentId, level, number])
  189. @@index([bookId])
  190. @@index([bookId, parentId])
  191. @@index([bookId, level])
  192. }
  193. model VideoProject {
  194. id Int @id @default(autoincrement())
  195. userId Int?
  196. title String
  197. description String?
  198. coverUrl String?
  199. configJson String? @db.LongText
  200. outputUrl String?
  201. duration Int?
  202. fileSize Int?
  203. bookId Int?
  204. chapterId Int?
  205. status String @default("draft")
  206. progress Int @default(0)
  207. errorMsg String? @db.Text
  208. createdAt DateTime @default(now())
  209. updatedAt DateTime @updatedAt
  210. book Book? @relation(fields: [bookId], references: [id])
  211. chapter BookChapter? @relation(fields: [chapterId], references: [id])
  212. @@index([userId, status])
  213. @@index([createdAt])
  214. @@index([bookId], map: "VideoProject_bookId_fkey")
  215. @@index([chapterId], map: "VideoProject_chapterId_fkey")
  216. }
  217. model SearchHistory {
  218. id Int @id @default(autoincrement())
  219. userId Int
  220. keyword String
  221. createdAt DateTime @default(now())
  222. @@index([userId, createdAt])
  223. @@index([userId])
  224. }
  225. model HotSearch {
  226. id Int @id @default(autoincrement())
  227. keyword String
  228. count Int @default(0)
  229. sort Int @default(0)
  230. createdAt DateTime @default(now())
  231. updatedAt DateTime @updatedAt
  232. @@index([sort])
  233. @@index([count])
  234. }
  235. model SignRecord {
  236. id Int @id @default(autoincrement())
  237. userId Int
  238. createdAt DateTime @default(now())
  239. user User @relation(fields: [userId], references: [id])
  240. @@unique([userId, createdAt])
  241. @@index([userId, createdAt])
  242. }
  243. model SubscriptionPlan {
  244. id Int @id @default(autoincrement())
  245. name String
  246. level Int @default(0)
  247. priceMonthly Decimal @default(0.00) @db.Decimal(10, 2)
  248. priceYearly Decimal @default(0.00) @db.Decimal(10, 2)
  249. description String? @db.Text
  250. features String? @db.Text
  251. isRecommended Boolean @default(false)
  252. isActive Boolean @default(true)
  253. sortOrder Int @default(0)
  254. dailyGenerations Int @default(3)
  255. perGenerationLimit Int @default(2000)
  256. monthlyTokens Int @default(10000)
  257. monthlyMinutes Int @default(30)
  258. yearlyTokens Int?
  259. voiceOptions Int @default(5)
  260. audioQuality String @default("standard")
  261. apiAccess Boolean @default(false)
  262. batchProcessing Boolean @default(false)
  263. teamManagement Boolean @default(false)
  264. overageEnabled Boolean @default(false)
  265. overagePrice Decimal @default(0.000) @db.Decimal(10, 3)
  266. createdAt DateTime @default(now())
  267. updatedAt DateTime @updatedAt
  268. orders Order[]
  269. subscriptions Subscription[]
  270. @@index([level])
  271. @@index([isActive, sortOrder])
  272. }
  273. model Subscription {
  274. id Int @id @default(autoincrement())
  275. userId Int
  276. planId Int
  277. startDate DateTime
  278. endDate DateTime
  279. status String @default("active")
  280. autoRenew Boolean @default(false)
  281. createdAt DateTime @default(now())
  282. updatedAt DateTime @updatedAt
  283. plan SubscriptionPlan @relation(fields: [planId], references: [id])
  284. user User @relation(fields: [userId], references: [id])
  285. @@index([userId, status])
  286. @@index([userId, endDate])
  287. @@index([planId], map: "Subscription_planId_fkey")
  288. }
  289. model TokenUsage {
  290. id Int @id @default(autoincrement())
  291. userId Int
  292. type String
  293. amount Int @default(0)
  294. contentLength Int @default(0)
  295. orderId Int?
  296. description String? @db.Text
  297. createdAt DateTime @default(now())
  298. order Order? @relation(fields: [orderId], references: [id])
  299. user User @relation(fields: [userId], references: [id])
  300. @@index([userId, createdAt])
  301. @@index([userId, type])
  302. @@index([orderId], map: "TokenUsage_orderId_fkey")
  303. }
  304. model TokenBalance {
  305. id Int @id @default(autoincrement())
  306. userId Int @unique
  307. totalTokens Int @default(0)
  308. usedTokens Int @default(0) // 总消耗
  309. packTokens Int @default(0) // 积分包购买的Token总数
  310. usedPackTokens Int @default(0) // 积分包已消耗的Token数
  311. resetDate DateTime?
  312. createdAt DateTime @default(now())
  313. updatedAt DateTime @updatedAt
  314. user User @relation(fields: [userId], references: [id])
  315. @@index([userId])
  316. }
  317. model VideoMaterial {
  318. id Int @id @default(autoincrement())
  319. userId Int?
  320. type String
  321. name String
  322. url String @db.Text
  323. thumbnail String?
  324. tags String? @db.Text
  325. category String?
  326. duration Int?
  327. size Int?
  328. width Int?
  329. height Int?
  330. createdAt DateTime @default(now())
  331. updatedAt DateTime @updatedAt
  332. @@index([userId, type])
  333. @@index([type, category])
  334. }
  335. model AudioRecord {
  336. id Int @id @default(autoincrement())
  337. userId Int?
  338. audioId String @unique
  339. title String @default("未命名音频")
  340. text String? @db.LongText
  341. wordCount Int @default(0)
  342. voiceId String @default("cherry")
  343. voiceParams String?
  344. audioUrl String? @db.Text
  345. audioDuration Int @default(0)
  346. audioSize Int @default(0)
  347. status String @default("processing")
  348. errorMsg String? @db.Text
  349. createdAt DateTime @default(now())
  350. updatedAt DateTime @updatedAt
  351. bookId Int?
  352. provider String? // TTS 供应商: bailian / edge / mock
  353. @@index([userId])
  354. @@index([audioId])
  355. @@index([bookId])
  356. }
  357. model TtsTask {
  358. id Int @id @default(autoincrement())
  359. taskType String @default("tts") @db.VarChar(20) // "tts" | "content"
  360. chapterId Int
  361. bookId Int?
  362. userId Int?
  363. contentHash String @db.VarChar(64)
  364. content String? @db.LongText
  365. status String @default("pending")
  366. audioUrl String? @db.Text
  367. audioDuration Int @default(0)
  368. errorMsg String? @db.Text
  369. retryCount Int @default(0)
  370. maxRetries Int @default(3)
  371. voiceId String @default("default")
  372. voiceSpeed Float @default(1.0)
  373. startedAt DateTime?
  374. completedAt DateTime?
  375. createdAt DateTime @default(now())
  376. updatedAt DateTime @updatedAt
  377. chapter BookChapter @relation(fields: [chapterId], references: [id], onDelete: Cascade)
  378. @@index([taskType, status, createdAt])
  379. @@index([chapterId, contentHash])
  380. @@index([contentHash, chapterId])
  381. }
  382. model AiCallLog {
  383. id Int @id @default(autoincrement())
  384. callType String @db.VarChar(20) // llm_chat | llm_tools | tts_synthesize | tts_create | tts_poll
  385. provider String @db.VarChar(30) // minimax | bailian | volcengine
  386. model String @db.VarChar(50) // MiniMax-M2.7 | cosyvoice-v3-flash | qwen3-tts-instruct-flash
  387. userId Int?
  388. bookId Int?
  389. chapterId Int?
  390. textLen Int @default(0) // 输入文本长度(字符数)
  391. prompt String? @db.LongText // 提示词内容(LLM only)
  392. inputTokens Int @default(0) // 输入 Token 数
  393. outputTokens Int @default(0) // 输出 Token 数
  394. estimatedCost Float @default(0) // 估算成本(元)
  395. duration Int @default(0) // 耗时(ms)
  396. success Boolean @default(true)
  397. errorMsg String? @db.Text
  398. createdAt DateTime @default(now())
  399. @@index([callType, createdAt])
  400. @@index([provider, createdAt])
  401. @@index([userId, createdAt])
  402. @@index([bookId])
  403. @@index([createdAt])
  404. }
  405. model PlatformAccount {
  406. id Int @id @default(autoincrement())
  407. userId Int
  408. platform String
  409. nickname String @default("")
  410. avatar String @default("")
  411. cookies String @db.Text
  412. headers String? @db.Text
  413. isValid Boolean @default(true)
  414. expireTime DateTime?
  415. createdAt DateTime @default(now())
  416. updatedAt DateTime @updatedAt
  417. @@unique([userId, platform])
  418. @@index([userId])
  419. @@index([platform])
  420. }
  421. model PublishTask {
  422. id Int @id @default(autoincrement())
  423. userId Int
  424. videoProjectId Int
  425. platform String
  426. title String @db.Text
  427. description String? @db.Text
  428. tags String? @db.Text
  429. coverUrl String? @db.Text
  430. videoUrl String? @db.Text
  431. status String @default("pending")
  432. errorMsg String? @db.Text
  433. publishedUrl String? @db.Text
  434. createdAt DateTime @default(now())
  435. updatedAt DateTime @updatedAt
  436. @@index([userId, platform])
  437. @@index([status])
  438. }
  439. model Draft {
  440. id Int @id @default(autoincrement())
  441. userId Int
  442. type String
  443. title String? @db.Text
  444. content String? @db.LongText
  445. metadata String? @db.Text
  446. autoSavedAt DateTime?
  447. createdAt DateTime @default(now())
  448. updatedAt DateTime @updatedAt
  449. user User @relation(fields: [userId], references: [id])
  450. @@index([userId, type])
  451. @@index([userId, updatedAt])
  452. }
  453. model Playlist {
  454. id Int @id @default(autoincrement())
  455. userId Int
  456. name String
  457. description String? @db.Text
  458. createdAt DateTime @default(now())
  459. updatedAt DateTime @updatedAt
  460. user User @relation(fields: [userId], references: [id])
  461. items PlaylistItem[]
  462. @@index([userId])
  463. }
  464. model PlaylistItem {
  465. id Int @id @default(autoincrement())
  466. playlistId Int
  467. chapterId Int?
  468. audioId String?
  469. order Int @default(0)
  470. chapter BookChapter? @relation(fields: [chapterId], references: [id])
  471. playlist Playlist @relation(fields: [playlistId], references: [id], onDelete: Cascade)
  472. @@index([playlistId, order])
  473. @@index([chapterId], map: "PlaylistItem_chapterId_fkey")
  474. }
  475. model Feedback {
  476. id String @id @default(uuid())
  477. type String
  478. title String @db.Text
  479. content String @db.Text
  480. contact String @db.Text
  481. screenshotUrls String @db.Text
  482. status String @default("submitted")
  483. createdAt DateTime @default(now())
  484. updatedAt DateTime @updatedAt
  485. @@index([type])
  486. @@index([status])
  487. @@index([createdAt])
  488. }
  489. model ShareRecord {
  490. id Int @id @default(autoincrement())
  491. userId Int
  492. audioId Int
  493. platform String
  494. shareCode String
  495. rewarded Boolean @default(false)
  496. createdAt DateTime @default(now())
  497. user User @relation(fields: [userId], references: [id])
  498. @@index([userId])
  499. @@index([shareCode])
  500. @@index([createdAt])
  501. }
  502. model InviteRecord {
  503. id Int @id @default(autoincrement())
  504. inviterId Int
  505. inviteeId Int @unique
  506. shareCode String?
  507. rewarded Boolean @default(false)
  508. rewardAmount Int @default(10000)
  509. createdAt DateTime @default(now())
  510. inviter User @relation("InviterRelation", fields: [inviterId], references: [id])
  511. invitee User @relation("InviteeRelation", fields: [inviteeId], references: [id])
  512. @@index([inviterId])
  513. @@index([shareCode])
  514. }
  515. model TokenPackPurchase {
  516. id Int @id @default(autoincrement())
  517. userId Int
  518. packMinutes Int
  519. quantity Int
  520. unitPrice Float
  521. totalAmount Float
  522. addedQuota Float
  523. createdAt DateTime @default(now())
  524. }