index.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <template>
  2. <div class="ant-upload-preview">
  3. <div style="width: 100%">
  4. <el-upload
  5. ref="upload"
  6. class="avatar-uploader"
  7. :class="[disabled ? 'uploadDisabled' : null]"
  8. :disabled="disabled"
  9. :accept="accept"
  10. :show-file-list="false"
  11. :action="ossUploadUrl"
  12. :data="dataObj"
  13. :before-upload="beforeUpload"
  14. :http-request="handleChange"
  15. >
  16. <i
  17. v-if="isDelete && imageUrl"
  18. class="el-icon-error"
  19. @click.stop="onDelete"
  20. style="
  21. position: absolute;
  22. right: -14px;
  23. font-size: 24px;
  24. top: -14px;
  25. color: #787878;
  26. background: #fff;
  27. "
  28. ></i>
  29. <img v-if="imageUrl" :src="imageUrl" class="avatar" :style="showBox" />
  30. <span v-else>
  31. <i
  32. v-if="loading"
  33. class="el-icon-loading avatar-uploader-icon"
  34. :style="showBox"
  35. ></i>
  36. <i
  37. v-else
  38. class="el-icon-plus avatar-uploader-icon"
  39. :style="showBox"
  40. ></i>
  41. <span class="upload-desc">添加上传图片</span>
  42. </span>
  43. </el-upload>
  44. </div>
  45. <!-- modal -->
  46. <cropper-modal
  47. ref="CropperModal"
  48. @cropper-no="handleCropperClose"
  49. @cropper-ok="handleCropperSuccess"
  50. ></cropper-modal>
  51. </div>
  52. </template>
  53. <script>
  54. import CropperModal from "./CropperModal";
  55. import { policy } from "@/api/appTenant";
  56. import axios from "axios";
  57. export default {
  58. name: "ImageCropper",
  59. components: {
  60. CropperModal,
  61. },
  62. props: {
  63. //图片裁切配置
  64. options: {
  65. type: Object,
  66. default: function () {
  67. return {
  68. autoCrop: true, //是否默认生成截图框
  69. enlarge: 1, // 图片放大倍数
  70. autoCropWidth: 200, //默认生成截图框宽度
  71. autoCropHeight: 200, //默认生成截图框高度
  72. fixedBox: false, //是否固定截图框大小 不允许改变
  73. previewsCircle: true, //预览图是否是原圆形
  74. title: "上传图片",
  75. };
  76. },
  77. },
  78. // 显示图片原始图片
  79. showSize: {
  80. type: Boolean,
  81. default: false,
  82. },
  83. // 上传图片的大小,单位M
  84. imgSize: {
  85. type: Number,
  86. default: 2,
  87. },
  88. isDelete: {
  89. type: Boolean,
  90. default: false,
  91. },
  92. // 图片地址
  93. imageUrl: {
  94. type: String,
  95. default: "",
  96. },
  97. // 默认图片格式
  98. accept: {
  99. type: String,
  100. default: ".png,.jpg,.jpeg,.gif",
  101. },
  102. acceptArray: {
  103. type: [Array, Object],
  104. default() {
  105. return ["image/jpeg", "image/png", "image/jpg", "image/gif"];
  106. },
  107. },
  108. disabled: {
  109. type: Boolean,
  110. default: false,
  111. },
  112. bucket_name: {
  113. type: String,
  114. default: "daya",
  115. },
  116. },
  117. data() {
  118. return {
  119. loading: false,
  120. isStopRun: false,
  121. info: null,
  122. ossUploadUrl: "https://ks3-cn-beijing.ksyuncs.com/" + this.bucket_name,
  123. dataObj: {
  124. policy: "",
  125. signature: "",
  126. key: "",
  127. KSSAccessKeyId: "",
  128. // dir: "",
  129. acl: "public-read",
  130. name: "",
  131. },
  132. };
  133. },
  134. computed: {
  135. showBox() {
  136. let styleList = {};
  137. if (this.showSize) {
  138. styleList = {
  139. width: this.options.autoCropWidth + "px",
  140. height: this.options.autoCropHeight + "px",
  141. lineHeight: this.options.autoCropHeight + "px",
  142. };
  143. }
  144. console.log(styleList);
  145. return styleList;
  146. },
  147. },
  148. methods: {
  149. onDelete() {
  150. // 删除图片
  151. this.$emit("update:imageUrl", "");
  152. },
  153. //从本地选择文件
  154. async handleChange(info) {
  155. // 缓存原始数据信息
  156. this.info = info;
  157. if (this.isStopRun) {
  158. return;
  159. }
  160. this.loading = true;
  161. // ---
  162. //----
  163. const { options } = this;
  164. this.getBase64(info.file, (imageUrl) => {
  165. const target = Object.assign({}, options, {
  166. img: imageUrl,
  167. name: info.file.name, // 上传文件名
  168. });
  169. this.$refs.CropperModal.edit(target);
  170. });
  171. },
  172. // 上传之前 格式与大小校验
  173. beforeUpload(file) {
  174. this.isStopRun = false;
  175. var fileType = file.type;
  176. if (fileType.indexOf("image") < 0) {
  177. this.$message.warning("请上传图片");
  178. this.isStopRun = true;
  179. return false;
  180. }
  181. const isJpgOrPng = this.acceptArray.includes(file.type);
  182. // file.type === 'image/jpeg' ||
  183. // file.type === 'image/png' ||
  184. // file.type === 'image/jpg'
  185. if (!isJpgOrPng) {
  186. this.$message.error("你上传图片格式不正确!");
  187. this.isStopRun = true;
  188. }
  189. const isLtSize = file.size < this.imgSize * 1024 * 1024;
  190. if (!isLtSize) {
  191. this.$message.error("图片大小不能超过" + this.imgSize + "MB!");
  192. this.isStopRun = true;
  193. }
  194. return isJpgOrPng && isLtSize;
  195. },
  196. async handleCropperSuccess(data) {
  197. // 开始上传数据
  198. let { action, headers, filename } = this.info;
  199. let fileName = this.info.file.name.replaceAll(" ", "_");
  200. const formData = new FormData();
  201. try {
  202. let key = new Date().getTime() + fileName;
  203. let obj = {
  204. filename: fileName,
  205. bucketName: this.bucket_name,
  206. postData: {
  207. filename: fileName,
  208. acl: "public-read",
  209. key: key,
  210. unknowValueField: [],
  211. },
  212. };
  213. const res = await policy(obj);
  214. this.dataObj = {
  215. policy: res.data.policy,
  216. signature: res.data.signature,
  217. key: key,
  218. KSSAccessKeyId: res.data.kssAccessKeyId,
  219. acl: "public-read",
  220. name: fileName,
  221. };
  222. for (let key in this.dataObj) {
  223. formData.append(key, this.dataObj[key]);
  224. }
  225. formData.append(filename, data, fileName);
  226. console.log(this.ossUploadUrl, "this.ossUploadUrl", action);
  227. axios
  228. .post(action, formData, {
  229. ...headers,
  230. })
  231. .then((res) => {
  232. let url = this.ossUploadUrl + "/" + this.dataObj.key;
  233. if (url) {
  234. // filelist.value = [
  235. // {
  236. // name: url,
  237. // url: url,
  238. // },
  239. // ];
  240. // resValues.value = url;
  241. let data = {
  242. data: {
  243. url: url,
  244. },
  245. };
  246. this.loading = false;
  247. this.$emit("crop-upload-success", data);
  248. CropperModal.value.closeVisible();
  249. } else {
  250. this.handleCropperClose();
  251. // ElMessage.error(res.msg || '上传失败')
  252. }
  253. })
  254. .catch((e) => {
  255. // console.log(e, '失败')
  256. this.handleCropperClose();
  257. });
  258. //putObject
  259. } catch (err) {
  260. this.handleCropperClose();
  261. this.$message.error("上传失败");
  262. }
  263. //将返回的数据回显
  264. },
  265. // 取消上传
  266. handleCropperClose() {
  267. this.loading = false;
  268. this.$emit("crop-upload-close");
  269. },
  270. getBase64(img, callback) {
  271. const reader = new FileReader();
  272. reader.addEventListener("load", () => callback(reader.result));
  273. reader.readAsDataURL(img);
  274. },
  275. },
  276. };
  277. </script>
  278. <style lang="scss" scoped>
  279. .ant-upload-preview {
  280. background-color: #fff;
  281. .avatar-uploader {
  282. .upload-desc {
  283. position: absolute;
  284. bottom: 0;
  285. left: 0;
  286. color: #ccc;
  287. font-size: 8px;
  288. right: 0;
  289. }
  290. }
  291. }
  292. ::v-deep .avatar-uploader .el-upload--text {
  293. border: 1px dashed #d9d9d9;
  294. border-radius: 6px;
  295. margin-right: 20px;
  296. cursor: pointer;
  297. position: relative;
  298. // overflow: hidden;
  299. }
  300. ::v-deep .avatar-uploader.uploadDisabled {
  301. .el-upload--text {
  302. cursor: not-allowed;
  303. background-color: #f7f7f7;
  304. }
  305. .el-upload:hover {
  306. border-color: #d9d9d9;
  307. }
  308. }
  309. ::v-deep .avatar-uploader .el-upload:hover {
  310. border-color: #409eff;
  311. }
  312. ::v-deep .avatar-uploader-icon {
  313. font-size: 22px;
  314. color: #ccc;
  315. width: 108px;
  316. height: 108px;
  317. line-height: 108px;
  318. text-align: center;
  319. }
  320. ::v-deep.avatar {
  321. width: 108px;
  322. height: 108px;
  323. display: block;
  324. }
  325. </style>