当前位置:   article > 正文

vue实现H5拖拽可视化编辑器_vue可视化h5拖拽编辑器

vue可视化h5拖拽编辑器

一款专注可视化平台工具,功能强大,高可扩展的HTML5可视化编辑器,致力于提供一套简单易用、高效创新、无限可能的解决方案。技术栈采用vue和typescript开发, 专注研发创新工具。 

  1. <template>
  2. <div
  3. :style="style"
  4. :class="[{
  5. [classNameActive]: enabled,
  6. [classNameDragging]: dragging,
  7. [classNameResizing]: resizing,
  8. [classNameDraggable]: draggable,
  9. [classNameResizable]: resizable
  10. }, className]"
  11. @click="$emit('click')"
  12. @mousedown="elementMouseDown"
  13. @touchstart="elementTouchDown"
  14. @contextmenu="onContextMenu">
  15. <div
  16. v-for="handle in actualHandles"
  17. :key="handle"
  18. :class="[classNameHandle, classNameHandle + '-' + handle]"
  19. :style="handleStyle(handle)"
  20. @mousedown.stop.prevent="handleDown(handle, $event)"
  21. @touchstart.stop.prevent="handleTouchDown(handle, $event)">
  22. <slot :name="handle"></slot>
  23. </div>
  24. <slot></slot>
  25. </div>
  26. </template>
  27. <script>
  28. import { matchesSelectorToParentElements, getComputedSize, addEvent, removeEvent } from './utils/dom'
  29. import { computeWidth, computeHeight, restrictToBounds, snapToGrid } from './utils/fns'
  30. const events = {
  31. mouse: {
  32. start: 'mousedown',
  33. move: 'mousemove',
  34. stop: 'mouseup'
  35. },
  36. touch: {
  37. start: 'touchstart',
  38. move: 'touchmove',
  39. stop: 'touchend'
  40. }
  41. }
  42. // 禁止用户选取
  43. const userSelectNone = {
  44. userSelect: 'none',
  45. MozUserSelect: 'none',
  46. WebkitUserSelect: 'none',
  47. MsUserSelect: 'none'
  48. }
  49. // 用户选中自动
  50. const userSelectAuto = {
  51. userSelect: 'auto',
  52. MozUserSelect: 'auto',
  53. WebkitUserSelect: 'auto',
  54. MsUserSelect: 'auto'
  55. }
  56. let eventsFor = events.mouse
  57. export default {
  58. replace: true,
  59. name: 'draggable-resizable',
  60. props: {
  61. rotateZ: {
  62. type: Number,
  63. default: 0
  64. },
  65. className: {
  66. type: String,
  67. default: 'vdr'
  68. },
  69. classNameDraggable: {
  70. type: String,
  71. default: 'draggable'
  72. },
  73. classNameResizable: {
  74. type: String,
  75. default: 'resizable'
  76. },
  77. classNameDragging: {
  78. type: String,
  79. default: 'dragging'
  80. },
  81. classNameResizing: {
  82. type: String,
  83. default: 'resizing'
  84. },
  85. classNameActive: {
  86. type: String,
  87. default: 'active'
  88. },
  89. classNameHandle: {
  90. type: String,
  91. default: 'handle'
  92. },
  93. disableUserSelect: {
  94. type: Boolean,
  95. default: true
  96. },
  97. enableNativeDrag: {
  98. type: Boolean,
  99. default: false
  100. },
  101. preventDeactivation: {
  102. type: Boolean,
  103. default: false
  104. },
  105. active: {
  106. type: Boolean,
  107. default: false
  108. },
  109. draggable: {
  110. type: Boolean,
  111. default: true
  112. },
  113. resizable: {
  114. type: Boolean,
  115. default: true
  116. },
  117. // 锁定宽高比
  118. lockAspectRatio: {
  119. type: Boolean,
  120. default: false
  121. },
  122. w: {
  123. type: [Number, String],
  124. default: 200,
  125. validator: (val) => {
  126. if (typeof val === 'number') {
  127. return val > 0
  128. }
  129. return val === 'auto'
  130. }
  131. },
  132. h: {
  133. type: [Number, String],
  134. default: 200,
  135. validator: (val) => {
  136. if (typeof val === 'number') {
  137. return val > 0
  138. }
  139. return val === 'auto'
  140. }
  141. },
  142. minWidth: {
  143. type: Number,
  144. default: 0,
  145. validator: (val) => val >= 0
  146. },
  147. minHeight: {
  148. type: Number,
  149. default: 0,
  150. validator: (val) => val >= 0
  151. },
  152. maxWidth: {
  153. type: Number,
  154. default: null,
  155. validator: (val) => val >= 0
  156. },
  157. maxHeight: {
  158. type: Number,
  159. default: null,
  160. validator: (val) => val >= 0
  161. },
  162. x: {
  163. type: Number,
  164. default: 0
  165. },
  166. y: {
  167. type: Number,
  168. default: 0
  169. },
  170. z: {
  171. type: [String, Number],
  172. default: 'auto',
  173. validator: (val) => (typeof val === 'string' ? val === 'auto' : val >= 0)
  174. },
  175. handles: {
  176. type: Array,
  177. default: () => ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'],
  178. validator: (val) => {
  179. const s = new Set(['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'])
  180. return new Set(val.filter(h => s.has(h))).size === val.length
  181. }
  182. },
  183. dragHandle: {
  184. type: String,
  185. default: null
  186. },
  187. dragCancel: {
  188. type: String,
  189. default: null
  190. },
  191. axis: {
  192. type: String,
  193. default: 'both',
  194. validator: (val) => ['x', 'y', 'both'].includes(val)
  195. },
  196. grid: {
  197. type: Array,
  198. default: () => [1, 1]
  199. },
  200. parent: {
  201. type: [Boolean, String],
  202. default: false
  203. },
  204. onDragStart: {
  205. type: Function,
  206. default: () => true
  207. },
  208. onDrag: {
  209. type: Function,
  210. default: () => true
  211. },
  212. onResizeStart: {
  213. type: Function,
  214. default: () => true
  215. },
  216. onResize: {
  217. type: Function,
  218. default: () => true
  219. },
  220. // 冲突检测
  221. isConflictCheck: {
  222. type: Boolean,
  223. default: false
  224. },
  225. // 元素对齐
  226. snap: {
  227. type: Boolean,
  228. default: false
  229. },
  230. // 当调用对齐时,用来设置组件与组件之间的对齐距离,以像素为单位
  231. snapTolerance: {
  232. type: Number,
  233. default: 5,
  234. validator: function (val) {
  235. return typeof val === 'number'
  236. }
  237. },
  238. // 缩放比例
  239. scaleRatio: {
  240. type: Number,
  241. default: 1,
  242. validator: (val) => typeof val === 'number'
  243. },
  244. // handle是否缩放
  245. handleInfo: {
  246. type: Object,
  247. default: () => {
  248. return {
  249. size: 8,
  250. offset: -5,
  251. switch: true
  252. }
  253. }
  254. }
  255. },
  256. data: function () {
  257. return {
  258. left: this.x,
  259. top: this.y,
  260. right: null,
  261. bottom: null,
  262. width: null,
  263. height: null,
  264. widthTouched: false,
  265. heightTouched: false,
  266. aspectFactor: null,
  267. parentWidth: null,
  268. parentHeight: null,
  269. minW: this.minWidth,
  270. minH: this.minHeight,
  271. maxW: this.maxWidth,
  272. maxH: this.maxHeight,
  273. handle: null,
  274. enabled: this.active,
  275. resizing: false,
  276. dragging: false,
  277. zIndex: this.z
  278. }
  279. },
  280. created: function () {
  281. // eslint-disable-next-line 无效的prop:minWidth不能大于maxWidth
  282. if (this.maxWidth && this.minWidth > this.maxWidth) console.warn('[Vdr warn]: Invalid prop: minWidth cannot be greater than maxWidth')
  283. // eslint-disable-next-line 无效prop:minHeight不能大于maxHeight'
  284. if (this.maxWidth && this.minHeight > this.maxHeight) console.warn('[Vdr warn]: Invalid prop: minHeight cannot be greater than maxHeight')
  285. this.resetBoundsAndMouseState()
  286. },
  287. mounted: function () {
  288. if (!this.enableNativeDrag) {
  289. this.$el.ondragstart = () => false
  290. }
  291. const [parentWidth, parentHeight] = this.getParentSize()
  292. this.parentWidth = parentWidth
  293. this.parentHeight = parentHeight
  294. const [width, height] = getComputedSize(this.$el)
  295. this.aspectFactor = (this.w !== 'auto' ? this.w : width) / (this.h !== 'auto' ? this.h : height)
  296. this.width = this.w !== 'auto' ? this.w : width
  297. this.height = this.h !== 'auto' ? this.h : height
  298. this.right = this.parentWidth - this.width - this.left
  299. this.bottom = this.parentHeight - this.height - this.top
  300. this.settingAttribute()
  301. // 优化:取消选中的行为优先绑定在父节点上
  302. const parentElement = this.$el.parentNode
  303. addEvent(parentElement || document.documentElement, 'mousedown', this.deselect)
  304. addEvent(parentElement || document.documentElement, 'touchend touchcancel', this.deselect)
  305. addEvent(window, 'resize', this.checkParentSize)
  306. },
  307. beforeDestroy: function () {
  308. removeEvent(document.documentElement, 'mousedown', this.deselect)
  309. removeEvent(document.documentElement, 'touchstart', this.handleUp)
  310. removeEvent(document.documentElement, 'mousemove', this.move)
  311. removeEvent(document.documentElement, 'touchmove', this.move)
  312. removeEvent(document.documentElement, 'mouseup', this.handleUp)
  313. removeEvent(document.documentElement, 'touchend touchcancel', this.deselect)
  314. removeEvent(window, 'resize', this.checkParentSize)
  315. },
  316. methods: {
  317. // 右键菜单
  318. onContextMenu (e) {
  319. this.$emit('contextmenu', e)
  320. },
  321. // 重置边界和鼠标状态
  322. resetBoundsAndMouseState () {
  323. this.mouseClickPosition = { mouseX: 0, mouseY: 0, x: 0, y: 0, w: 0, h: 0 }
  324. this.bounds = {
  325. minLeft: null,
  326. maxLeft: null,
  327. minRight: null,
  328. maxRight: null,
  329. minTop: null,
  330. maxTop: null,
  331. minBottom: null,
  332. maxBottom: null
  333. }
  334. },
  335. // 检查父元素大小
  336. checkParentSize () {
  337. if (this.parent) {
  338. const [newParentWidth, newParentHeight] = this.getParentSize()
  339. // 修复父元素改变大小后,组件resizing时活动异常
  340. this.right = newParentWidth - this.width - this.left
  341. this.bottom = newParentHeight - this.height - this.top
  342. this.parentWidth = newParentWidth
  343. this.parentHeight = newParentHeight
  344. }
  345. },
  346. // 获取父元素大小
  347. getParentSize () {
  348. if (this.parent === true) {
  349. const style = window.getComputedStyle(this.$el.parentNode, null)
  350. return [
  351. parseInt(style.getPropertyValue('width'), 10),
  352. parseInt(style.getPropertyValue('height'), 10)
  353. ]
  354. }
  355. if (typeof this.parent === 'string') {
  356. const parentNode = document.querySelector(this.parent)
  357. if (!(parentNode instanceof HTMLElement)) {
  358. throw new Error(`The selector ${this.parent} does not match any element`)
  359. }
  360. return [parentNode.offsetWidth, parentNode.offsetHeight]
  361. }
  362. return [null, null]
  363. },
  364. // 元素触摸按下
  365. elementTouchDown (e) {
  366. eventsFor = events.touch
  367. this.elementDown(e)
  368. },
  369. elementMouseDown (e) {
  370. eventsFor = events.mouse
  371. this.elementDown(e)
  372. },
  373. // 元素按下
  374. elementDown (e) {
  375. if (e instanceof MouseEvent && e.which !== 1) {
  376. return
  377. }
  378. const target = e.target || e.srcElement
  379. if (this.$el.contains(target)) {
  380. if (this.onDragStart(e) === false) {
  381. return
  382. }
  383. if (
  384. (this.dragHandle && !matchesSelectorToParentElements(target, this.dragHandle, this.$el)) ||
  385. (this.dragCancel && matchesSelectorToParentElements(target, this.dragCancel, this.$el))
  386. ) {
  387. this.dragging = false
  388. return
  389. }
  390. if (!this.enabled) {
  391. this.enabled = true
  392. this.$emit('activated')
  393. this.$emit('update:active', true)
  394. }
  395. if (this.draggable) {
  396. this.dragging = true
  397. }
  398. this.mouseClickPosition.mouseX = e.touches ? e.touches[0].pageX : e.pageX
  399. this.mouseClickPosition.mouseY = e.touches ? e.touches[0].pageY : e.pageY
  400. this.mouseClickPosition.left = this.left
  401. this.mouseClickPosition.right = this.right
  402. this.mouseClickPosition.top = this.top
  403. this.mouseClickPosition.bottom = this.bottom
  404. this.mouseClickPosition.w = this.width
  405. this.mouseClickPosition.h = this.height
  406. if (this.parent) {
  407. this.bounds = this.calcDragLimits()
  408. }
  409. addEvent(document.documentElement, eventsFor.move, this.move)
  410. addEvent(document.documentElement, eventsFor.stop, this.handleUp)
  411. }
  412. },
  413. // 计算移动范围
  414. calcDragLimits () {
  415. return {
  416. minLeft: this.left % this.grid[0],
  417. maxLeft: Math.floor((this.parentWidth - this.width - this.left) / this.grid[0]) * this.grid[0] + this.left,
  418. minRight: this.right % this.grid[0],
  419. maxRight: Math.floor((this.parentWidth - this.width - this.right) / this.grid[0]) * this.grid[0] + this.right,
  420. minTop: this.top % this.grid[1],
  421. maxTop: Math.floor((this.parentHeight - this.height - this.top) / this.grid[1]) * this.grid[1] + this.top,
  422. minBottom: this.bottom % this.grid[1],
  423. maxBottom: Math.floor((this.parentHeight - this.height - this.bottom) / this.grid[1]) * this.grid[1] + this.bottom
  424. }
  425. },
  426. // 取消
  427. deselect (e) {
  428. const target = e.target || e.srcElement
  429. const regex = new RegExp(this.className + '-([trmbl]{2})', '')
  430. if (!this.$el.contains(target) && !regex.test(target.className)) {
  431. if (this.enabled && !this.preventDeactivation) {
  432. this.enabled = false
  433. this.$emit('deactivated')
  434. this.$emit('update:active', false)
  435. }
  436. removeEvent(document.documentElement, eventsFor.move, this.handleResize)
  437. }
  438. this.resetBoundsAndMouseState()
  439. },
  440. // 控制柄触摸按下
  441. handleTouchDown (handle, e) {
  442. eventsFor = events.touch
  443. this.handleDown(handle, e)
  444. },
  445. // 控制柄按下
  446. handleDown (handle, e) {
  447. if (e instanceof MouseEvent && e.which !== 1) {
  448. return
  449. }
  450. if (this.onResizeStart(handle, e) === false) {
  451. return
  452. }
  453. if (e.stopPropagation) e.stopPropagation()
  454. // Here we avoid a dangerous recursion by faking
  455. // corner handles as middle handles
  456. if (this.lockAspectRatio && !handle.includes('m')) {
  457. this.handle = 'm' + handle.substring(1)
  458. } else {
  459. this.handle = handle
  460. }
  461. this.resizing = true
  462. this.mouseClickPosition.mouseX = e.touches ? e.touches[0].pageX : e.pageX
  463. this.mouseClickPosition.mouseY = e.touches ? e.touches[0].pageY : e.pageY
  464. this.mouseClickPosition.left = this.left
  465. this.mouseClickPosition.right = this.right
  466. this.mouseClickPosition.top = this.top
  467. this.mouseClickPosition.bottom = this.bottom
  468. this.mouseClickPosition.w = this.width
  469. this.mouseClickPosition.h = this.height
  470. this.bounds = this.calcResizeLimits()
  471. addEvent(document.documentElement, eventsFor.move, this.handleResize)
  472. addEvent(document.documentElement, eventsFor.stop, this.handleUp)
  473. },
  474. // 计算调整大小范围
  475. calcResizeLimits () {
  476. let minW = this.minW
  477. let minH = this.minH
  478. let maxW = this.maxW
  479. let maxH = this.maxH
  480. const aspectFactor = this.aspectFactor
  481. const [gridX, gridY] = this.grid
  482. const width = this.width
  483. const height = this.height
  484. const left = this.left
  485. const top = this.top
  486. const right = this.right
  487. const bottom = this.bottom
  488. if (this.lockAspectRatio) {
  489. if (minW / minH > aspectFactor) {
  490. minH = minW / aspectFactor
  491. } else {
  492. minW = aspectFactor * minH
  493. }
  494. if (maxW && maxH) {
  495. maxW = Math.min(maxW, aspectFactor * maxH)
  496. maxH = Math.min(maxH, maxW / aspectFactor)
  497. } else if (maxW) {
  498. maxH = maxW / aspectFactor
  499. } else if (maxH) {
  500. maxW = aspectFactor * maxH
  501. }
  502. }
  503. maxW = maxW - (maxW % gridX)
  504. maxH = maxH - (maxH % gridY)
  505. const limits = {
  506. minLeft: null,
  507. maxLeft: null,
  508. minTop: null,
  509. maxTop: null,
  510. minRight: null,
  511. maxRight: null,
  512. minBottom: null,
  513. maxBottom: null
  514. }
  515. if (this.parent) {
  516. limits.minLeft = left % gridX
  517. limits.maxLeft = left + Math.floor((width - minW) / gridX) * gridX
  518. limits.minTop = top % gridY
  519. limits.maxTop = top + Math.floor((height - minH) / gridY) * gridY
  520. limits.minRight = right % gridX
  521. limits.maxRight = right + Math.floor((width - minW) / gridX) * gridX
  522. limits.minBottom = bottom % gridY
  523. limits.maxBottom = bottom + Math.floor((height - minH) / gridY) * gridY
  524. if (maxW) {
  525. limits.minLeft = Math.max(limits.minLeft, this.parentWidth - right - maxW)
  526. limits.minRight = Math.max(limits.minRight, this.parentWidth - left - maxW)
  527. }
  528. if (maxH) {
  529. limits.minTop = Math.max(limits.minTop, this.parentHeight - bottom - maxH)
  530. limits.minBottom = Math.max(limits.minBottom, this.parentHeight - top - maxH)
  531. }
  532. if (this.lockAspectRatio) {
  533. limits.minLeft = Math.max(limits.minLeft, left - top * aspectFactor)
  534. limits.minTop = Math.max(limits.minTop, top - left / aspectFactor)
  535. limits.minRight = Math.max(limits.minRight, right - bottom * aspectFactor)
  536. limits.minBottom = Math.max(limits.minBottom, bottom - right / aspectFactor)
  537. }
  538. } else {
  539. limits.minLeft = null
  540. limits.maxLeft = left + Math.floor((width - minW) / gridX) * gridX
  541. limits.minTop = null
  542. limits.maxTop = top + Math.floor((height - minH) / gridY) * gridY
  543. limits.minRight = null
  544. limits.maxRight = right + Math.floor((width - minW) / gridX) * gridX
  545. limits.minBottom = null
  546. limits.maxBottom = bottom + Math.floor((height - minH) / gridY) * gridY
  547. if (maxW) {
  548. limits.minLeft = -(right + maxW)
  549. limits.minRight = -(left + maxW)
  550. }
  551. if (maxH) {
  552. limits.minTop = -(bottom + maxH)
  553. limits.minBottom = -(top + maxH)
  554. }
  555. if (this.lockAspectRatio && (maxW && maxH)) {
  556. limits.minLeft = Math.min(limits.minLeft, -(right + maxW))
  557. limits.minTop = Math.min(limits.minTop, -(maxH + bottom))
  558. limits.minRight = Math.min(limits.minRight, -left - maxW)
  559. limits.minBottom = Math.min(limits.minBottom, -top - maxH)
  560. }
  561. }
  562. return limits
  563. },
  564. // 移动
  565. move (e) {
  566. if (this.resizing) {
  567. this.handleResize(e)
  568. } else if (this.dragging) {
  569. this.handleDrag(e)
  570. }
  571. },
  572. // 元素移动
  573. async handleDrag (e) {
  574. const axis = this.axis
  575. const grid = this.grid
  576. const bounds = this.bounds
  577. const mouseClickPosition = this.mouseClickPosition
  578. const tmpDeltaX = axis && axis !== 'y' ? mouseClickPosition.mouseX - (e.touches ? e.touches[0].pageX : e.pageX) : 0
  579. const tmpDeltaY = axis && axis !== 'x' ? mouseClickPosition.mouseY - (e.touches ? e.touches[0].pageY : e.pageY) : 0
  580. const [deltaX, deltaY] = snapToGrid(grid, tmpDeltaX, tmpDeltaY, this.scaleRatio)
  581. const left = restrictToBounds(mouseClickPosition.left - deltaX, bounds.minLeft, bounds.maxLeft)
  582. const top = restrictToBounds(mouseClickPosition.top - deltaY, bounds.minTop, bounds.maxTop)
  583. if (this.onDrag(left, top) === false) {
  584. return
  585. }
  586. const right = restrictToBounds(mouseClickPosition.right + deltaX, bounds.minRight, bounds.maxRight)
  587. const bottom = restrictToBounds(mouseClickPosition.bottom + deltaY, bounds.minBottom, bounds.maxBottom)
  588. this.left = left
  589. this.top = top
  590. this.right = right
  591. this.bottom = bottom
  592. await this.snapCheck()
  593. this.$emit('dragging', {left: this.left, top: this.top})
  594. },
  595. moveHorizontally (val) {
  596. const [deltaX, _] = snapToGrid(this.grid, val, this.top, this.scale)
  597. const left = restrictToBounds(deltaX, this.bounds.minLeft, this.bounds.maxLeft)
  598. this.left = left
  599. this.right = this.parentWidth - this.width - left
  600. },
  601. moveVertically (val) {
  602. const [_, deltaY] = snapToGrid(this.grid, this.left, val, this.scale)
  603. const top = restrictToBounds(deltaY, this.bounds.minTop, this.bounds.maxTop)
  604. this.top = top
  605. this.bottom = this.parentHeight - this.height - top
  606. },
  607. // 控制柄移动
  608. handleResize (e) {
  609. let left = this.left
  610. let top = this.top
  611. let right = this.right
  612. let bottom = this.bottom
  613. const mouseClickPosition = this.mouseClickPosition
  614. const lockAspectRatio = this.lockAspectRatio
  615. const aspectFactor = this.aspectFactor
  616. const tmpDeltaX = mouseClickPosition.mouseX - (e.touches ? e.touches[0].pageX : e.pageX)
  617. const tmpDeltaY = mouseClickPosition.mouseY - (e.touches ? e.touches[0].pageY : e.pageY)
  618. if (!this.widthTouched && tmpDeltaX) {
  619. this.widthTouched = true
  620. }
  621. if (!this.heightTouched && tmpDeltaY) {
  622. this.heightTouched = true
  623. }
  624. const [deltaX, deltaY] = snapToGrid(this.grid, tmpDeltaX, tmpDeltaY, this.scaleRatio)
  625. if (this.handle.includes('b')) {
  626. bottom = restrictToBounds(
  627. mouseClickPosition.bottom + deltaY,
  628. this.bounds.minBottom,
  629. this.bounds.maxBottom
  630. )
  631. if (this.lockAspectRatio && this.resizingOnY) {
  632. right = this.right - (this.bottom - bottom) * aspectFactor
  633. }
  634. } else if (this.handle.includes('t')) {
  635. top = restrictToBounds(
  636. mouseClickPosition.top - deltaY,
  637. this.bounds.minTop,
  638. this.bounds.maxTop
  639. )
  640. if (this.lockAspectRatio && this.resizingOnY) {
  641. left = this.left - (this.top - top) * aspectFactor
  642. }
  643. }
  644. if (this.handle.includes('r')) {
  645. right = restrictToBounds(
  646. mouseClickPosition.right + deltaX,
  647. this.bounds.minRight,
  648. this.bounds.maxRight
  649. )
  650. if (this.lockAspectRatio && this.resizingOnX) {
  651. bottom = this.bottom - (this.right - right) / aspectFactor
  652. }
  653. } else if (this.handle.includes('l')) {
  654. left = restrictToBounds(
  655. mouseClickPosition.left - deltaX,
  656. this.bounds.minLeft,
  657. this.bounds.maxLeft
  658. )
  659. if (this.lockAspectRatio && this.resizingOnX) {
  660. top = this.top - (this.left - left) / aspectFactor
  661. }
  662. }
  663. const width = computeWidth(this.parentWidth, left, right)
  664. const height = computeHeight(this.parentHeight, top, bottom)
  665. if (this.onResize(this.handle, left, top, width, height) === false) {
  666. return
  667. }
  668. this.left = left
  669. this.top = top
  670. this.right = right
  671. this.bottom = bottom
  672. this.width = width
  673. this.height = height
  674. this.$emit('resizing', {left: this.left, top: this.top, width: this.width, height: this.height})
  675. },
  676. changeWidth (val) {
  677. const [newWidth, _] = snapToGrid(this.grid, val, 0, this.scale)
  678. let right = restrictToBounds(
  679. (this.parentWidth - newWidth - this.left),
  680. this.bounds.minRight,
  681. this.bounds.maxRight
  682. )
  683. let bottom = this.bottom
  684. if (this.lockAspectRatio) {
  685. bottom = this.bottom - (this.right - right) / this.aspectFactor
  686. }
  687. const width = computeWidth(this.parentWidth, this.left, right)
  688. const height = computeHeight(this.parentHeight, this.top, bottom)
  689. this.right = right
  690. this.bottom = bottom
  691. this.width = width
  692. this.height = height
  693. },
  694. changeHeight (val) {
  695. const [_, newHeight] = snapToGrid(this.grid, 0, val, this.scale)
  696. let bottom = restrictToBounds(
  697. (this.parentHeight - newHeight - this.top),
  698. this.bounds.minBottom,
  699. this.bounds.maxBottom
  700. )
  701. let right = this.right
  702. if (this.lockAspectRatio) {
  703. right = this.right - (this.bottom - bottom) * this.aspectFactor
  704. }
  705. const width = computeWidth(this.parentWidth, this.left, right)
  706. const height = computeHeight(this.parentHeight, this.top, bottom)
  707. this.right = right
  708. this.bottom = bottom
  709. this.width = width
  710. this.height = height
  711. },
  712. // 从控制柄松开
  713. async handleUp (e) {
  714. this.handle = null
  715. // 初始化辅助线数据
  716. const temArr = new Array(3).fill({ display: false, position: '', origin: '', lineLength: '' })
  717. const refLine = { vLine: [], hLine: [] }
  718. for (let i in refLine) { refLine[i] = JSON.parse(JSON.stringify(temArr)) }
  719. if (this.resizing) {
  720. this.resizing = false
  721. await this.conflictCheck()
  722. this.$emit('refLineParams', refLine)
  723. this.$emit('resizestop', this.left, this.top, this.width, this.height)
  724. }
  725. if (this.dragging) {
  726. this.dragging = false
  727. await this.conflictCheck()
  728. this.$emit('refLineParams', refLine)
  729. this.$emit('dragstop', this.left, this.top)
  730. }
  731. this.resetBoundsAndMouseState()
  732. removeEvent(document.documentElement, eventsFor.move, this.handleResize)
  733. },
  734. // 设置属性
  735. settingAttribute () {
  736. // 设置冲突检测
  737. this.$el.setAttribute('data-is-check', `${this.isConflictCheck}`)
  738. // 设置对齐元素
  739. this.$el.setAttribute('data-is-snap', `${this.snap}`)
  740. },
  741. // 冲突检测
  742. conflictCheck () {
  743. const top = this.top
  744. const left = this.left
  745. const width = this.width
  746. const height = this.height
  747. if (this.isConflictCheck) {
  748. const nodes = this.$el.parentNode.childNodes // 获取当前父节点下所有子节点
  749. for (let item of nodes) {
  750. if (item.className !== undefined && !item.className.includes(this.classNameActive) && item.getAttribute('data-is-check') !== null && item.getAttribute('data-is-check') !== 'false') {
  751. const tw = item.offsetWidth
  752. const th = item.offsetHeight
  753. // 正则获取left与right
  754. let [tl, tt] = this.formatTransformVal(item.style.transform)
  755. // 左上角与右下角重叠
  756. const tfAndBr = (top >= tt && left >= tl && tt + th > top && tl + tw > left) || (top <= tt && left < tl && top + height > tt && left + width > tl)
  757. // 右上角与左下角重叠
  758. const brAndTf = (left <= tl && top >= tt && left + width > tl && top < tt + th) || (top < tt && left > tl && top + height > tt && left < tl + tw)
  759. // 下边与上边重叠
  760. const bAndT = (top <= tt && left >= tl && top + height > tt && left < tl + tw) || (top >= tt && left <= tl && top < tt + th && left > tl + tw)
  761. // 上边与下边重叠(宽度不一样)
  762. const tAndB = (top <= tt && left >= tl && top + height > tt && left < tl + tw) || (top >= tt && left <= tl && top < tt + th && left > tl + tw)
  763. // 左边与右边重叠
  764. const lAndR = (left >= tl && top >= tt && left < tl + tw && top < tt + th) || (top > tt && left <= tl && left + width > tl && top < tt + th)
  765. // 左边与右边重叠(高度不一样)
  766. const rAndL = (top <= tt && left >= tl && top + height > tt && left < tl + tw) || (top >= tt && left <= tl && top < tt + th && left + width > tl)
  767. // 如果冲突,就将回退到移动前的位置
  768. if (tfAndBr || brAndTf || bAndT || tAndB || lAndR || rAndL) {
  769. this.top = this.mouseClickPosition.top
  770. this.left = this.mouseClickPosition.left
  771. this.right = this.mouseClickPosition.right
  772. this.bottom = this.mouseClickPosition.bottom
  773. this.width = this.mouseClickPosition.w
  774. this.height = this.mouseClickPosition.h
  775. this.$emit('resizing', this.left, this.top, this.width, this.height)
  776. }
  777. }
  778. }
  779. }
  780. },
  781. // 检测对齐元素
  782. async snapCheck () {
  783. let width = this.width
  784. let height = this.height
  785. if (this.snap) {
  786. let activeLeft = this.left
  787. let activeRight = this.left + width
  788. let activeTop = this.top
  789. let activeBottom = this.top + height
  790. // 初始化辅助线数据
  791. const temArr = new Array(3).fill({ display: false, position: '', origin: '', lineLength: '' })
  792. const refLine = { vLine: [], hLine: [] }
  793. for (let i in refLine) { refLine[i] = JSON.parse(JSON.stringify(temArr)) }
  794. // 获取当前父节点下所有子节点
  795. const nodes = this.$el.parentNode.childNodes
  796. let tem = {
  797. value: { x: [[], [], []], y: [[], [], []] },
  798. display: [],
  799. position: []
  800. }
  801. const { groupWidth, groupHeight, groupLeft, groupTop, bln } = await this.getActiveAll(nodes)
  802. if (!bln) {
  803. width = groupWidth
  804. height = groupHeight
  805. activeLeft = groupLeft
  806. activeRight = groupLeft + groupWidth
  807. activeTop = groupTop
  808. activeBottom = groupTop + groupHeight
  809. }
  810. for (let item of nodes) {
  811. if (item.className !== undefined && !item.className.includes(this.classNameActive) && item.getAttribute('data-is-snap') !== null && item.getAttribute('data-is-snap') !== 'false') {
  812. const w = item.offsetWidth
  813. const h = item.offsetHeight
  814. const [l, t] = this.formatTransformVal(item.style.transform)
  815. const r = l + w // 对齐目标right
  816. const b = t + h // 对齐目标的bottom
  817. const hc = Math.abs((activeTop + height / 2) - (t + h / 2)) <= this.snapTolerance // 水平中线
  818. const vc = Math.abs((activeLeft + width / 2) - (l + w / 2)) <= this.snapTolerance // 垂直中线
  819. const ts = Math.abs(t - activeBottom) <= this.snapTolerance // 从上到下
  820. const TS = Math.abs(b - activeBottom) <= this.snapTolerance // 从上到下
  821. const bs = Math.abs(t - activeTop) <= this.snapTolerance // 从下到上
  822. const BS = Math.abs(b - activeTop) <= this.snapTolerance // 从下到上
  823. const ls = Math.abs(l - activeRight) <= this.snapTolerance // 外左
  824. const LS = Math.abs(r - activeRight) <= this.snapTolerance // 外左
  825. const rs = Math.abs(l - activeLeft) <= this.snapTolerance // 外右
  826. const RS = Math.abs(r - activeLeft) <= this.snapTolerance // 外右
  827. tem['display'] = [ts, TS, bs, BS, hc, hc, ls, LS, rs, RS, vc, vc]
  828. tem['position'] = [t, b, t, b, t + h / 2, t + h / 2, l, r, l, r, l + w / 2, l + w / 2]
  829. // fix:中线自动对齐,元素可能超过父元素边界的问题
  830. if (ts) {
  831. if (bln) {
  832. this.top = Math.max(t - height, this.bounds.minTop)
  833. this.bottom = this.parentHeight - this.top - height
  834. }
  835. tem.value.y[0].push(l, r, activeLeft, activeRight)
  836. }
  837. if (bs) {
  838. if (bln) {
  839. this.top = t
  840. this.bottom = this.parentHeight - this.top - height
  841. }
  842. tem.value.y[0].push(l, r, activeLeft, activeRight)
  843. }
  844. if (TS) {
  845. if (bln) {
  846. this.top = Math.max(b - height, this.bounds.minTop)
  847. this.bottom = this.parentHeight - this.top - height
  848. }
  849. tem.value.y[1].push(l, r, activeLeft, activeRight)
  850. }
  851. if (BS) {
  852. if (bln) {
  853. this.top = b
  854. this.bottom = this.parentHeight - this.top - height
  855. }
  856. tem.value.y[1].push(l, r, activeLeft, activeRight)
  857. }
  858. if (ls) {
  859. if (bln) {
  860. this.left = Math.max(l - width, this.bounds.minLeft)
  861. this.right = this.parentWidth - this.left - width
  862. }
  863. tem.value.x[0].push(t, b, activeTop, activeBottom)
  864. }
  865. if (rs) {
  866. if (bln) {
  867. this.left = l
  868. this.right = this.parentWidth - this.left - width
  869. }
  870. tem.value.x[0].push(t, b, activeTop, activeBottom)
  871. }
  872. if (LS) {
  873. if (bln) {
  874. this.left = Math.max(r - width, this.bounds.minLeft)
  875. this.right = this.parentWidth - this.left - width
  876. }
  877. tem.value.x[1].push(t, b, activeTop, activeBottom)
  878. }
  879. if (RS) {
  880. if (bln) {
  881. this.left = r
  882. this.right = this.parentWidth - this.left - width
  883. }
  884. tem.value.x[1].push(t, b, activeTop, activeBottom)
  885. }
  886. if (hc) {
  887. if (bln) {
  888. this.top = Math.max(t + h / 2 - height / 2, this.bounds.minTop)
  889. this.bottom = this.parentHeight - this.top - height
  890. }
  891. tem.value.y[2].push(l, r, activeLeft, activeRight)
  892. }
  893. if (vc) {
  894. if (bln) {
  895. this.left = Math.max(l + w / 2 - width / 2, this.bounds.minLeft)
  896. this.right = this.parentWidth - this.left - width
  897. }
  898. tem.value.x[2].push(t, b, activeTop, activeBottom)
  899. }
  900. // 辅助线坐标与是否显示(display)对应的数组,易于循环遍历
  901. const arrTem = [0, 1, 0, 1, 2, 2, 0, 1, 0, 1, 2, 2]
  902. for (let i = 0; i <= arrTem.length; i++) {
  903. // 前6为Y辅助线,后6为X辅助线
  904. const xory = i < 6 ? 'y' : 'x'
  905. const horv = i < 6 ? 'hLine' : 'vLine'
  906. if (tem.display[i]) {
  907. const { origin, length } = this.calcLineValues(tem.value[xory][arrTem[i]])
  908. refLine[horv][arrTem[i]].display = tem.display[i]
  909. refLine[horv][arrTem[i]].position = tem.position[i] + 'px'
  910. refLine[horv][arrTem[i]].origin = origin
  911. refLine[horv][arrTem[i]].lineLength = length
  912. }
  913. }
  914. }
  915. }
  916. this.$emit('refLineParams', refLine)
  917. }
  918. },
  919. calcLineValues (arr) {
  920. const length = Math.max(...arr) - Math.min(...arr) + 'px'
  921. const origin = Math.min(...arr) + 'px'
  922. return { length, origin }
  923. },
  924. async getActiveAll (nodes) {
  925. const activeAll = []
  926. const XArray = []
  927. const YArray = []
  928. let groupWidth = 0
  929. let groupHeight = 0
  930. let groupLeft = 0
  931. let groupTop = 0
  932. for (let item of nodes) {
  933. if (item.className !== undefined && item.className.includes(this.classNameActive)) {
  934. activeAll.push(item)
  935. }
  936. }
  937. const AllLength = activeAll.length
  938. if (AllLength > 1) {
  939. for (let i of activeAll) {
  940. const l = i.offsetLeft
  941. const r = l + i.offsetWidth
  942. const t = i.offsetTop
  943. const b = t + i.offsetHeight
  944. XArray.push(t, b)
  945. YArray.push(l, r)
  946. }
  947. groupWidth = Math.max(...YArray) - Math.min(...YArray)
  948. groupHeight = Math.max(...XArray) - Math.min(...XArray)
  949. groupLeft = Math.min(...YArray)
  950. groupTop = Math.min(...XArray)
  951. }
  952. const bln = AllLength === 1
  953. return { groupWidth, groupHeight, groupLeft, groupTop, bln }
  954. },
  955. // 正则获取left与top
  956. formatTransformVal (string) {
  957. let [left, top] = string.replace(/[^0-9\-,]/g, '').split(',')
  958. if (top === undefined) top = 0
  959. return [+left, +top]
  960. }
  961. },
  962. computed: {
  963. handleStyle () {
  964. return (stick) => {
  965. if (!this.handleInfo.switch) return { display: this.enabled ? 'block' : 'none' }
  966. const size = (this.handleInfo.size / this.scaleRatio).toFixed(2)
  967. const offset = (this.handleInfo.offset / this.scaleRatio).toFixed(2)
  968. const center = (size / 2).toFixed(2)
  969. const styleMap = {
  970. tl: {
  971. top: `${offset}px`,
  972. left: `${offset}px`
  973. },
  974. tm: {
  975. top: `${offset}px`,
  976. left: `calc(50% - ${center}px)`
  977. },
  978. tr: {
  979. top: `${offset}px`,
  980. right: `${offset}px`
  981. },
  982. mr: {
  983. top: `calc(50% - ${center}px)`,
  984. right: `${offset}px`
  985. },
  986. br: {
  987. bottom: `${offset}px`,
  988. right: `${offset}px`
  989. },
  990. bm: {
  991. bottom: `${offset}px`,
  992. right: `calc(50% - ${center}px)`
  993. },
  994. bl: {
  995. bottom: `${offset}px`,
  996. left: `${offset}px`
  997. },
  998. ml: {
  999. top: `calc(50% - ${center}px)`,
  1000. left: `${offset}px`
  1001. }
  1002. }
  1003. const stickStyle = {
  1004. width: `${size}px`,
  1005. height: `${size}px`,
  1006. top: styleMap[stick].top,
  1007. left: styleMap[stick].left,
  1008. right: styleMap[stick].right,
  1009. bottom: styleMap[stick].bottom
  1010. }
  1011. stickStyle.display = this.enabled ? 'block' : 'none'
  1012. return stickStyle
  1013. }
  1014. },
  1015. style () {
  1016. return {
  1017. transform: `translate(${this.left}px, ${this.top}px) rotateZ(${this.rotateZ}deg)`,
  1018. width: this.computedWidth,
  1019. height: this.computedHeight,
  1020. zIndex: this.zIndex,
  1021. ...(this.dragging && this.disableUserSelect ? userSelectNone : userSelectAuto)
  1022. }
  1023. },
  1024. // 控制柄显示与否
  1025. actualHandles () {
  1026. if (!this.resizable) return []
  1027. return this.handles
  1028. },
  1029. computedWidth () {
  1030. if (this.w === 'auto') {
  1031. if (!this.widthTouched) {
  1032. return 'auto'
  1033. }
  1034. }
  1035. return this.width + 'px'
  1036. },
  1037. computedHeight () {
  1038. if (this.h === 'auto') {
  1039. if (!this.heightTouched) {
  1040. return 'auto'
  1041. }
  1042. }
  1043. return this.height + 'px'
  1044. },
  1045. resizingOnX () {
  1046. return (Boolean(this.handle) && (this.handle.includes('l') || this.handle.includes('r')))
  1047. },
  1048. resizingOnY () {
  1049. return (Boolean(this.handle) && (this.handle.includes('t') || this.handle.includes('b')))
  1050. },
  1051. isCornerHandle () {
  1052. return (Boolean(this.handle) && ['tl', 'tr', 'br', 'bl'].includes(this.handle))
  1053. }
  1054. },
  1055. watch: {
  1056. active (val) {
  1057. this.enabled = val
  1058. if (val) {
  1059. this.$emit('activated')
  1060. } else {
  1061. this.$emit('deactivated')
  1062. }
  1063. },
  1064. z (val) {
  1065. if (val >= 0 || val === 'auto') {
  1066. this.zIndex = val
  1067. }
  1068. },
  1069. x (val) {
  1070. if (this.resizing || this.dragging) {
  1071. return
  1072. }
  1073. if (this.parent) {
  1074. this.bounds = this.calcDragLimits()
  1075. }
  1076. this.moveHorizontally(val)
  1077. },
  1078. y (val) {
  1079. if (this.resizing || this.dragging) {
  1080. return
  1081. }
  1082. if (this.parent) {
  1083. this.bounds = this.calcDragLimits()
  1084. }
  1085. this.moveVertically(val)
  1086. },
  1087. lockAspectRatio (val) {
  1088. if (val) {
  1089. this.aspectFactor = this.width / this.height
  1090. } else {
  1091. this.aspectFactor = undefined
  1092. }
  1093. },
  1094. minWidth (val) {
  1095. if (val > 0 && val <= this.width) {
  1096. this.minW = val
  1097. }
  1098. },
  1099. minHeight (val) {
  1100. if (val > 0 && val <= this.height) {
  1101. this.minH = val
  1102. }
  1103. },
  1104. maxWidth (val) {
  1105. this.maxW = val
  1106. },
  1107. maxHeight (val) {
  1108. this.maxH = val
  1109. },
  1110. w (val) {
  1111. if (this.resizing || this.dragging) {
  1112. return
  1113. }
  1114. if (this.parent) {
  1115. this.bounds = this.calcResizeLimits()
  1116. }
  1117. this.changeWidth(val)
  1118. },
  1119. h (val) {
  1120. if (this.resizing || this.dragging) {
  1121. return
  1122. }
  1123. if (this.parent) {
  1124. this.bounds = this.calcResizeLimits()
  1125. }
  1126. this.changeHeight(val)
  1127. }
  1128. }
  1129. }
  1130. </script>
  1. <template>
  2. <!--选择素材-->
  3. <el-dialog
  4. @close="$emit('cancel')"
  5. :title="$t('plugin.selectFootage')"
  6. append-to-body
  7. :close-on-click-modal="false"
  8. :visible.sync="visible">
  9. <el-form inline ref="queryForm" :model="material" size="small">
  10. <el-form-item label="分组" prop="groupId">
  11. <tree-select
  12. placeholder="请选择素材分组"
  13. :data="groupOptions"
  14. :props="defaultProps"
  15. :clearable="true"
  16. :accordion="true"
  17. @getValue="getValue"/>
  18. </el-form-item>
  19. <el-form-item label="名称" prop="name">
  20. <el-input circle v-model="material.name" placeholder="请输入素材名称"></el-input>
  21. </el-form-item>
  22. <el-form-item>
  23. <el-button icon="el-icon-search" @click="getListMaterial" type="primary">{{ $t('plugin.search') }}</el-button>
  24. <el-button icon="el-icon-refresh" @click="resetQuery">{{ $t('plugin.rest') }}</el-button>
  25. </el-form-item>
  26. </el-form>
  27. <el-radio-group
  28. @change="changeType"
  29. v-if="typeList.length > 1"
  30. style="margin-bottom: 8px;"
  31. v-model="material.type" size="small">
  32. <el-radio
  33. border
  34. :label="item"
  35. style="margin-right: 5px;"
  36. v-for="item in typeList">
  37. <span>{{ item | filterType }}</span>
  38. </el-radio>
  39. </el-radio-group>
  40. <el-row :gutter="20" v-loading="material.loading">
  41. <el-col :span="6" v-for="(item, index) in material.list">
  42. <label>
  43. <div style="background-color: #fff; width: 167px; font-weight: 400; border: 2px solid transparent;"
  44. :class="{'active-material': currentIndex.some(s => s.id == item.id)}" class="choose-file"
  45. @click="rowClick(item)">
  46. <span v-show="Number(item.duration)" class="duration">{{ item.duration }} {{ $t('plugin.second') }}</span>
  47. <span class="resolution">{{ item.resolution }}</span>
  48. <img v-if="item.type === 'image'"
  49. style="width: 100%; height: 120px;"
  50. :src="filterUrl(item)"/>
  51. <img v-if="item.type === 'file'"
  52. style="width: 100%; height: 120px;"
  53. :src="filterUrl(item)"/>
  54. <div v-if="item.type === 'audio'" style="height: 120px; width: 100%; background-color: #ecf4ff;">
  55. <svg-icon style="color: #86baff; font-size: 36px; margin: 10px;" icon-class="audio"/>
  56. </div>
  57. <video v-if="item.type === 'media'"
  58. style="height: 120px; width: 100%; object-fit: fill; vertical-align: bottom;"
  59. :disabled="true"
  60. :autoplay="false"
  61. :controls="false"
  62. :src="filterUrl(item)">
  63. {{ $t('tips.canvas') }}
  64. </video>
  65. <div class="bottom line-clamp1">
  66. <span style="margin: 0 5px;">{{ item.name }}</span>
  67. </div>
  68. </div>
  69. </label>
  70. </el-col>
  71. </el-row>
  72. <el-pagination
  73. style="margin-top: 16px;"
  74. @size-change="getListMaterial"
  75. @current-change="getListMaterial"
  76. :current-page.sync="material.current"
  77. :page-size="material.size"
  78. layout="total, prev, pager, next"
  79. :total="material.total">
  80. </el-pagination>
  81. <div style="text-align: right; margin-top: 16px;">
  82. <el-button size="small" @click="$emit('cancel')">{{ $t('tips.cancel') }}</el-button>
  83. <el-button size="small" :disabled="!currentIndex.length" type="primary" @click="confirm"> {{
  84. $t('tips.confirm')
  85. }}
  86. </el-button>
  87. </div>
  88. </el-dialog>
  89. </template>
  90. <script>
  91. import treeSelect from "./TreeSelect/index"
  92. import {request} from "@/config";
  93. import Cookies from "js-cookie";
  94. const {getMaterialList, groupTree} = request;
  95. export default {
  96. name: "material",
  97. inject: ['equipment'],
  98. components: {
  99. treeSelect
  100. },
  101. watch: {
  102. visible: {
  103. handler() {
  104. this.currentIndex = [];
  105. },
  106. deep: true,
  107. immediate: true
  108. }
  109. },
  110. props: {
  111. mode: {
  112. type: String,
  113. default: "single"
  114. }, // single、multiple
  115. ids: {
  116. type: Array,
  117. default() {
  118. return []
  119. }
  120. },
  121. title: {
  122. type: String,
  123. default: "选择素材"
  124. },
  125. visible: {
  126. type: Boolean,
  127. default: false
  128. },
  129. typeList: {
  130. type: Array,
  131. default() {
  132. return ["image"]
  133. }
  134. }
  135. },
  136. filters: {
  137. filterType(data) {
  138. const typeList = [
  139. {label: "图片", name: "image"},
  140. {label: "视频", name: "media"},
  141. {label: "音频", name: "audio"}];
  142. const vo = typeList.find(item => data === item.name);
  143. const {label, name} = vo;
  144. const language = Cookies.get('language') || "zh"
  145. return language === 'zh' ? label : name;
  146. }
  147. },
  148. computed: {
  149. currentType() {
  150. return this.typeList.length ? this.typeList[0] : ""
  151. }
  152. },
  153. data() {
  154. const type = this.typeList[0]
  155. return {
  156. defaultProps: {
  157. value: 'id',
  158. label: 'name',
  159. children: 'children'
  160. },
  161. groupOptions: [],
  162. empty: require("@/assets/images/empty-img.png"),
  163. currentIndex: [],
  164. material: {
  165. name: "",
  166. groupId: "",
  167. type: type,
  168. list: [],
  169. current: 1,
  170. total: 0,
  171. size: 20,
  172. loading: false,
  173. data: []
  174. },
  175. baseUrl: sessionStorage.getItem('baseUrl')
  176. }
  177. },
  178. methods: {
  179. getValue(value) {
  180. this.material.groupId = value;
  181. this.getListMaterial();
  182. },
  183. getTree() {
  184. groupTree({type: '0'}).then(response => {
  185. this.groupOptions = response.data
  186. })
  187. },
  188. changeType() {
  189. this.material.current = 1;
  190. this.getListMaterial();
  191. },
  192. filterUrl(data) {
  193. const {decodedUrl, originalUrl} = data;
  194. return data ? `${this.baseUrl}${decodedUrl || originalUrl}` : this.empty;
  195. },
  196. rowClick(data) {
  197. if (this.mode === "multiple") {
  198. if (this.currentIndex.some(item => item.id == data.id)) {
  199. this.currentIndex = this.currentIndex.filter(item => item.id !== data.id);
  200. } else {
  201. this.currentIndex.push(data)
  202. }
  203. } else {
  204. this.currentIndex = [data]
  205. }
  206. },
  207. confirm() {
  208. let array = JSON.parse(JSON.stringify(this.currentIndex));
  209. this.material.data = [];
  210. let flag = false;
  211. array.forEach(data => {
  212. const {decodedUrl, originalUrl} = data;
  213. data.url = `${this.baseUrl}${decodedUrl || originalUrl}`
  214. if (data.addition) {
  215. data.addition = data.addition.split(",").map(item => this.baseUrl + item);
  216. } else {
  217. flag = true;
  218. }
  219. this.material.data.push(data);
  220. })
  221. if (flag && this.currentType === 'file') {
  222. return this.$notify.warning("当前文档未转换成功")
  223. }
  224. if (this.mode === "multiple") {
  225. this.$emit("confirm", this.material.data);
  226. } else {
  227. const data = this.material.data;
  228. this.$emit("confirm", data.length ? data[0] : {});
  229. }
  230. },
  231. getListMaterial() {
  232. this.material.loading = true;
  233. if (!Number(this.material.groupId)) {
  234. this.material.groupId = "";
  235. }
  236. getMaterialList({
  237. name: this.material.name,
  238. groupId: this.material.groupId,
  239. type: this.material.type,
  240. current: this.material.current,
  241. size: this.material.size
  242. }).then(response => {
  243. const {total, data} = response;
  244. if (data) {
  245. data.forEach((item, index) => {
  246. if (item.type === 'file') {
  247. const list = item.addition ? item.addition.split(",") : [""]
  248. data[index].decodedUrl = list[0];
  249. }
  250. })
  251. this.material.list = data;
  252. this.material.total = total;
  253. }
  254. this.material.loading = false;
  255. })
  256. },
  257. resetQuery() {
  258. this.$refs.queryForm.resetFields();
  259. this.material.current = 1;
  260. this.material.groupId = "";
  261. this.getListMaterial();
  262. }
  263. },
  264. created() {
  265. if (!this.equipment) {
  266. this.getListMaterial();
  267. this.getTree();
  268. }
  269. }
  270. }
  271. </script>
  272. <style>
  273. .active-material {
  274. transition: .3s;
  275. background-color: #ecf4ff !important;
  276. border: 3px solid #409eff !important;
  277. }
  278. </style>

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/214443
推荐阅读
相关标签
  

闽ICP备14008679号