layout.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. <template>
  2. <div class="ibps-desktop-page">
  3. <ibps-grid-layout
  4. v-if="layout && layout.length >0"
  5. :layout.sync="layout"
  6. :col-num="colNum"
  7. :row-height="rowHeight"
  8. :is-draggable="readonly?false:isDraggable"
  9. :is-resizable="readonly?false:isResizable"
  10. :is-mirrored="isMirrored"
  11. :vertical-compact="verticalCompact"
  12. :margin="margin"
  13. :use-css-transforms="useCssTransforms"
  14. :responsive="responsive"
  15. >
  16. <ibps-grid-item
  17. v-for="(item ,index) in layout"
  18. :key="item.i"
  19. :x="item.x"
  20. :y="item.y"
  21. :w="item.w"
  22. :h="item.h"
  23. :i="item.i"
  24. @resize="resizeEvent"
  25. @move="moveEvent"
  26. >
  27. <div v-if="hasComponent(item.alias)" class="ibps-grid-item">
  28. <div v-if="!readonly" class="ibps-grid-item-tools">
  29. <span class="drag el-button el-button--primary el-button--mini">
  30. <i class="ibps-icon-crosshairs" /> 拖动
  31. </span>
  32. <el-button
  33. class="remove"
  34. size="mini"
  35. type="danger"
  36. icon="ibps-icon-remove"
  37. @click="handleRemove(item,index)"
  38. >删除</el-button>
  39. </div>
  40. <component
  41. :is="'ibps-desktop-'+item.alias"
  42. :id="item.i"
  43. :alias="item.alias"
  44. :height="getHeight(item.h)"
  45. @action-event="(command,data)=> handleActionEvent(command,data,index)"
  46. />
  47. </div>
  48. </ibps-grid-item>
  49. </ibps-grid-layout>
  50. <el-alert
  51. v-else
  52. :closable="false"
  53. :title="emptyText"
  54. type="warning"
  55. show-icon
  56. style="height:50px"
  57. />
  58. <add-column
  59. :visible="dialogVisible"
  60. @close="closeDialog"
  61. @confirm="handleAddConfirm"
  62. />
  63. <preview
  64. :id="id"
  65. :visible="dialogPreviewVisible"
  66. :screen="screen"
  67. title="全屏预览"
  68. @close="visible => dialogPreviewVisible = visible"
  69. />
  70. </div>
  71. </template>
  72. <script>
  73. import { isInit, getComponents } from '@/views/system/dashboard/components'
  74. // 网格布局组件
  75. import { GridLayout, GridItem } from 'vue-grid-layout'
  76. import AddColumn from './add-column'
  77. import Preview from '@/views/platform/desktop/column/preview'
  78. export default {
  79. components: {
  80. 'ibps-grid-layout': GridLayout,
  81. 'ibps-grid-item': GridItem,
  82. AddColumn,
  83. Preview
  84. },
  85. props: {
  86. data: {
  87. type: Array,
  88. default: () => []
  89. },
  90. emptyText: {
  91. type: String
  92. },
  93. open: {
  94. type: Boolean
  95. },
  96. readonly: {
  97. type: Boolean,
  98. default: false
  99. },
  100. visible: Boolean,
  101. ectypal: {
  102. type: Array,
  103. default: () => []
  104. }
  105. },
  106. data () {
  107. return {
  108. autoSize: true, // 是否根据内容确定容器的高度
  109. colNum: 24, // 列数
  110. rowHeight: 30, // 行高
  111. margin: [15, 15], // 两个可移动元素间的距离
  112. // maxRows: 99999999999, // 最大的行高
  113. useCssTransforms: true, // 是否使用自定义的过渡效果
  114. isDraggable: true, // 是否支持推拽
  115. isResizable: true, // 是否支持改变大小
  116. isMirrored: false, // if the RTL/LTR should be reversed.
  117. verticalCompact: true, // 是否使用verticalCompact(垂直紧凑)布局
  118. responsive: false, // 响应式布局
  119. layout: [],
  120. dialogPreviewVisible: false, // 预览
  121. id: '',
  122. defaultData: [],
  123. screen: true,
  124. shrink: false,
  125. dialogVisible: false
  126. }
  127. },
  128. watch: {
  129. open (val, oldVal) {
  130. if (val) {
  131. this.fetchData()
  132. }
  133. },
  134. data () {
  135. this.layout = JSON.parse(JSON.stringify(this.data))
  136. },
  137. ectypal () {
  138. this.defaultData = JSON.parse(JSON.stringify(this.ectypal))
  139. },
  140. visible: {
  141. handler: function (val, oldVal) {
  142. this.dialogVisible = this.visible
  143. },
  144. immediate: true
  145. }
  146. },
  147. mounted () {
  148. this.fetchData()
  149. },
  150. methods: {
  151. // 调整大小时的事件
  152. resizeEvent (i, newH, newW, newHPx, newWPx) {
  153. const index = this.layout.findIndex(item => item.i === i)
  154. Object.assign(this.layout[index], { h: newH, w: newW })
  155. this.$emit('change', this.layout)
  156. },
  157. // 移动时的事件
  158. moveEvent (i, newX, newY) {
  159. const index = this.layout.findIndex(item => item.i === i)
  160. Object.assign(this.layout[index], { x: newX, y: newY })
  161. this.$emit('change', this.layout)
  162. },
  163. // 抓取数据
  164. fetchData () {
  165. if (isInit()) {
  166. this.$emit('init')
  167. } else {
  168. const interval = setInterval(() => {
  169. if (isInit()) {
  170. this.$emit('init')
  171. clearInterval(interval)
  172. }
  173. }, 100)
  174. }
  175. },
  176. hasComponent (alias) {
  177. const name = 'ibps-desktop-' + alias
  178. return getComponents().includes(name)
  179. },
  180. getHeight (h) {
  181. return (h - 1) * (this.rowHeight + this.margin[1]) + this.margin[1]
  182. },
  183. closeDialog () {
  184. this.$emit('close', false)
  185. },
  186. handleAddConfirm (data) {
  187. const layout = this.layout
  188. layout.push(data)
  189. this.defaultData.push(data)
  190. this.$emit('close', false)
  191. this.$emit('change', this.layout)
  192. },
  193. /**
  194. * 删除栏目
  195. */
  196. handleRemove (item, i) {
  197. this.$confirm('确定删除?', '提示', {
  198. type: 'warning'
  199. }).then(() => {
  200. this.layout.splice(i, 1)
  201. this.$emit('change', this.layout)
  202. }).catch(() => {
  203. })
  204. },
  205. handleActionEvent (command, { id }, index) {
  206. switch (command) {
  207. case 'fullscreen':
  208. this.handleFullscreen(id)
  209. break
  210. case 'collapse':
  211. case 'expansion':
  212. this.handleCollapseExpansion(index, command === 'collapse')
  213. break
  214. default:
  215. break
  216. }
  217. },
  218. /**
  219. * 全屏展示切换
  220. */
  221. handleFullscreen (id) {
  222. this.dialogPreviewVisible = true
  223. this.id = id
  224. },
  225. // 处理收缩/展开
  226. handleCollapseExpansion (index, isCollapse) {
  227. this.layout[index].h = isCollapse ? 2 : this.defaultData[index].h
  228. this.layout.push({ i: '0' })
  229. const deleteIndex = this.layout.findIndex(item => item.i === '0')
  230. this.layout.splice(deleteIndex, 1)
  231. }
  232. }
  233. }
  234. </script>
  235. <style lang="scss" scoped>
  236. @import '~@/assets/styles/public.scss';
  237. .ibps-desktop-page {
  238. .vue-grid-layout {
  239. border-radius: 4px;
  240. // margin: -10px;
  241. .page_card {
  242. height: 100%;
  243. @extend %unable-select;
  244. }
  245. .vue-resizable-handle {
  246. opacity: .3;
  247. &:hover{
  248. opacity: 1;
  249. }
  250. }
  251. }
  252. .ibps-grid-item,
  253. .el-card{
  254. height: 100%;
  255. }
  256. // .vue-grid-item{
  257. // transition: height .5s;
  258. // }
  259. .ibps-grid-item .drag{
  260. cursor:move;
  261. padding: 5px;
  262. }
  263. .ibps-grid-item .remove{
  264. padding: 5px;
  265. }
  266. .ibps-grid-item .drag,
  267. .ibps-grid-item .remove {
  268. filter: alpha(opacity=20);
  269. opacity: 0.2;
  270. -webkit-transition: all 500ms ease;
  271. -moz-transition: all 500ms ease;
  272. -ms-transition: all 500ms ease;
  273. -o-transition: all 500ms ease;
  274. transition: all 500ms ease;
  275. }
  276. .ibps-grid-item:hover .drag,
  277. .ibps-grid-item:hover .remove{
  278. filter: alpha(opacity=100);
  279. opacity: 1;
  280. }
  281. .ibps-grid-item-tools{
  282. position: absolute;
  283. top: -15px;
  284. right: 0;
  285. padding: 7px 8px;
  286. z-index:10;
  287. }
  288. }
  289. </style>
  290. <style lang="scss" >
  291. .templateHtml-box{
  292. height: 100%;
  293. }
  294. .ibps-desktop-dashboard{
  295. .item {
  296. position: relative;
  297. margin: 12px;
  298. padding: 12px;
  299. height: 90px;
  300. border-radius: 4px;
  301. box-sizing: border-box;
  302. overflow: hidden;
  303. color: #fff;
  304. }
  305. .item-header {
  306. position: relative;
  307. & > p {
  308. margin: 0px;
  309. font-size: 14px;
  310. }
  311. & > span {
  312. position: absolute;
  313. right: 0px;
  314. top: 0px;
  315. padding: 2px 8px;
  316. border-radius: 4px;
  317. font-size: 12px;
  318. background: rgba(255, 255, 255, 0.3);
  319. }
  320. }
  321. .item-body {
  322. & > h2 {
  323. margin: 0;
  324. font-size: 32px;
  325. line-height: 60px;
  326. }
  327. }
  328. // .item-footer {
  329. // line-height: 16px;
  330. // & > span {
  331. // font-size: 10px;
  332. // }
  333. // & > p {
  334. // margin: 0px;
  335. // font-size: 12px;
  336. // }
  337. // }
  338. .item-tip {
  339. display: flex;
  340. align-items: center;
  341. justify-content: center;
  342. position: absolute;
  343. width: 80px;
  344. height: 80px;
  345. bottom: -35px;
  346. right: 50px;
  347. border: 2px solid #fff;
  348. border-radius: 100%;
  349. font-size: 48px;
  350. transform: rotate(-40deg);
  351. opacity: 0.1;
  352. }
  353. }
  354. </style>