導入彈窗
<template><el-dialog:title="title":visible.sync="fileUploadVisible"append-to-bodyclose-on-click-modalclose-on-press-escapewidth="420px"><div v-if="showDatePicker">選擇時間:<el-date-pickerv-model="dataDate"type="date"placeholder="選擇日期"value-format="yyyy-MM-dd"format="yyyy-MM-dd"></el-date-picker></div><div class="my-upload"><el-uploadclass="upload-file-uploader"ref="fileUpload"multipledrag:action="uploadFileUrl":before-upload="handleBeforeUpload":file-list="fileList":limit="limit":on-error="handleUploadError":on-exceed="handleExceed":on-success="handleUploadSuccess":show-file-list="false":headers="headers":data="infoType"><i class="el-icon-upload"></i><div class="el-upload__text">將文件拖到此處,或<em style="color: rgb(22, 93, 255)">點擊上傳</em></div></el-upload><!-- 文件列表 --><transition-groupclass="upload-file-list el-upload-list el-upload-list--text"name="el-fade-in-linear"tag="ul"><li:key="file.url"class="el-upload-list__item ele-upload-list__item-content"v-for="(file, index) in fileList"><el-link :href="file.url" :underline="false" target="_blank"><span class="el-icon-document"> {{ getFileName(file.name) }} </span></el-link><div class="ele-upload-list__item-content-action"><el-link:underline="false"@click="handleDelete(index)"type="danger">刪除</el-link></div></li></transition-group></div><div style="text-align: center; padding: 15px">點擊右側按鈕,下載導入模板<span class="import-text" v-if="showDownLoad" @click="onDownLoad">下載</span></div><div class="tip-text" v-if="tipText"><span>特別提醒:</span>{{ tipText }}</div></el-dialog>
</template>
<script>
import dayjs from "dayjs";
import { saveAs } from "file-saver";
import { getToken } from "@/utils/auth";export default {props: {title: {type: String,default: "導入",},tipText: {type: String,default: "",},// 值value: [String, Object, Array],// 數量限制limit: {type: Number,default: 99,},// 文件類型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array,default: () => ["xls", "xlsx"],// default: () => ["png", "jpg", "jpeg"],},// 下載模版apidownloadApi: {type: Function,default: () => {console.log("[ ] >", "downloadApi");},},// 下載模板標題downloadTitle: {type: String,default: "導入模板",},// 導入apiimportApi: {type: Function,default: () => {console.log("[ ] >", "importApi");},},// 是否真是下載模板showDownLoad: {type: Boolean,default: true,},showDatePicker: {type: Boolean,default: false,},// 模板下載地址uploadUrl: { type: String, default: "" },// 導入需要的InfoTypeinfoType: {type: Object,default: () => {},},},data() {return {number: 0,uploadList: [],uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上傳文件服務器地址headers: {Authorization: "Bearer " + getToken(),},fileList: [],fileUploadVisible: false,file: null,dataDate: "",};},mounted() {},watch: {value: {handler(val) {if (val) {let temp = 1;// 首先將值轉為數組const list = Array.isArray(val) ? val : this.value.split(",");// 然后將數組轉為對象數組this.fileList = list.map((item) => {if (typeof item === "string") {item = { name: item, url: item };}item.uid = item.uid || new Date().getTime() + temp++;return item;});} else {this.fileList = [];return [];}},deep: true,immediate: true,},},methods: {onShow() {this.fileUploadVisible = true;console.log(process.env.VUE_APP_BASE_API + "/file/upload");this.dataDate = "";},// 下載模版onDownLoad() {this.downloadApi().then((res) => {const blob = new Blob([res]);saveAs(blob, `${this.downloadTitle}.xlsx`);});},// 上傳前校檢格式和大小handleBeforeUpload(file) {if (this.showDatePicker && this.dataDate == "") {this.$message.warning("請先選擇日期");} else {// 校檢文件類型if (this.fileType) {const fileName = file.name.split(".");const fileExt = fileName[fileName.length - 1];const isTypeOk = this.fileType.indexOf(fileExt) >= 0;if (!isTypeOk) {this.$modal.msgError(`文件格式不正確, 請上傳${this.fileType.join("/")}格式文件!`);return false;}}this.file = file;this.$modal.loading("正在上傳文件,請稍候...");this.number++;return true;}},// 文件個數超出handleExceed() {this.$modal.msgError(`上傳文件數量不能超過 ${this.limit} 個!`);},// 上傳失敗handleUploadError(err) {this.$modal.msgError("上傳文件失敗,請重試");this.$modal.closeLoading();},// 上傳成功回調handleUploadSuccess(res, file) {if (this.showDatePicker && this.dataDate == "") {} else {if (res.code == 200) {const formData = new FormData();formData.append("file", this.file);if (this.showDatePicker) {formData.append("dataDate", this.dataDate);}this.importApi(formData).then((res) => {if (res.code == 0 || res.code == 200) {this.$message.success("導入成功");this.uploadList = [];this.fileList = [];this.fileUploadVisible = false;this.$modal.closeLoading();this.$emit("getList");}}).catch(() => {this.$modal.closeLoading();});return;}this.$modal.msgError("上傳文件失敗,請重試");this.$modal.closeLoading();}},// 刪除文件handleDelete(index) {this.fileList.splice(index, 1);this.$emit("input", this.listToString(this.fileList));},// 上傳結束處理uploadedSuccessfully() {if (this.number > 0 && this.uploadList.length === this.number) {this.fileList = this.fileList.concat(this.uploadList);this.uploadList = [];this.number = 0;this.$emit("input", this.listToString(this.fileList));this.$modal.closeLoading();}},// 獲取文件名稱getFileName(name) {// 如果是url那么取最后的名字 如果不是直接返回if (name?.lastIndexOf("/") > -1) {return name.slice(name.lastIndexOf("/") + 1);} else {return name;}},// 對象轉成指定字符串分隔listToString(list, separator) {let strs = "";separator = separator || ",";for (let i in list) {strs += list[i].url + separator;}return strs != "" ? strs.substr(0, strs.length - 1) : "";},},
};
</script>
<style lang="scss" scoped>
::v-deep .el-dialog__header > .el-dialog__title {font-weight: 600 !important;
}.import-text {color: rgb(22, 93, 255);text-align: center;font-size: 14px;cursor: pointer;
}.my-upload {margin-top: 20px;display: flex;justify-content: center;.el-icon-upload {color: rgb(22, 93, 255);font-size: 100px;}
}.tip-text {padding: 0 10px;margin-top: 20px;color: rgb(241, 51, 51);
}.upload-file-uploader {margin-bottom: 5px;
}.upload-file-list .el-upload-list__item {border: 1px solid #e4e7ed;line-height: 2;margin-bottom: 10px;position: relative;
}.upload-file-list .ele-upload-list__item-content {display: flex;justify-content: space-between;align-items: center;color: inherit;
}.ele-upload-list__item-content-action .el-link {margin-right: 10px;
}:v-deep .el-upload,
.el-upload--text {// margin: 0 auto !important;width: 100% !important;
}
</style>
彈窗使用
<!-- 導入 -->
<FileUploadref="fileUpload"title="導入數據":importApi="importRealApi":onReset="getRealList"@getList="getList":infoType="infoType":downloadApi="downRealTempleteApi":showDatePicker="true":tipText="tipText"downloadTitle="房產交易信息導入模板"
/>
1.為什么要進行 const formData = new FormData() 處理
HTTP 請求中,文件不能直接作為普通文本字段發送,需要以二進制流的形式上傳。FormData
專門用于構造包含文件的表單數據,瀏覽器會自動將其編碼成 multipart/form-data
格式,符合文件上傳的標準
2.multipart/form-data 格式是什么??
multipart/form-data
是一種專門為上傳文件設計的 HTTP 請求編碼格式,它通過分隔符將多個字段(包括文件)分開,保證文件數據能被正確傳輸和解析,是文件上傳的標準方式。