邃芒官网、邃芒慧影、口播(H5) https://m.metavatar.cc
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

377 line
11 KiB

  1. <template>
  2. <div class="uploder">
  3. <div class="change-photo-setter" style="height: 240px; width: 160px">
  4. <van-uploader ref="uploader" class="sett-item" :before-read="beforeRead" style="height: 240px; width: 160px">
  5. <div style="height: 240px; width: 160px">
  6. <!-- <img :src="ImgUrl" alt="" /> -->
  7. </div>
  8. </van-uploader>
  9. </div>
  10. <div class="uploadava">
  11. <!-- van-popup有bug,某些1情况需要绑定app为根 -->
  12. <van-popup :get-container="this.isAndroid ? '' : '#app'" class="vanPopup" duration="0" v-model="showCropper" position="top" :style="{ height: '100%' }">
  13. <div class="cropper-container" :style="{ height: '92vh', position: 'relative' }">
  14. <van-loading v-show="loadingShow" size="50" color="#fff" vertical text-color="#fff">上传中...</van-loading>
  15. <!-- 切图组件 -->
  16. <!-- :outputSize="option.outputSize" -->
  17. <vueCropper
  18. :style="{ backgroundImage: 'none', height: '92vh' }"
  19. ref="cropper"
  20. :img="option.img"
  21. :outputSize="option.outputSize"
  22. :outputType="option.outputType"
  23. :info="option.info"
  24. :full="option.full"
  25. :autoCropWidth="option.autoCropWidth"
  26. :autoCropHeight="option.autoCropHeight"
  27. :canMove="option.canMove"
  28. :canMoveBox="option.canMoveBox"
  29. :original="option.original"
  30. :autoCrop="option.autoCrop"
  31. :fixed="option.fixed"
  32. :fixedNumber="option.fixedNumber"
  33. :centerBox="option.centerBox"
  34. :infoTrue="option.infoTrue"
  35. :fixedBox="option.fixedBox"
  36. :high="option.high"
  37. :mode="option.mode" />
  38. <!-- <div style="display: flex; justify-content: space-between; padding: 10px; height: 8vh">
  39. <div @click="onClickLeft">取消</div>
  40. <div @click="onClickRight">确定</div>
  41. </div> -->
  42. <van-nav-bar :style="{ height: '8vh', width: '100%', position: 'absolute' }" left-text="取消" right-text="确定" @click-left="onClickLeft" @click-right="onClickRight" />
  43. </div>
  44. </van-popup>
  45. </div>
  46. </div>
  47. </template>
  48. <script>
  49. import { awsImgUpload } from '@/api/editModel';
  50. import { Toast } from 'vant';
  51. import { VueCropper } from 'vue-cropper';
  52. import { scrollToID, getDeviceType } from '../utils';
  53. import { saveImgApi } from '../api/editModel';
  54. import { watch } from 'vue';
  55. export default {
  56. name: 'uploadAva',
  57. components: {
  58. VueCropper
  59. },
  60. props: {
  61. showAta: {
  62. default: false,
  63. type: Boolean
  64. },
  65. avaUrl: {
  66. default: '',
  67. type: String
  68. },
  69. type: {
  70. default: '',
  71. type: Number
  72. },
  73. videoType: {
  74. default: null,
  75. type: Number
  76. }
  77. },
  78. data() {
  79. return {
  80. isAndroid: false, //判断是不是ios
  81. aaa: null,
  82. ImgUrl: '',
  83. show: true, // 上传类型的弹窗
  84. imageFileName: '',
  85. showCropper: false, // 裁剪的弹窗
  86. option: {
  87. img: '',
  88. outputSize: 0.5, //图片质量
  89. info: false, // 裁剪框的大小信息
  90. // outputType: 'jpeg', // 裁剪生成图片的格式
  91. outputType: 'png', // 裁剪生成图片的格式
  92. canScale: true, // 图片是否允许滚轮缩放
  93. autoCrop: true, // 是否默认生成截图框
  94. autoCropWidth: window.innerWidth - 100 + 'px', // 默认生成截图框宽度
  95. autoCropHeight: window.innerWidth - 100 + 'px', // 默认生成截图框高度
  96. high: true, // 是否按照设备的dpr 输出等比例图片
  97. fixedBox: false, // 固定截图框大小 不允许改变
  98. fixed: false, // 是否开启截图框宽高固定比例
  99. // fixedNumber: [1, 1], // 截图框的宽高比例
  100. full: true, // 是否输出原图比例的截图
  101. canMoveBox: true, // 截图框能否拖动
  102. original: false, // 上传图片按照原始比例渲染
  103. centerBox: true, // 截图框是否被限制在图片里面
  104. infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
  105. mode: '100% auto' // 图片默认渲染方式
  106. },
  107. loadingShow: false // 是否展示loading
  108. };
  109. },
  110. created() {
  111. const deviceType = getDeviceType();
  112. this.isAndroid = false;
  113. if (!deviceType) {
  114. // 设备类型为pc
  115. this.isAndroid = false;
  116. } else {
  117. if (deviceType[0] == 'Android') {
  118. // 设备类型为安卓
  119. this.isAndroid = true;
  120. } else {
  121. // 其他设备
  122. this.isAndroid = false;
  123. }
  124. }
  125. if (this.type == 4 && this.videoType == 1) {
  126. this.option.autoCropWidth = 1080 + 'px'; // 默认生成截图框宽度
  127. this.option.autoCropHeight = 1920 + 'px'; // 默认生成截图框高度
  128. this.option.fixed = true;
  129. this.option.fixedNumber = [1080, 1920];
  130. }
  131. if (this.type == 4 && this.videoType == 2) {
  132. this.option.autoCropWidth = 1920 + 'px'; // 默认生成截图框宽度
  133. this.option.autoCropHeight = 1080 + 'px'; // 默认生成截图框高度
  134. this.option.fixed = true;
  135. this.option.fixedNumber = [1920, 1080];
  136. }
  137. },
  138. methods: {
  139. beforeRead(file) {
  140. // console.log(file)
  141. if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
  142. this.$toast('请上传 jpg/png 格式图片');
  143. return false;
  144. }
  145. // let data = window.URL.createObjectURL(new Blob([file]));
  146. let data = window.URL.createObjectURL(file);
  147. console.log(data);
  148. this.option.img = data; //给裁剪图片的路径
  149. this.showCropper = true;
  150. return false;
  151. },
  152. // 点击裁剪的选择
  153. onClickRight() {
  154. const timestamp = Date.now();
  155. let that = this;
  156. this.loadingShow = true;
  157. // console.log(this.$refs.cropper);
  158. this.$refs.cropper.getCropData(data => {
  159. // do something
  160. // console.log(data, 'base64');
  161. });
  162. this.$refs.cropper.getCropBlob(async data => {
  163. console.log(data, '上传图片数据');
  164. // 利用canvas压缩图片
  165. const img = new Image();
  166. img.src = URL.createObjectURL(data);
  167. const canvas = document.createElement('canvas');
  168. const context = canvas.getContext('2d');
  169. const getCanvasData = new Promise((resolve, reject) => {
  170. img.onload = function () {
  171. canvas.width = img.width;
  172. canvas.height = img.height;
  173. context.drawImage(img, 0, 0);
  174. canvas.toBlob(
  175. function (compressedBlob) {
  176. resolve(compressedBlob);
  177. },
  178. 0.5
  179. ); // 指定导出的图像类型和压缩质量
  180. };
  181. });
  182. // img.src = URL.createObjectURL(data);
  183. const canvasData = await getCanvasData;
  184. // ---------------------------------------------
  185. let formData = new FormData();
  186. // formData.append('file', data, timestamp + '.png');
  187. console.log(canvasData, '压缩图片数据');
  188. formData.append('file', canvasData, timestamp + '.png');
  189. that.loading = false;
  190. // console.log(that.ImgUrl, 'dasdasd')
  191. // 发请求
  192. const AccessToken = localStorage.getItem('AccessToken');
  193. that
  194. .$axios({
  195. method: 'post',
  196. url: process.env.VUE_APP_API_ROOT + `/api/upload/awsImgUpload`,
  197. headers: {
  198. 'content-type': 'multipart/form-data',
  199. token: AccessToken,
  200. 'Access-Control-Allow-Credentials': true
  201. },
  202. data: formData
  203. })
  204. .then(async res => {
  205. // console.log(res.data.data.url)
  206. const res1 = await saveImgApi({
  207. type: that.type,
  208. videoType: that.videoType,
  209. material: res.data.data.url
  210. });
  211. // 重新获取列表
  212. await that.$parent.$parent.getMyBGIListApi();
  213. await that.$parent.$parent.getMyScListApi();
  214. if (this.type == 4) {
  215. that.$parent.$parent.changeShowBGIList(1);
  216. }
  217. if (this.type == 5) {
  218. that.$parent.$parent.changeShowBGIList(3);
  219. }
  220. that.loadingShow = false;
  221. that.showCropper = false;
  222. Toast.success('上传成功');
  223. });
  224. });
  225. },
  226. // 点击取消
  227. onClickLeft() {
  228. this.loadingShow = false;
  229. this.showCropper = false;
  230. this.$parent.showPhotoUploader = false;
  231. },
  232. // 上传图片
  233. async pushImg(data) {
  234. try {
  235. const res = await awsImgUpload(data);
  236. this.loadingShow = false;
  237. this.showCropper = false;
  238. Toast.success('上传成功');
  239. } catch (error) {
  240. console.log(error, 'error');
  241. Toast.fail(error.message);
  242. }
  243. },
  244. //图片转base64,异步
  245. toBase64(file) {
  246. let that = this;
  247. return new Promise((resolve, reject) => {
  248. const reader = new FileReader();
  249. reader.onload = () => {
  250. // base64结果
  251. that.ImgUrl = this.result;
  252. that.loading = false;
  253. };
  254. reader.onerror = reject;
  255. reader.readAsDataURL(file);
  256. });
  257. },
  258. // base64 转二进制
  259. base64ToBinary(base64) {
  260. const binaryStr = window.atob(base64);
  261. const len = binaryStr.length;
  262. const bytes = new Uint8Array(len);
  263. for (let i = 0; i < len; ++i) {
  264. bytes[i] = binaryStr.charCodeAt(i);
  265. }
  266. return bytes;
  267. }
  268. },
  269. mounted() {}
  270. };
  271. </script>
  272. <style lang="scss" scoped>
  273. // /deep/.cropper-container {
  274. // z-index: 2005 !important;
  275. // }
  276. // .uploder{
  277. // overflow: hidden;
  278. // }
  279. /deep/.van-nav-bar__content {
  280. height: 8vh;
  281. background-color: #ccc;
  282. }
  283. /deep/.van-hairline--bottom::after {
  284. // height: 8vh;
  285. }
  286. /deep/.cropper-view-box {
  287. outline: 2px dashed #fff !important;
  288. }
  289. /deep/.crop-point {
  290. background-color: auto !important;
  291. }
  292. /deep/.van-loading {
  293. position: absolute;
  294. // color: red;
  295. z-index: 9999;
  296. left: 50%;
  297. top: 50%;
  298. margin-left: -55px;
  299. margin-top: -30px;
  300. background: rgba(0, 0, 0, 0.3);
  301. padding: 10px 30px;
  302. border-radius: 25px;
  303. }
  304. .uploadava {
  305. // width: 100%;
  306. // width: 100vw;
  307. height: 94vh;
  308. .update-avatar {
  309. height: 100%;
  310. text-align: center;
  311. .update-avatar-line {
  312. width: 100%;
  313. height: 1px;
  314. background-color: #979797;
  315. }
  316. .avatar-select-type {
  317. background-color: #fff;
  318. width: 346px;
  319. border-radius: 12px;
  320. padding-bottom: 4px;
  321. .upload-avator {
  322. padding: 14px;
  323. }
  324. }
  325. p {
  326. margin: 15px 0 30px;
  327. background-color: #fff;
  328. width: 346px;
  329. border-radius: 12px;
  330. padding: 15px 0 18px;
  331. }
  332. }
  333. .cropper-container {
  334. position: relative;
  335. width: 100%;
  336. height: 94vh;
  337. // height: 100%;
  338. /deep/ .van-nav-bar {
  339. position: absolute;
  340. z-index: 999;
  341. width: 100%;
  342. bottom: 0px;
  343. left: 0px;
  344. height: 6vh;
  345. background-color: rgba(0, 0, 0, 0.87);
  346. :global(.van-nav-bar__text) {
  347. color: #000;
  348. // font-size: $font-size-normal-x;
  349. }
  350. :global(.van-nav-bar__text:nth-child(2)) {
  351. color: #000;
  352. font-weight: 500;
  353. }
  354. // :global(.van-icon) {
  355. // color: red;
  356. // }
  357. }
  358. }
  359. .vue-cropper {
  360. background: #000;
  361. width: 100%;
  362. height: 88vh;
  363. padding-top: 46px;
  364. box-sizing: border-box;
  365. }
  366. }
  367. </style>