Skip to content

Instantly share code, notes, and snippets.

@dansp89
Last active February 29, 2024 21:32
Show Gist options
  • Select an option

  • Save dansp89/e6b0105a03edf24d97b4a1d2d864ed03 to your computer and use it in GitHub Desktop.

Select an option

Save dansp89/e6b0105a03edf24d97b4a1d2d864ed03 to your computer and use it in GitHub Desktop.

Revisions

  1. dansp89 revised this gist Feb 29, 2024. 1 changed file with 44 additions and 38 deletions.
    82 changes: 44 additions & 38 deletions Drav-TEMP.vue
    Original file line number Diff line number Diff line change
    @@ -39,7 +39,14 @@
    /**
    * @source Basic Usage <https://element-plus.org/en-US/component/upload.html#photo-wall>
    */
    import { defineComponent, ref, watchEffect, watch, type PropType } from "vue";
    import {
    defineComponent,
    ref,
    watchEffect,
    watch,
    type PropType,
    onMounted
    } from "vue";
    import { ElMessage, ElMessageBox } from "element-plus";
    import type { UploadProps, UploadUserFile } from "element-plus";
    import { UploadFilled } from "@element-plus/icons-vue";
    @@ -109,8 +116,8 @@ export default defineComponent({
    const fileList = ref<UploadUserFile[]>([]);
    const dialogImageUrl = ref("");
    const dialogVisible = ref(false);
    const valor = ref(props.modelValue);
    const imageUrls = ref([]);
    const valor = ref(props.modelValue) as any;
    const instructions = ref("");
    const uploadFileId = ref();
    @@ -123,6 +130,32 @@ export default defineComponent({
    }
    };
    const loadImageById = async (ids: Array<number | string>) => {
    // Reset imageUrls array
    imageUrls.value = [];
    const IDs = JSON.parse(JSON.stringify(ids));
    console.log("[loadImageById]::", IDs);
    // Loop through each id and fetch its URL
    for (const id of IDs) {
    try {
    const { data } = await ApiService.get(`/upload/files/${id}`);
    const response = data;
    // Assuming the response has a data object with a url property
    // console.log("[loadImageById]::response", valor.value);
    if (response.data && response.data.url) {
    imageUrls.value.push(
    import.meta.env.VITE_APP_API_URL.replace("/api", "") +
    response.data.url
    );
    }
    } catch (error) {
    console.error("Error loading image with id:", id, error);
    }
    }
    valor.value = IDs;
    };
    watchEffect(() => {
    if (props.accept === "*") {
    instructions.value = `Permitido ${props.limit} arquivo de todos os formatos, até ${props.limitSize}mb`;
    @@ -143,12 +176,6 @@ export default defineComponent({
    );
    };
    watch(valor, (newValue) => {
    emit("update:modelValue", newValue);
    emit("change", newValue);
    emit("input", newValue);
    });
    watch(
    () => props.modelValue,
    (newValue, oldValue) => {
    @@ -162,37 +189,11 @@ export default defineComponent({
    emit("update:modelValue", newValue);
    emit("change", newValue);
    emit("input", newValue);
    loadImageById(newValue as any[]);
    },
    { deep: true, immediate: true }
    ); // { deep: true } para observação profunda, { immediate: true } para rodar na inicialização
    watch(
    () => props.modelValue,
    (newValue) => {
    emit("update:modelValue", newValue);
    emit("change", newValue);
    emit("input", newValue);
    },
    { deep: true }
    );
    const loadImageById = async (id: number | string) => {
    ApiService.setHeader(); // Configura o cabeçalho, se necessário
    try {
    const response = await ApiService.get(`/upload/files/${id}`);
    if (response.data && response.data.url) {
    imageUrl.value =
    import.meta.env.VITE_APP_API_URL.replace("/api", "") +
    response.data.url;
    } else {
    throw new Error("Imagem não encontrada");
    }
    } catch (error) {
    ElMessage.error("Erro ao carregar a imagem");
    console.error(error);
    }
    };
    const beforeRemove: UploadProps["beforeRemove"] = (
    uploadFile,
    uploadFiles
    @@ -270,7 +271,7 @@ export default defineComponent({
    })
    .filter(Boolean);
    console.log("[handleDragSuccess]::", response, uploadFile, filesIds);
    console.log("[handleDragSuccess]::\n", response, uploadFile, filesIds);
    const ext = uploadFile.raw.type.split("/")[1];
    console.log("EXT FILE::", ext);
    if (uploadFile.raw.type.includes("image")) {
    @@ -327,6 +328,10 @@ export default defineComponent({
    return true;
    };
    onMounted(() => {
    return loadImageById(valor.value);
    });
    const updateValue = () => {
    emit("update:modelValue", valor.value);
    };
    @@ -348,7 +353,8 @@ export default defineComponent({
    handleDragCardPreview,
    handleDragSuccess,
    beforeDragUpload,
    loadImageById
    loadImageById,
    imageUrls
    };
    }
    });
  2. dansp89 revised this gist Feb 29, 2024. 1 changed file with 52 additions and 17 deletions.
    69 changes: 52 additions & 17 deletions Drav-TEMP.vue
    Original file line number Diff line number Diff line change
    @@ -143,6 +143,56 @@ export default defineComponent({
    );
    };
    watch(valor, (newValue) => {
    emit("update:modelValue", newValue);
    emit("change", newValue);
    emit("input", newValue);
    });
    watch(
    () => props.modelValue,
    (newValue, oldValue) => {
    console.log("modelValue alterado:", newValue);
    valor.value = newValue;
    // Para imprimir as diferenças entre os valores antigo e novo
    console.log("Valores antigos:", oldValue);
    console.log("Novos valores:", newValue);
    emit("update:modelValue", newValue);
    emit("change", newValue);
    emit("input", newValue);
    },
    { deep: true, immediate: true }
    ); // { deep: true } para observação profunda, { immediate: true } para rodar na inicialização
    watch(
    () => props.modelValue,
    (newValue) => {
    emit("update:modelValue", newValue);
    emit("change", newValue);
    emit("input", newValue);
    },
    { deep: true }
    );
    const loadImageById = async (id: number | string) => {
    ApiService.setHeader(); // Configura o cabeçalho, se necessário
    try {
    const response = await ApiService.get(`/upload/files/${id}`);
    if (response.data && response.data.url) {
    imageUrl.value =
    import.meta.env.VITE_APP_API_URL.replace("/api", "") +
    response.data.url;
    } else {
    throw new Error("Imagem não encontrada");
    }
    } catch (error) {
    ElMessage.error("Erro ao carregar a imagem");
    console.error(error);
    }
    };
    const beforeRemove: UploadProps["beforeRemove"] = (
    uploadFile,
    uploadFiles
    @@ -245,18 +295,6 @@ export default defineComponent({
    };
    const beforeDragUpload: UploadProps["beforeUpload"] = (rawFile) => {
    // console.log(
    // "[beforeDragUpload]",
    // fileList,
    // rawFile,
    // valor.value.length
    // );
    // console.log(
    // "[LIMITE de arquivos]",
    // valor.value.length,
    // props.limit,
    // valor.value.length >= props.limit
    // );
    if (valor.value.length >= props.limit) {
    ElMessage.error(`Permitido no máximo até ${props.limit} arquivo(s).`);
    return false;
    @@ -289,10 +327,6 @@ export default defineComponent({
    return true;
    };
    watch(valor, (newValue) => {
    emit("update:modelValue", newValue);
    });
    const updateValue = () => {
    emit("update:modelValue", valor.value);
    };
    @@ -313,7 +347,8 @@ export default defineComponent({
    handleDragRemove,
    handleDragCardPreview,
    handleDragSuccess,
    beforeDragUpload
    beforeDragUpload,
    loadImageById
    };
    }
    });
  3. dansp89 created this gist Feb 29, 2024.
    325 changes: 325 additions & 0 deletions Drav-TEMP.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,325 @@
    <template>
    <el-upload
    v-model:file-list="fileList"
    class="photo-wall-uploader"
    :list-type="listType"
    :drag="true"
    :name="name"
    :action="uploadMetas.url"
    :method="uploadMetas.method"
    :headers="uploadMetas.headers"
    :accept="accept"
    :multiple="multiple"
    :show-file-list="true"
    :on-success="handleDragSuccess"
    :on-remove="handleDragRemove"
    :on-exceed="handleExceed"
    :before-remove="beforeRemove"
    :before-upload="beforeDragUpload"
    :auto-upload="true"
    :limit="limit"
    >
    <!-- :disabled="fileList.length >= limit" -->
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <div class="el-upload__text">
    Solte o arquivo aqui ou
    <em>clique para fazer upload</em>
    </div>
    <template #tip>
    <div class="el-upload__tip" v-html="instructions"></div>
    </template>
    </el-upload>

    <el-dialog v-model="dialogVisible">
    <img :src="dialogImageUrl" alt="Preview Image" />
    </el-dialog>
    </template>

    <script lang="ts">
    /**
    * @source Basic Usage <https://element-plus.org/en-US/component/upload.html#photo-wall>
    */
    import { defineComponent, ref, watchEffect, watch, type PropType } from "vue";
    import { ElMessage, ElMessageBox } from "element-plus";
    import type { UploadProps, UploadUserFile } from "element-plus";
    import { UploadFilled } from "@element-plus/icons-vue";
    import { getToken } from "@/core/services/JwtService";
    import ApiService from "@/core/services/ApiService";
    import { getAssetPath } from "@/core/helpers/assets";
    export default defineComponent({
    name: "campo-upload-photowall",
    components: { UploadFilled },
    props: {
    buttonText: {
    type: String,
    default: "Clique para upload"
    },
    accept: {
    type: String,
    default: "*"
    },
    multiple: {
    type: Boolean,
    default: false
    },
    name: {
    type: String,
    default: "files" // ( Nome da chave para o arquivo carregado. )Padrão usado no STRAPI 4
    },
    withCredentials: {
    type: Boolean,
    default: false
    },
    showFileList: {
    type: Boolean,
    default: true
    },
    drag: {
    type: Boolean,
    default: false
    },
    listType: {
    type: String as PropType<"text" | "picture" | "picture-card">,
    default: "text",
    validator: (value: string) =>
    ["text", "picture", "picture-card"].includes(value)
    },
    disabled: {
    type: Boolean,
    default: false
    },
    limit: {
    type: Number,
    default: 1
    },
    limitSize: {
    type: Number,
    default: 2
    },
    modelValue: {
    type: Array, // ou o tipo apropriado
    default: () => []
    }
    },
    emits: ["update:modelValue", "change", "input"],
    setup(props, { emit }) {
    const imageUrl = ref("");
    const fileList = ref<UploadUserFile[]>([]);
    const dialogImageUrl = ref("");
    const dialogVisible = ref(false);
    const valor = ref(props.modelValue);
    const instructions = ref("");
    const uploadFileId = ref();
    const uploadData = {} as ImageData; // Resposta do servidor
    const uploadMetas = {
    url: import.meta.env.VITE_APP_API_URL + "/upload",
    method: "POST",
    headers: {
    Authorization: `Bearer ${getToken()}`
    }
    };
    watchEffect(() => {
    if (props.accept === "*") {
    instructions.value = `Permitido ${props.limit} arquivo de todos os formatos, até ${props.limitSize}mb`;
    } else {
    const filesExts = props.accept.split(",").map((a) => {
    return `*.${a.split("/")[1]}`;
    });
    const archive = props.limit < 2 ? "arquivo" : "arquivos";
    instructions.value = `Permitido <strong>${props.limit}</strong> ${archive} <strong>${filesExts}</strong> até <strong>${props.limitSize}mb</strong>`;
    }
    console.log("[Drag]::watchEffect", valor.value);
    });
    const handleExceed: UploadProps["onExceed"] = (files, uploadFiles) => {
    console.log("[handleExceed]", files, uploadFiles);
    ElMessage.warning(
    `O limite é de ${props.limit}, Você selecionou ${files.length} arquivos de uma vez.`
    );
    };
    const beforeRemove: UploadProps["beforeRemove"] = (
    uploadFile,
    uploadFiles
    ) => {
    console.log("[beforeRemove]", uploadFile, uploadFiles);
    return ElMessageBox.confirm(
    `Cancelar a transferência de ${uploadFile.name} ?`
    ).then(
    () => true,
    () => false
    );
    };
    const handleDragRemove: UploadProps["onRemove"] = async (
    uploadFile,
    uploadFiles
    ) => {
    console.log("[handleDragRemove]", uploadFile, uploadFiles);
    let id = JSON.parse(JSON.stringify(uploadFile));
    console.log("[handleDragRemove]::FILES IDS:", id);
    try {
    id = id.response[0].id;
    console.log("[handleDragRemove]::FILES IDS::toRemove:", id);
    ApiService.setHeader();
    const deletar = await ApiService.delete(`/upload/files/${id}`);
    console.log("[handleDragRemove]::deletar", deletar);
    if (deletar?.status === 200) {
    ElMessage.success("Eliminado com sucesso!");
    valor.value = valor.value?.filter((item) => item !== id);
    updateValue();
    } else {
    ElMessage.error("Falha ao eliminar!");
    }
    } catch {
    console.log("");
    }
    };
    const handleDragCardPreview: UploadProps["onPreview"] = (uploadFile) => {
    console.log("[handleDragCardPreview]", uploadFile);
    const ext = uploadFile.raw.type.split("/")[1];
    console.log("EXT FILE::", ext);
    if (uploadFile.raw.type.includes("image")) {
    dialogImageUrl.value = URL.createObjectURL(uploadFile.raw!);
    } else if (ext.includes("pdf")) {
    dialogImageUrl.value =
    window.location.origin + getAssetPath(`media/svg/files/${ext}.svg`);
    } else {
    dialogImageUrl.value =
    window.location.origin + getAssetPath(`media/svg/files/upload.svg`);
    }
    // dialogImageUrl.value = uploadFile.url!;
    dialogImageUrl.value =
    window.location.origin + getAssetPath(`media/svg/files/upload.svg`);
    dialogVisible.value = true;
    valor.value = [];
    updateValue();
    };
    const handleDragSuccess: UploadProps["onSuccess"] = (
    response,
    uploadFile,
    uploadFiles
    ) => {
    const filesIds = uploadFiles
    .map((a) => {
    try {
    a.response[0]?.id;
    } catch {
    a;
    }
    })
    .filter(Boolean);
    console.log("[handleDragSuccess]::", response, uploadFile, filesIds);
    const ext = uploadFile.raw.type.split("/")[1];
    console.log("EXT FILE::", ext);
    if (uploadFile.raw.type.includes("image")) {
    imageUrl.value = URL.createObjectURL(uploadFile.raw!);
    } else if (ext.includes("pdf")) {
    imageUrl.value =
    window.location.origin + getAssetPath(`media/svg/files/${ext}.svg`);
    } else {
    imageUrl.value =
    window.location.origin + getAssetPath(`media/svg/files/upload.svg`);
    }
    valor.value = filesIds;
    console.log(
    "[handleDragSuccess]::valor:",
    JSON.parse(JSON.stringify(valor.value)),
    "URL IMAGE:",
    imageUrl.value
    );
    emit("update:modelValue", valor.value);
    emit("change", valor.value);
    emit("input", valor.value);
    };
    const beforeDragUpload: UploadProps["beforeUpload"] = (rawFile) => {
    // console.log(
    // "[beforeDragUpload]",
    // fileList,
    // rawFile,
    // valor.value.length
    // );
    // console.log(
    // "[LIMITE de arquivos]",
    // valor.value.length,
    // props.limit,
    // valor.value.length >= props.limit
    // );
    if (valor.value.length >= props.limit) {
    ElMessage.error(`Permitido no máximo até ${props.limit} arquivo(s).`);
    return false;
    }
    if (
    !props.accept
    .split(",")
    .map((a) => a.trim())
    .includes(rawFile.type)
    ) {
    ElMessage.error(
    `Permitido ${props.limit} arquivo de todos os formatos, até ${props.limitSize}mb`
    );
    return false;
    }
    if (rawFile.size / 1024 / 1024 > props.limitSize) {
    const filesExts = props.accept.split(",").map((a) => {
    return `*.${a.split("/")[1]}`;
    });
    const archive = props.limit < 2 ? "arquivo" : "arquivos";
    instructions.value = `Permitido <strong>${props.limit}</strong> ${archive} <strong>${filesExts}</strong> até <strong>${props.limitSize}mb</strong>`;
    ElMessage.error({
    message: `Permitido ${props.limit} ${archive} ${filesExts} até ${props.limitSize}mb`,
    duration: 5000
    });
    return false;
    }
    return true;
    };
    watch(valor, (newValue) => {
    emit("update:modelValue", newValue);
    });
    const updateValue = () => {
    emit("update:modelValue", valor.value);
    };
    return {
    dialogImageUrl,
    dialogVisible,
    imageUrl,
    fileList,
    instructions,
    uploadFileId,
    uploadData,
    uploadMetas,
    valor,
    updateValue,
    handleExceed,
    beforeRemove,
    handleDragRemove,
    handleDragCardPreview,
    handleDragSuccess,
    beforeDragUpload
    };
    }
    });
    </script>
    <style scoped>
    .el-dialog__body img {
    width: 100%;
    }
    </style>