usePasteEvent.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { onMounted, onUnmounted } from 'vue'
  2. import { storeToRefs } from 'pinia'
  3. import { useMainStore } from '@/store'
  4. import { getImageDataURL } from '@/utils/image'
  5. import usePasteTextClipboardData from './usePasteTextClipboardData'
  6. import useCreateElement from './useCreateElement'
  7. /**
  8. * 上传 File 到 S3,返回公开访问的 URL
  9. */
  10. const uploadFileToS3 = (file: File): Promise<string> => {
  11. return new Promise((resolve, reject) => {
  12. if (typeof window === 'undefined' || !window.AWS) {
  13. reject(new Error('AWS SDK not available'))
  14. return
  15. }
  16. const credentials = {
  17. accessKeyId: 'AKIATLPEDU37QV5CHLMH',
  18. secretAccessKey: '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',
  19. }
  20. window.AWS.config.update(credentials)
  21. window.AWS.config.region = 'cn-northwest-1'
  22. const bucket = new window.AWS.S3({
  23. params: { Bucket: 'ccrb' }, httpOptions: {
  24. timeout: 600000 // 10分钟超时
  25. }
  26. })
  27. const ext = file.name.split('.').pop() || 'bin'
  28. const key = `${file.name.split('.')[0]}_${Date.now()}.${ext}`
  29. const params = {
  30. Key: 'pptto/' + key,
  31. ContentType: file.type,
  32. Body: file,
  33. ACL: 'public-read',
  34. }
  35. const options = {
  36. partSize: 5 * 1024 * 1024, // 2GB 分片,可酌情调小
  37. queueSize: 2,
  38. leavePartsOnError: true,
  39. }
  40. bucket
  41. .upload(params, options)
  42. .promise()
  43. .then(data => resolve(data.Location))
  44. .catch(err => reject(err))
  45. })
  46. }
  47. export default () => {
  48. const { editorAreaFocus, thumbnailsFocus, disableHotkeys } = storeToRefs(useMainStore())
  49. const { pasteTextClipboardData } = usePasteTextClipboardData()
  50. const { createImageElement } = useCreateElement()
  51. // 粘贴图片到幻灯片元素
  52. const pasteImageFile = (imageFile: File) => {
  53. // getImageDataURL(imageFile).then(dataURL => createImageElement(dataURL))
  54. uploadFileToS3(imageFile).then(url => createImageElement(url))
  55. }
  56. /**
  57. * 粘贴事件监听
  58. * @param e ClipboardEvent
  59. */
  60. const pasteListener = (e: ClipboardEvent) => {
  61. if (!editorAreaFocus.value && !thumbnailsFocus.value) return
  62. if (disableHotkeys.value) return
  63. if (!e.clipboardData) return
  64. const clipboardDataItems = e.clipboardData.items
  65. const clipboardDataFirstItem = clipboardDataItems[0]
  66. if (!clipboardDataFirstItem) return
  67. // 如果剪贴板内有图片,优先尝试读取图片
  68. let isImage = false
  69. for (const item of clipboardDataItems) {
  70. if (item.kind === 'file' && item.type.indexOf('image') !== -1) {
  71. const imageFile = item.getAsFile()
  72. if (imageFile) pasteImageFile(imageFile)
  73. isImage = true
  74. }
  75. }
  76. if (isImage) return
  77. // 如果剪贴板内没有图片,但有文字内容,尝试解析文字内容
  78. if (clipboardDataFirstItem.kind === 'string' && clipboardDataFirstItem.type === 'text/plain') {
  79. clipboardDataFirstItem.getAsString(text => pasteTextClipboardData(text))
  80. }
  81. }
  82. onMounted(() => {
  83. document.addEventListener('paste', pasteListener)
  84. })
  85. onUnmounted(() => {
  86. document.removeEventListener('paste', pasteListener)
  87. })
  88. }