image-upload.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <template>
  2. <div>
  3. <el-upload
  4. class="uploader"
  5. :action="oss_url"
  6. :data="dataObj"
  7. :multiple="multiple"
  8. name="file"
  9. :accept="accept"
  10. :show-file-list="false"
  11. :on-success="uploadSuccess"
  12. :before-upload="beforeUpload"
  13. />
  14. <div class="images">
  15. <div v-for="(item, index) in fileList" :key="index" class="item">
  16. <div
  17. v-if="item.url"
  18. class="img"
  19. @mouseover="item.hover = true"
  20. @mouseout="item.hover = false"
  21. >
  22. <el-image
  23. v-if="checkFileType(item.url) == 'image'"
  24. ref="img"
  25. :src="imageURL + item.url"
  26. :preview-src-list="previewImages"
  27. style="width: 120px; height: 120px"
  28. fit="cover"
  29. />
  30. <el-image
  31. v-else
  32. ref="img"
  33. :src="imageURL + item.url"
  34. style="width: 120px; height: 120px"
  35. fit="cover"
  36. >
  37. <div slot="error" class="image-slot">
  38. <img
  39. v-if="checkFileType(item.url) == 'word'"
  40. class="file"
  41. src="@/assets/common/word.png"
  42. />
  43. <img
  44. v-if="checkFileType(item.url) == 'excel'"
  45. class="file"
  46. src="@/assets/common/excel.png"
  47. />
  48. <img
  49. v-if="checkFileType(item.url) == 'ppt'"
  50. class="file"
  51. src="@/assets/common/ppt.png"
  52. />
  53. <img
  54. v-if="checkFileType(item.url) == 'pdf'"
  55. class="file"
  56. src="@/assets/common/pdf.png"
  57. />
  58. <img
  59. v-if="checkFileType(item.url) == 'file'"
  60. class="file"
  61. src="@/assets/common/zip.jpeg"
  62. />
  63. </div>
  64. </el-image>
  65. <div v-show="item.hover" class="mask">
  66. <i
  67. v-if="checkFileType(item.url) == 'image'"
  68. class="el-icon-zoom-in"
  69. @click="previewImage(item.url)"
  70. />
  71. <i class="el-icon-upload2" @click="uploadImage(item.url)" />
  72. <i class="el-icon-delete" @click="deleteImage(item.url)" />
  73. </div>
  74. </div>
  75. </div>
  76. <div
  77. v-if="multiple || (!multiple && fileList.length < 1)"
  78. class="add"
  79. @click="uploadImage()"
  80. >
  81. <i class="el-icon-plus" />
  82. </div>
  83. </div>
  84. </div>
  85. </template>
  86. <script>
  87. import { getOssConfig } from "@/api/common";
  88. import { findElem } from "@/utils/util";
  89. export default {
  90. name: "FileUpload",
  91. props: {
  92. // 接受上传的文件列表
  93. fileList: Array,
  94. // 接受上传的文件类型
  95. fileType: {
  96. type: Array,
  97. default: () => ["image", "word", "excel", "ppt", "pdf", "file"],
  98. },
  99. // 是否支持多选文件
  100. multiple: {
  101. type: Boolean,
  102. default: false,
  103. },
  104. startRestricting: {
  105. type: Boolean,
  106. default: false,
  107. },
  108. restrictFilename: {
  109. type: Array,
  110. default: () => {
  111. return [];
  112. },
  113. },
  114. },
  115. data() {
  116. return {
  117. imageURL: this.$imageUrl,
  118. oss_url: "",
  119. dataObj: {},
  120. uploadImageUrl: "",
  121. waitUploadList: [],
  122. fileName: "",
  123. };
  124. },
  125. computed: {
  126. isShowFileList: {
  127. get: function () {
  128. if (this.fileList.length > 0 && this.fileList[0].url) {
  129. return true;
  130. } else {
  131. return false;
  132. }
  133. },
  134. set: function (newValue) {},
  135. },
  136. accept() {
  137. const imageList = [".jpg", ".jpeg", ".png"];
  138. const videoList = [".mp4"];
  139. const wordList = [".doc", ".docx", ".dot", ".wps", ".wpt"];
  140. const excelList = [".xls", ".xlsx", ".xlt", ".et", ".ett"];
  141. const pptList = [".ppt", ".pptx", ".dps", ".dpt", ".pot", ".pps"];
  142. const pdfList = [".pdf"];
  143. const fileList = [".zip", ".rar", ".gz", ".apk"];
  144. let whiteList = [];
  145. this.fileType.includes("image") &&
  146. (whiteList = whiteList.concat(imageList));
  147. this.fileType.includes("video") &&
  148. (whiteList = whiteList.concat(videoList));
  149. this.fileType.includes("word") &&
  150. (whiteList = whiteList.concat(wordList));
  151. this.fileType.includes("excel") &&
  152. (whiteList = whiteList.concat(excelList));
  153. this.fileType.includes("ppt") && (whiteList = whiteList.concat(pptList));
  154. this.fileType.includes("pdf") && (whiteList = whiteList.concat(pdfList));
  155. this.fileType.includes("file") &&
  156. (whiteList = whiteList.concat(fileList));
  157. return whiteList.join(",");
  158. },
  159. previewImages() {
  160. const fileList = [];
  161. if (this.fileList && this.fileList.length > 0) {
  162. this.fileList.forEach((item) => {
  163. if (this.checkFileType(item.url) == "image") {
  164. fileList.push(this.imageURL + item.url);
  165. }
  166. });
  167. }
  168. return fileList;
  169. },
  170. },
  171. created() {
  172. getOssConfig().then((res) => {
  173. this.oss_url = res.data.host;
  174. });
  175. },
  176. methods: {
  177. getUUID() {
  178. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
  179. return (
  180. c === "x" ? (Math.random() * 16) | 0 : "r&0x3" | "0x8"
  181. ).toString(16);
  182. });
  183. },
  184. createName(name) {
  185. const date = Date.now();
  186. const uuid = this.getUUID();
  187. const fileSuffix = name.substring(name.lastIndexOf(".") + 1);
  188. return `${date}${uuid}.${fileSuffix}`;
  189. },
  190. // 检查文件类型
  191. checkFileType(url) {
  192. if (!url) return "";
  193. const fileSuffix = url.substring(url.lastIndexOf(".") + 1);
  194. if (["jpg", "jpeg", "png"].includes(fileSuffix)) {
  195. return "image";
  196. } else if (["doc", "docx", "dot", "wps", "wpt"].includes(fileSuffix)) {
  197. return "word";
  198. } else if (["xls", "xlsx", "xlt", "et", "ett"].includes(fileSuffix)) {
  199. return "excel";
  200. } else if (
  201. ["ppt", "pptx", "dps", "dpt", "pot", "pps"].includes(fileSuffix)
  202. ) {
  203. return "ppt";
  204. } else if (["pdf"].includes(fileSuffix)) {
  205. return "pdf";
  206. } else if (["zip", "rar", "gz", "apk"].includes(fileSuffix)) {
  207. return "file";
  208. }
  209. {
  210. return "pdf";
  211. }
  212. },
  213. // 获取oss配置
  214. async getOssConfig(fileName) {
  215. const result = await new Promise((resolve, reject) => {
  216. getOssConfig()
  217. .then((res) => {
  218. const fileKey = this.createName(fileName);
  219. res.data.name = fileName;
  220. res.data.key = res.data.dir + fileKey;
  221. resolve(res.data);
  222. })
  223. .catch((res) => {
  224. resolve({});
  225. });
  226. });
  227. return result;
  228. },
  229. // 预览图片
  230. previewImage(url) {
  231. const index = findElem(this.fileList, "url", url);
  232. this.$refs.img[index].showViewer = true;
  233. },
  234. // 删除图片
  235. deleteImage(url) {
  236. const index = findElem(this.fileList, "url", url);
  237. this.fileList.splice(index, 1);
  238. },
  239. // 点击上传
  240. uploadImage(url) {
  241. this.uploadImageUrl = url;
  242. document.querySelector(".uploader input").click();
  243. },
  244. // 上传文件之前
  245. async beforeUpload(file) {
  246. const loading = this.$loading({
  247. lock: true,
  248. text: "Loading",
  249. spinner: "el-icon-loading",
  250. background: "rgba(0, 0, 0, 0.7)",
  251. });
  252. this.getFileName(file.name);
  253. this.$emit("handleIsFileName", this.fileName);
  254. this.dataObj = await this.getOssConfig(this.fileName);
  255. console.log(this.dataObj, "ppp");
  256. this.waitUploadList.push(this.dataObj);
  257. },
  258. // 文件上传成功
  259. uploadSuccess(res, file) {
  260. const loading = this.$loading({
  261. lock: true,
  262. text: "Loading",
  263. spinner: "el-icon-loading",
  264. background: "rgba(0, 0, 0, 0.7)",
  265. });
  266. if (this.uploadImageUrl) {
  267. const index = findElem(this.fileList, "url", this.uploadImageUrl);
  268. this.$set(this.fileList, index, {
  269. name: this.dataObj.name,
  270. url: this.dataObj.key,
  271. hover: false,
  272. });
  273. this.waitUploadList = [];
  274. } else {
  275. this.getFileName(file.name);
  276. const index = findElem(this.waitUploadList, "name", this.fileName);
  277. this.fileList.push({
  278. name: this.waitUploadList[index].name,
  279. url: this.waitUploadList[index].key,
  280. hover: false,
  281. });
  282. this.waitUploadList.splice(index, 1);
  283. }
  284. this.showFileList = true;
  285. loading.close();
  286. },
  287. getFileName(name) {
  288. const fileName = name.substring(0, name.lastIndexOf("."));
  289. let suffix = name.match(/.[^.]+$/)[0];
  290. console.log(suffix, fileName);
  291. // 押金申请上传限制
  292. this.fileName = name;
  293. if (this.startRestricting) {
  294. // 检查是否存在相应文字,否filterKeywords.length = 0
  295. const filterKeywords = this.restrictFilename.filter((k) =>
  296. fileName.includes(k)
  297. );
  298. // filterKeywords = 0 || 'zip', 'rar', 'gz', 'apk' 归为 其他文件
  299. if (
  300. !filterKeywords.length ||
  301. suffix.includes("zip", "rar", "gz", "apk")
  302. ) {
  303. this.fileName = `其他文件${suffix}`;
  304. }
  305. // 限制照片/相片名称统一为照片 , restrictFilename[restrictFilename.length-1|restrictFilename.length-1]为照片、相片
  306. if (fileName.includes("相片") || fileName.includes("照片")) {
  307. this.fileName = `照片${suffix}`;
  308. }
  309. }
  310. },
  311. },
  312. };
  313. </script>
  314. <style scoped lang="scss">
  315. .images {
  316. display: flex;
  317. flex-wrap: wrap;
  318. .item {
  319. margin-right: 20px;
  320. .img {
  321. width: 120px;
  322. height: 120px;
  323. border-radius: 5px;
  324. overflow: hidden;
  325. position: relative;
  326. border: 1px dashed #eaeaea;
  327. display: flex;
  328. .el-image {
  329. display: block;
  330. }
  331. .file {
  332. width: 120px;
  333. height: 120px;
  334. display: block;
  335. padding: 30px;
  336. }
  337. .mask {
  338. position: absolute;
  339. left: 0;
  340. top: 0;
  341. width: 120px;
  342. height: 120px;
  343. background: rgba($color: #000000, $alpha: 0.3);
  344. display: flex;
  345. align-items: center;
  346. justify-content: center;
  347. i {
  348. font-size: 20px;
  349. color: #ffffff;
  350. cursor: pointer;
  351. margin: 0 8px;
  352. }
  353. }
  354. }
  355. }
  356. .add {
  357. width: 120px;
  358. height: 120px;
  359. border: 1px dashed #eaeaea;
  360. border-radius: 5px;
  361. cursor: pointer;
  362. display: flex;
  363. align-items: center;
  364. justify-content: center;
  365. i {
  366. font-size: 30px;
  367. color: #999;
  368. }
  369. }
  370. }
  371. .uploader {
  372. height: 0;
  373. }
  374. </style>