VideoToolBarItem.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <script setup lang="ts">
  2. import { ref, inject, type Ref } from "vue";
  3. import { VideoCamera } from "@element-plus/icons-vue";
  4. import { DropdownToolbar } from "md-editor-v3";
  5. import { Link } from "@element-plus/icons-vue";
  6. import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
  7. import { v4 as uuid4 } from "uuid";
  8. const prefix = "md-editor";
  9. const s3 = inject<InstanceType<typeof S3Client>>("s3");
  10. const editorLoading = inject<Ref<boolean>>("editorLoading");
  11. const props = defineProps<{
  12. insert?: Function;
  13. }>();
  14. const showDropdown = ref(false);
  15. const showDialog = ref(false);
  16. const linkInput = ref("");
  17. const onClickMenuLink = () => {
  18. showDropdown.value = false;
  19. showDialog.value = true;
  20. };
  21. const selectFile = (contentType: string, multiple: boolean) => {
  22. return new Promise((resolve) => {
  23. let input = document.createElement("input");
  24. input.type = "file";
  25. input.multiple = multiple;
  26. input.accept = contentType;
  27. input.onchange = (_) => {
  28. let files = Array.from(input.files);
  29. if (multiple) resolve(files);
  30. else resolve(files[0]);
  31. };
  32. input.click();
  33. });
  34. };
  35. const onClickMenuSelect = async () => {
  36. showDropdown.value = false;
  37. const file = await selectFile("video/*", false);
  38. const key = `${uuid4()}::${file.name}`;
  39. const command = new PutObjectCommand({
  40. Bucket: import.meta.env.VITE_DOCS_MEDIA_BUCKET,
  41. Key: key,
  42. Body: file,
  43. ACL: "public-read",
  44. });
  45. editorLoading!.value = true;
  46. await s3!.send(command);
  47. editorLoading!.value = false;
  48. insert(
  49. `https://${import.meta.env.VITE_DOCS_MEDIA_BUCKET}.s3.amazonaws.com/${key}`
  50. );
  51. };
  52. const onConfirmDialog = async () => {
  53. // FIXME check link format?
  54. await insert(linkInput.value);
  55. linkInput.value = "";
  56. showDialog.value = false;
  57. };
  58. const insert = (url: string) => {
  59. // TEST
  60. // const url = `https://woolyss.com/f/av1-opus-sita.webm`;
  61. props.insert?.(() => ({
  62. targetValue: `<video src="${url}" width="100%" controls></video>`,
  63. }));
  64. };
  65. </script>
  66. <template>
  67. <DropdownToolbar title="video" :visible="showDropdown" :onChange="(v) => (showDropdown = v)">
  68. <template #trigger>
  69. <VideoCamera width="18" />
  70. </template>
  71. <template #overlay>
  72. <ul :class="`${prefix}-menu`">
  73. <li :class="`${prefix}-menu-item ${prefix}-menu-item-title`" @click="onClickMenuLink">
  74. 输入链接
  75. </li>
  76. <li :class="`${prefix}-menu-item ${prefix}-menu-item-title`" @click="onClickMenuSelect">
  77. 选择文件
  78. </li>
  79. </ul>
  80. </template>
  81. </DropdownToolbar>
  82. <el-dialog v-model="showDialog" title="添加视频">
  83. <div>
  84. <el-input v-model="linkInput" placeholder="https://woolyss.com/f/av1-opus-sita.webm">
  85. <template #prepend>
  86. <el-icon>
  87. <Link />
  88. </el-icon>
  89. </template>
  90. </el-input>
  91. </div>
  92. <template #footer>
  93. <div>
  94. <el-button @click="showDialog = false">取消</el-button>
  95. <el-button type="primary" @click="onConfirmDialog"> 确认 </el-button>
  96. </div>
  97. </template>
  98. </el-dialog>
  99. </template>