PosterUpload.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <div>
  3. <div :id="'upload-wrapper-' + name" class="upload-wrapper" :style="uploadStyle">
  4. <img v-if="src" :src="src" oncontextmenu="return false;" />
  5. <div v-else class="upload-default">
  6. 点击上传
  7. </div>
  8. <div v-if="loading" class="loading">
  9. <i class="el-icon-loading"></i>
  10. </div>
  11. </div>
  12. <avatar-cropper
  13. ref="cropper"
  14. @submit="loading = true"
  15. @uploaded="handleUploaded"
  16. :trigger="'#upload-wrapper-' + name"
  17. :cropper-options="cropperOptions"
  18. :output-options="outputOptions"
  19. :output-quality="1"
  20. :upload-url="uploadUrl"
  21. :labels="{ submit: '确认', cancel: '取消' }"
  22. :upload-headers="headers"
  23. />
  24. <div class="tips">
  25. <slot name="tips"></slot>
  26. </div>
  27. </div>
  28. </template>
  29. <script>
  30. import resolveUrl from 'resolve-url';
  31. import AvatarCropper from 'vue-avatar-cropper';
  32. export default {
  33. props: {
  34. value: {},
  35. width: {
  36. type: Number,
  37. default: 400
  38. },
  39. height: {
  40. type: Number,
  41. default: 400
  42. },
  43. ratio: {
  44. type: Array,
  45. default: () => {
  46. [1, 1];
  47. }
  48. },
  49. imgWidth: {
  50. type: Number,
  51. default: 100
  52. },
  53. name: {
  54. type: String,
  55. default: ''
  56. }
  57. },
  58. created() {
  59. this.uploadUrl = resolveUrl(this.$baseUrl, 'upload/file');
  60. if (this.value) {
  61. this.src = this.value;
  62. }
  63. },
  64. mounted() {
  65. document.body.appendChild(this.$refs.cropper.$el);
  66. },
  67. beforeDestroy() {
  68. document.body.removeChild(this.$refs.cropper.$el);
  69. },
  70. data() {
  71. return {
  72. uploadUrl: '',
  73. src: '',
  74. loading: false,
  75. headers: {
  76. // Authorization: 'Bearer ' + localStorage.getItem('token'),
  77. }
  78. };
  79. },
  80. computed: {
  81. outputOptions() {
  82. return { width: this.width * 2, height: this.height * 2 };
  83. },
  84. cropperOptions() {
  85. return {
  86. aspectRatio: Number((this.ratio[0] / this.ratio[1]).toFixed(2)),
  87. viewMode: 2,
  88. guides: false,
  89. modal: false,
  90. autoCropArea: 1
  91. };
  92. },
  93. uploadStyle() {
  94. return {
  95. width: this.imgWidth + 'px',
  96. height: (this.imgWidth * this.ratio[1]) / this.ratio[0] + 'px'
  97. };
  98. }
  99. },
  100. watch: {
  101. value() {
  102. if (this.value !== this.src) {
  103. this.src = this.value;
  104. }
  105. }
  106. },
  107. methods: {
  108. handleUploaded(res) {
  109. this.loading = false;
  110. this.src = res;
  111. this.$emit('input', res);
  112. }
  113. },
  114. components: {
  115. AvatarCropper
  116. }
  117. };
  118. </script>
  119. <style lang="scss" scoped>
  120. .upload-wrapper {
  121. width: 178px;
  122. height: 178px;
  123. display: block;
  124. border: 1px dashed #d9d9d9;
  125. // border-radius: 6px;
  126. cursor: pointer;
  127. position: relative;
  128. overflow: hidden;
  129. img {
  130. width: 100%;
  131. height: 100%;
  132. }
  133. &:hover {
  134. border-color: #409eff;
  135. .upload-default {
  136. color: #409eff;
  137. }
  138. }
  139. }
  140. .avatar-uploader-icon {
  141. font-size: 28px;
  142. color: #8c939d;
  143. width: 178px;
  144. height: 178px;
  145. line-height: 178px;
  146. text-align: center;
  147. cursor: pointer;
  148. position: relative;
  149. overflow: hidden;
  150. background-color: #fbfdff;
  151. }
  152. .loading {
  153. position: absolute;
  154. top: 0;
  155. bottom: 0;
  156. left: 0;
  157. right: 0;
  158. margin: auto;
  159. display: flex;
  160. align-items: center;
  161. justify-content: center;
  162. background: rgba(255, 255, 255, 0.6);
  163. color: #333;
  164. font-size: 24px;
  165. }
  166. .upload-default {
  167. width: 100%;
  168. height: 100%;
  169. display: flex;
  170. align-items: center;
  171. justify-content: center;
  172. background-color: #f5f7fa;
  173. color: #bcc1cc;
  174. font-size: 12px;
  175. }
  176. .tips {
  177. font-size: 12px;
  178. font-weight: 400;
  179. color: #bcc1cc;
  180. line-height: 17px;
  181. margin-top: 12px;
  182. }
  183. </style>