en-upload.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. <template>
  2. <view class="con">
  3. <movable-area class="area" :style="{ height: areaHeight }" @mouseenter="mouseenter" @mouseleave="mouseleave">
  4. <block v-for="(item, index) in imageList" :key="item.id">
  5. <movable-view class="view" :x="item.x" :y="item.y" direction="all" :damping="40"
  6. :disabled="item.disable" @change="onChange($event, item)" @touchstart="touchstart(item)"
  7. @mousedown="touchstart(item)" @touchend="touchend(item)" @mouseup="touchend(item)"
  8. :style="{ width: viewWidth + 'px', height: viewWidth + 'px', 'z-index': item.zIndex, opacity: item.opacity }">
  9. <view class="area-con" @click.stop="examineImgOne(index)"
  10. :style="{ width: childWidth, height: childWidth, transform: 'scale(' + item.scale + ')' }">
  11. <image class="pre-image"
  12. :src="item.src+(imgType===1?'':'?x-oss-process=video/snapshot,t_7000,f_jpg,w_600,h_0,m_fast')"
  13. mode="aspectFill"></image>
  14. <text v-if="imgType===2" class="bf-img iconfont"> &#xea82;</text>
  15. <view class="del-con" @click.stop="delImage(item, index)"
  16. @touchstart.stop="delImageMp(item, index)" @touchend.stop="nothing()"
  17. @mousedown.stop="nothing()" @mouseup.stop="nothing()">
  18. <view class="del-wrap">
  19. <!-- <image class="del-image"-->
  20. <!-- src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAhdEVYdENyZWF0aW9uIFRpbWUAMjAyMDowNzoyNSAyMTo1NDoyOU4TkJAAAADcSURBVFhH7ZfRCoMwDEXLvkjwwVf/bH/emmAyN6glTW9WBjsgwm28OeCLpj81Sil7zvlJ90UiONS/yY5VogsO6XrBg3IEQ5a/s8vRSWUAKmLqp2w5jz5BiNQEGMo3GbloDLtFXJ1IkaEuhAiiY6gEIqB4yqACSk9piIBiKQ8VUFpLviKg3C2rESKgWERCBZSWiEfgIfffYvrrsAgoISJ3Apy3zuTxcSxLQkV6ykNEPKVQkZEyiAiiZKgDIaC4upACSlcn5fM/+WuDCAHF1E/Z/N9AhkMZnPNDPI+UDjPIXgAQIGjNAAAAAElFTkSuQmCC">-->
  21. <!-- </image>-->
  22. <text class="del-image iconfont"> &#xe603;</text>
  23. </view>
  24. </view>
  25. </view>
  26. </movable-view>
  27. </block>
  28. <view class="add" v-if="imageList.length < number"
  29. :style="{ top: add.y, left: add.x, width: viewWidth + 'px', height: viewWidth + 'px' }"
  30. @click="selectMultimedia">
  31. <view class="add-wrap" :style="{ width: childWidth, height: childWidth }">
  32. <view class="video-data">
  33. <text class="video-img iconfont">&#xe658;</text>
  34. </view>
  35. </view>
  36. </view>
  37. </movable-area>
  38. </view>
  39. </template>
  40. <script>
  41. import tools from "@/service/tools";
  42. import {
  43. upLoadingFileOss
  44. } from "@/service/upLoadingFile";
  45. export default {
  46. components: {
  47. },
  48. data() {
  49. return {
  50. imageList: [],
  51. previewList: [],
  52. width: 0,
  53. add: {
  54. x: 0,
  55. y: 0
  56. },
  57. current: 0,
  58. colsValue: 0,
  59. viewWidth: 0,
  60. tempItem: null,
  61. timer: null,
  62. changeStatus: true,
  63. preStatus: true,
  64. ossClient: null
  65. }
  66. },
  67. props: {
  68. // 返回排序后图片
  69. list: {
  70. type: Array,
  71. default: function() {
  72. return []
  73. }
  74. },
  75. imgType: {
  76. type: Number,
  77. default: 1
  78. },
  79. fileNum: {
  80. type: Number,
  81. default: 9
  82. },
  83. // 选择图片数量限制
  84. number: {
  85. type: Number,
  86. default: 100
  87. },
  88. // 图片父容器宽度(实际显示的图片宽度为 imageWidth / 1.1 ),单位 rpx
  89. imageWidth: {
  90. type: Number,
  91. default: 230
  92. },
  93. // 图片列数(cols > 0 则 imageWidth 无效)
  94. cols: {
  95. type: Number,
  96. default: 0
  97. },
  98. // 图片周围空白填充,单位 rpx
  99. padding: {
  100. type: Number,
  101. default: 10
  102. },
  103. // 拖动图片时放大倍数 [0, ∞)
  104. scale: {
  105. type: Number,
  106. default: 1.1
  107. },
  108. // 拖动图片时不透明度
  109. opacity: {
  110. type: Number,
  111. default: 0.7
  112. },
  113. // 自定义添加(需配合 @aaddImage 事件使用)
  114. custom: {
  115. type: Boolean,
  116. default: false
  117. }
  118. },
  119. computed: {
  120. areaHeight() {
  121. if (this.imageList.length < this.number) {
  122. return Math.ceil((this.imageList.length + 1) / this.colsValue) * this.viewWidth + 'px'
  123. } else {
  124. return Math.ceil(this.imageList.length / this.colsValue) * this.viewWidth + 'px'
  125. }
  126. },
  127. childWidth() {
  128. return this.viewWidth - this.rpx2px(this.padding) * 2 + 'px'
  129. },
  130. },
  131. created() {
  132. this.width = uni.getSystemInfoSync().windowWidth
  133. this.viewWidth = this.rpx2px(this.imageWidth)
  134. },
  135. mounted() {
  136. const query = uni.createSelectorQuery().in(this)
  137. query.select('.area').boundingClientRect(data => {
  138. this.colsValue = Math.floor(data.width / this.viewWidth)
  139. if (this.cols > 0) {
  140. this.colsValue = this.cols
  141. this.viewWidth = data.width / this.cols
  142. }
  143. for (let item of this.list) {
  144. this.addProperties(item)
  145. }
  146. })
  147. query.exec()
  148. },
  149. methods: {
  150. examineImgOne(index) {
  151. // this.$emit('examineImgOne',index)
  152. // this.previewList = this.list
  153. // this.current = index
  154. // this.$refs.previewImage.open(index);
  155. let imgList = []
  156. this.imageList.forEach((item) => {
  157. console.log(item)
  158. imgList.push(item.src)
  159. })
  160. uni.previewImage({
  161. urls: imgList,
  162. current: index,
  163. success: () => {
  164. }
  165. })
  166. },
  167. startList(imgList) {
  168. if (imgList.length <= 0) {
  169. let maxImageNum = this.imageList.length
  170. if (maxImageNum > 0) {
  171. for (let i = maxImageNum; i > 0; --i) {
  172. let keyNum = i - 1;
  173. this.delImage(this.imageList[keyNum], keyNum)
  174. }
  175. }
  176. } else {
  177. imgList.forEach((item) => {
  178. this.addProperties(item)
  179. })
  180. }
  181. },
  182. onChange(e, item) {
  183. if (!item) return
  184. item.oldX = e.detail.x
  185. item.oldY = e.detail.y
  186. if (e.detail.source === 'touch') {
  187. if (item.moveEnd) {
  188. item.offset = Math.sqrt(Math.pow(item.oldX - item.absX * this.viewWidth, 2) + Math.pow(item.oldY -
  189. item
  190. .absY * this.viewWidth, 2))
  191. }
  192. let x = Math.floor((e.detail.x + this.viewWidth / 2) / this.viewWidth)
  193. if (x >= this.colsValue) return
  194. let y = Math.floor((e.detail.y + this.viewWidth / 2) / this.viewWidth)
  195. let index = this.colsValue * y + x
  196. if (item.index != index && index < this.imageList.length) {
  197. this.changeStatus = false
  198. for (let obj of this.imageList) {
  199. if (item.index > index && obj.index >= index && obj.index < item.index) {
  200. this.change(obj, 1)
  201. } else if (item.index < index && obj.index <= index && obj.index > item.index) {
  202. this.change(obj, -1)
  203. } else if (obj.id != item.id) {
  204. obj.offset = 0
  205. obj.x = obj.oldX
  206. obj.y = obj.oldY
  207. setTimeout(() => {
  208. this.$nextTick(() => {
  209. obj.x = obj.absX * this.viewWidth
  210. obj.y = obj.absY * this.viewWidth
  211. })
  212. }, 0)
  213. }
  214. }
  215. item.index = index
  216. item.absX = x
  217. item.absY = y
  218. this.sortList()
  219. }
  220. }
  221. },
  222. change(obj, i) {
  223. obj.index += i
  224. obj.offset = 0
  225. obj.x = obj.oldX
  226. obj.y = obj.oldY
  227. obj.absX = obj.index % this.colsValue
  228. obj.absY = Math.floor(obj.index / this.colsValue)
  229. setTimeout(() => {
  230. this.$nextTick(() => {
  231. obj.x = obj.absX * this.viewWidth
  232. obj.y = obj.absY * this.viewWidth
  233. })
  234. }, 0)
  235. },
  236. touchstart(item) {
  237. this.imageList.forEach(v => {
  238. v.zIndex = v.index + 9
  239. })
  240. item.zIndex = 99
  241. item.moveEnd = true
  242. this.tempItem = item
  243. this.timer = setTimeout(() => {
  244. item.scale = this.scale
  245. item.opacity = this.opacity
  246. clearTimeout(this.timer)
  247. this.timer = null
  248. }, 200)
  249. },
  250. touchend(item) {
  251. this.previewImage(item)
  252. item.scale = 1
  253. item.opacity = 1
  254. item.x = item.oldX
  255. item.y = item.oldY
  256. item.offset = 0
  257. item.moveEnd = false
  258. setTimeout(() => {
  259. this.$nextTick(() => {
  260. item.x = item.absX * this.viewWidth
  261. item.y = item.absY * this.viewWidth
  262. this.tempItem = null
  263. this.changeStatus = true
  264. })
  265. }, 0)
  266. },
  267. previewImage(item) {
  268. console.log(item)
  269. if (this.timer && this.preStatus && this.changeStatus && item.offset < 28.28) {
  270. clearTimeout(this.timer)
  271. this.timer = null
  272. let src = this.list.findIndex(v => v === item.src)
  273. uni.previewImage({
  274. urls: this.list,
  275. current: src,
  276. success: () => {
  277. this.preStatus = false
  278. setTimeout(() => {
  279. this.preStatus = true
  280. }, 600)
  281. }
  282. })
  283. } else if (this.timer) {
  284. clearTimeout(this.timer)
  285. this.timer = null
  286. }
  287. },
  288. mouseenter() {
  289. //#ifdef H5
  290. this.imageList.forEach(v => {
  291. v.disable = false
  292. })
  293. //#endif
  294. },
  295. mouseleave() {
  296. //#ifdef H5
  297. if (this.tempItem) {
  298. this.imageList.forEach(v => {
  299. v.disable = true
  300. v.zIndex = v.index + 1
  301. v.offset = 0
  302. v.moveEnd = false
  303. if (v.id == this.tempItem.id) {
  304. if (this.timer) {
  305. clearTimeout(this.timer)
  306. this.timer = null
  307. }
  308. v.scale = 1
  309. v.opacity = 1
  310. v.x = v.oldX
  311. v.y = v.oldY
  312. this.$nextTick(() => {
  313. v.x = v.absX * this.viewWidth
  314. v.y = v.absY * this.viewWidth
  315. this.tempItem = null
  316. })
  317. }
  318. })
  319. this.changeStatus = true
  320. }
  321. //#endif
  322. },
  323. selectMultimedia() {
  324. if (this.imgType === 1) {
  325. //图片选择
  326. this.uploadingImg();
  327. } else {
  328. //视频选择
  329. this.uploadingVideo();
  330. }
  331. },
  332. uploadingImg() {
  333. if (this.list.length > 100) {
  334. tools.error('最多上传100张')
  335. return;
  336. }
  337. uni.chooseImage({
  338. count: this.fileNum, //默认9
  339. sizeType: 'original', //可以指定是原图还是压缩图,默认二者都有 'camera' : 'album'
  340. sourceType: ['album'],
  341. success: (res) => {
  342. console.log(res.tempFiles)
  343. if (res.tempFiles !== undefined) {
  344. console.log(res.tempFiles)
  345. console.log('--------------------')
  346. res.tempFiles.forEach((file) => {
  347. console.log(file.size,"+++++++++++++");
  348. if (this.list.length > 100) {
  349. tools.error('最多上传100张')
  350. } else {
  351. console.log('--aaaaaaaaaa------------------')
  352. if (tools.getPlatform() === 'H5') {
  353. this.uploadingFile(file);
  354. } else {
  355. this.uploadingFile(file.path);
  356. }
  357. }
  358. })
  359. }
  360. },
  361. fail: (e) => {
  362. console.log(e)
  363. }
  364. });
  365. },
  366. uploadingVideo() {
  367. uni.chooseVideo({
  368. sourceType: ['album'],
  369. maxDuration: 60,
  370. success: (res) => {
  371. console.log(res)
  372. this.uploadingFile(res.tempFile);
  373. }
  374. });
  375. },
  376. uploadingFile(file) {
  377. //图片上传
  378. tools.showLoading();
  379. console.log('----------------asdsa')
  380. upLoadingFileOss(file).then((res) => {
  381. console.log('----------------------上传成功')
  382. console.log(res)
  383. if (res) {
  384. console.log(res)
  385. console.log('------------url')
  386. this.addProperties(res)
  387. tools.hideLoading();
  388. } else {
  389. tools.hideLoading();
  390. tools.error('上传失败')
  391. }
  392. }).catch((err) => {
  393. tools.hideLoading();
  394. })
  395. },
  396. addImages() {
  397. if (this.custom) {
  398. this.$emit('addImage')
  399. } else {
  400. let checkNumber = this.number - this.imageList.length
  401. uni.chooseImage({
  402. count: checkNumber,
  403. sourceType: ['album', 'camera'],
  404. success: res => {
  405. let count = checkNumber <= res.tempFilePaths.length ? checkNumber : res
  406. .tempFilePaths.length
  407. for (let i = 0; i < count; i++) {
  408. this.addProperties(res.tempFilePaths[i])
  409. }
  410. }
  411. })
  412. }
  413. },
  414. addImage(image) {
  415. this.addProperties(image)
  416. },
  417. delImage(item, index) {
  418. tools.showLoading()
  419. this.imageList.splice(index, 1)
  420. for (let obj of this.imageList) {
  421. if (obj.index > item.index) {
  422. obj.index -= 1
  423. obj.x = obj.oldX
  424. obj.y = obj.oldY
  425. obj.absX = obj.index % this.colsValue
  426. obj.absY = Math.floor(obj.index / this.colsValue)
  427. this.$nextTick(() => {
  428. obj.x = obj.absX * this.viewWidth
  429. obj.y = obj.absY * this.viewWidth
  430. })
  431. }
  432. }
  433. this.add.x = (this.imageList.length % this.colsValue) * this.viewWidth + 'px'
  434. this.add.y = Math.floor(this.imageList.length / this.colsValue) * this.viewWidth + 'px'
  435. this.sortList()
  436. },
  437. delImageMp(item, index) {
  438. //#ifdef MP
  439. this.delImage(item, index)
  440. //#endif
  441. },
  442. sortList() {
  443. let list = this.imageList.slice()
  444. list.sort((a, b) => {
  445. return a.index - b.index
  446. })
  447. for (let i = 0; i < list.length; i++) {
  448. list[i] = list[i].src
  449. }
  450. setTimeout(() => {
  451. tools.hideLoading()
  452. }, 500)
  453. // this.$emit('update:list', list)
  454. this.$emit('input', list)
  455. },
  456. addProperties(item) {
  457. console.log('------------------addProperties')
  458. console.log(item)
  459. let absX = this.imageList.length % this.colsValue
  460. let absY = Math.floor(this.imageList.length / this.colsValue)
  461. let x = absX * this.viewWidth
  462. let y = absY * this.viewWidth
  463. this.imageList.push({
  464. src: item,
  465. x,
  466. y,
  467. oldX: x,
  468. oldY: y,
  469. absX,
  470. absY,
  471. scale: 1,
  472. zIndex: 9,
  473. opacity: 1,
  474. index: this.imageList.length,
  475. id: this.guid(),
  476. disable: false,
  477. offset: 0,
  478. moveEnd: false
  479. })
  480. this.add.x = (this.imageList.length % this.colsValue) * this.viewWidth + 'px'
  481. this.add.y = Math.floor(this.imageList.length / this.colsValue) * this.viewWidth + 'px'
  482. this.sortList()
  483. },
  484. nothing() {},
  485. rpx2px(v) {
  486. return this.width * v / 750
  487. },
  488. guid() {
  489. function S4() {
  490. return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  491. }
  492. return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
  493. }
  494. }
  495. }
  496. </script>
  497. <style lang="scss" scoped>
  498. @import url("../../static/css/en-common.css");
  499. .con {
  500. padding: 30rpx;
  501. .area {
  502. width: 100%;
  503. .view {
  504. display: flex;
  505. justify-content: center;
  506. align-items: center;
  507. .area-con {
  508. position: relative;
  509. .pre-image {
  510. width: 100%;
  511. height: 100%;
  512. border-radius: 10rpx;
  513. }
  514. .bf-img {
  515. width: 40rpx;
  516. height: 40rpx;
  517. position: absolute;
  518. left: 50%;
  519. top: 50%;
  520. //margin: -20rpx 0 0 -20rpx;
  521. z-index: 2;
  522. }
  523. .del-con {
  524. position: absolute;
  525. top: 5rpx;
  526. right: 5rpx;
  527. //padding: 0 0 20rpx 20rpx;
  528. .del-wrap {
  529. width: 36rpx;
  530. height: 36rpx;
  531. //background-color: rgba(0, 0, 0, 0.4);
  532. border-radius: 0 0 0 10rpx;
  533. display: flex;
  534. justify-content: center;
  535. align-items: center;
  536. .del-image {
  537. //width: 20rpx;
  538. //height: 20rpx;
  539. }
  540. }
  541. }
  542. }
  543. }
  544. .add {
  545. position: absolute;
  546. display: flex;
  547. justify-content: center;
  548. align-items: center;
  549. .add-wrap {
  550. // display: flex;
  551. // justify-content: center;
  552. // align-items: center;
  553. background: #F7F7F7;
  554. border-radius: 10rpx;
  555. .add-img {
  556. width: 80rpx;
  557. height: 80rpx;
  558. margin: 0 auto;
  559. padding-top: 44rpx;
  560. }
  561. .names {
  562. color: #6F6F6F;
  563. font-size: 28rpx;
  564. text-align: center;
  565. }
  566. .video-data {
  567. width: 212rpx;
  568. height: 212rpx;
  569. //background-color: #fff;
  570. text-align: center;
  571. line-height: 212rpx;
  572. .video-img {
  573. font-size: 100rpx;
  574. color: #333333;
  575. }
  576. }
  577. }
  578. }
  579. }
  580. }
  581. </style>