record.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { ref, watchEffect } from "vue";
  2. import { autoSetModeCallback, createTemploraryID, unSetModelUpdate } from './sys'
  3. import {
  4. addStoreItem,
  5. deleteStoreItem,
  6. fetchStoreItems,
  7. recoverStoreItems,
  8. saveStoreItems,
  9. updateStoreItem,
  10. togetherCallback,
  11. diffStoreItemsChange
  12. } from '@/utils'
  13. import {
  14. fetchRecords,
  15. postAddRecord,
  16. postUpdateRecord,
  17. postDeleteRecord,
  18. RecordStatus,
  19. postMegerRecord,
  20. blobToFile,
  21. uploadFile,
  22. fetchRecordStatus
  23. } from '@/api'
  24. import {
  25. getRecordFragments,
  26. initRecordFragmentsByRecord,
  27. recordFragments,
  28. backupRecordFragments,
  29. recoverRecordFragments,
  30. saveRecordFragments
  31. } from './record-fragment'
  32. import type { Record as SRecord } from '@/api'
  33. import { Message } from "bill/index";
  34. export type Record = LocalMode<SRecord, 'cover'>
  35. export type Records = Record[]
  36. export const records = ref<Records>([])
  37. export const createRecord = (record: Partial<Record> = {}): Record => ({
  38. id: createTemploraryID(),
  39. title: '讲解视频' + (records.value.length + 1),
  40. cover: '',
  41. url: '',
  42. status: RecordStatus.UN,
  43. sort: Math.min(...records.value.map(item => item.sort)) - 1,
  44. ...record
  45. })
  46. let bcRecords: Records = []
  47. export const getBackupRecords = () => bcRecords
  48. export const backupRecords = () => {
  49. bcRecords = records.value.map(record => ({...record }))
  50. }
  51. export const recoverRecords = recoverStoreItems(records, getBackupRecords)
  52. const refreshRecords: NodeJS.Timeout[] = []
  53. const refreshRecordStatus = async (record: Record) => {
  54. const status = await fetchRecordStatus(record.id)
  55. if (status === RecordStatus.SUCCESS) {
  56. refreshRecords.forEach(clearTimeout)
  57. refreshRecords.length = 0
  58. initialRecords()
  59. } else {
  60. refreshRecords.push(
  61. setTimeout(refreshRecordStatus.bind(null, record), 3000)
  62. )
  63. }
  64. }
  65. const getRecordMergeFiles = (record: Record) => {
  66. const fragments = getRecordFragments(record)
  67. const files = fragments
  68. .filter(fragment => typeof fragment.url !== 'string')
  69. .map(fragment => blobToFile((fragment.url as Blob), '.mp4'))
  70. return files
  71. }
  72. export const initialRecords = async () => {
  73. const serviceRecords = await fetchRecords()
  74. unSetModelUpdate(() => records.value = serviceRecords)
  75. await Promise.all(records.value.map(initRecordFragmentsByRecord))
  76. for (const record of records.value) {
  77. if (record.status === RecordStatus.RUN) {
  78. refreshRecordStatus(record)
  79. }
  80. }
  81. backupRecords()
  82. }
  83. export const addRecord = addStoreItem(records, async (record) => {
  84. const cover = record.cover ? await uploadFile(record.cover) : record.cover
  85. const serviceRecord = await postAddRecord({ ...record, cover }, getRecordMergeFiles(record))
  86. record.id = serviceRecord.id
  87. await postUpdateRecord(record as SRecord)
  88. return record
  89. })
  90. export const updateRecord = updateStoreItem(records, async (record) => {
  91. const cover = record.cover ? await uploadFile(record.cover) : record.cover
  92. return await postUpdateRecord({ ...record, cover })
  93. })
  94. export const deleteRecord = deleteStoreItem(records, async record => {
  95. recordFragments.value = recordFragments.value.filter(fragment => fragment.recordId !== record.id)
  96. await postDeleteRecord(record.id)
  97. })
  98. export const saveRecords = saveStoreItems(
  99. records,
  100. getBackupRecords,
  101. {
  102. add: addRecord,
  103. delete: deleteRecord,
  104. update: updateRecord
  105. }
  106. )
  107. export const autoSaveRecords = autoSetModeCallback(
  108. [records, recordFragments],
  109. {
  110. backup: togetherCallback([backupRecordFragments, backupRecords]),
  111. recovery: togetherCallback([recoverRecordFragments, recoverRecords]),
  112. save: async () => {
  113. if (!records.value.every(record => record.title)) {
  114. Message.warning('视频名称不可为空')
  115. throw '视频名称不可为空'
  116. }
  117. for (let i = 0; i < records.value.length; i++) {
  118. records.value[i].sort = i
  119. }
  120. const oldRecords = getBackupRecords()
  121. const { added } = diffStoreItemsChange(records.value, oldRecords)
  122. await saveRecords()
  123. await saveRecordFragments()
  124. const files = records.value
  125. .filter(record => !added.includes(record))
  126. .map(record => ({ record, merge: getRecordMergeFiles(record) }))
  127. .filter(({merge}) => merge.length)
  128. await Promise.all(files.map(({record, merge}) => postMegerRecord(merge, record.id)))
  129. await initialRecords()
  130. }
  131. }
  132. )
  133. export { RecordStatus }