多租户商城-商户端
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.

362 lines
9.6 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <template>
  2. <div class="layout hom-layout" v-loading.fullscreen.lock="loading">
  3. <draggable
  4. class="dragArea list-group"
  5. :list="componentsData"
  6. group="pageEdit"
  7. :move="checkMove"
  8. @end="pageAdd"
  9. @change="pageChange"
  10. filter=".undraggable"
  11. >
  12. <div class="list-group-item" v-for="(item,index) in componentsData" :key="index" :class="[{'on':activeComponent == index,'undraggable':item.undraggable},'item-'+item.type]" @click="selectComponent(item,index)">
  13. <component v-show="!item.isEmpty" :isNoData.sync='item.isEmpty' :is="componentMap[terminal-1].get(item.type)" :componentContent="item.componentContent" :terminal="terminal" :typeId="typeId" :shopId="shopId" @cleckLoading="cleckLoading"></component>
  14. <div class="no-data" v-show="item.isEmpty">
  15. <i class="iconfont icon-kong"></i>
  16. <p>暂无数据<br>请在右边窗口编辑内容</p>
  17. </div>
  18. <div class="btns">
  19. <span @click="delComponent(item,index)"><i class="iconfont icon-shanchu"></i></span>
  20. </div>
  21. </div>
  22. </draggable>
  23. </div>
  24. </template>
  25. <script>
  26. import draggable from 'vuedraggable'
  27. import componentMap from './canvasShow/componentMap'
  28. import { mapGetters, mapMutations } from 'vuex'
  29. export default {
  30. // import testData from '@@/config/testData3'
  31. name: 'canvasEditPage',
  32. components: {
  33. draggable
  34. },
  35. props: {
  36. terminal: {
  37. type: Number,
  38. default: 4
  39. },
  40. typeId: {
  41. type: Number,
  42. default: 1
  43. },
  44. shopId: {
  45. type: Number,
  46. default: 0
  47. }
  48. },
  49. data () {
  50. return {
  51. activeComponent: -1,
  52. componentMap: componentMap,
  53. loading: false
  54. }
  55. },
  56. mounted () {
  57. // this.setComponentsData(testData)
  58. },
  59. computed: {
  60. ...mapGetters([
  61. 'componentsData'
  62. ])
  63. },
  64. methods: {
  65. ...mapMutations({
  66. setActiveComponent: 'SET_ACTIVECOMPONENT',
  67. setComponentsData: 'SET_COMPONENTSDATA'
  68. }),
  69. // 画布添加或者移动了组件
  70. pageChange (e) {
  71. if (e.added) {
  72. if(e.added.element.type == 'header'){
  73. var headerArr = this.componentsData.filter(v=>{
  74. return v.type === 'header'
  75. })
  76. if(headerArr.length >= 2){
  77. this.componentsData.splice(e.added.newIndex, 1)
  78. this.$message.warning('头部组件最多只能存在一个。')
  79. } else if(headerArr.length === 1 && this.componentsData[0].type !== 'header'){
  80. this.componentsData.splice(e.added.newIndex, 1)
  81. this.componentsData.unshift(e.added.element)
  82. }
  83. this.activeComponent = 0
  84. e.added.element.index = 0
  85. this.setActiveComponent(e.added.element)
  86. } else {
  87. this.activeComponent = e.added.newIndex
  88. e.added.element.index = e.added.newIndex
  89. this.setActiveComponent(e.added.element)
  90. }
  91. }
  92. if (e.moved) {
  93. this.activeComponent = e.moved.newIndex
  94. e.moved.element.index = e.moved.newIndex
  95. this.setActiveComponent(e.moved.element)
  96. }
  97. this.$emit('showRightBox', true)
  98. },
  99. // 拖动检查
  100. checkMove(e){
  101. console.log(e,'checkMove')
  102. //不允许停靠
  103. if (e.relatedContext.element.type == 'header') return false;
  104. //不允许拖拽
  105. if (e.draggedContext.element.type == 'header') return false;
  106. },
  107. pageAdd(e){
  108. console.log(e,'pageAdd')
  109. return false
  110. },
  111. // 选中组件
  112. selectComponent (item, index) {
  113. this.activeComponent = index
  114. item.index = index
  115. this.setActiveComponent(item)
  116. this.$emit('showRightBox', true)
  117. },
  118. // 删除组件
  119. delComponent (item, index) {
  120. this.$confirm('确定删除吗?', '提示', {
  121. confirmButtonText: this.$t('common.sure'),
  122. cancelButtonText: this.$t('common.cancel'),
  123. type: 'warning'
  124. }).then(() => {
  125. this.activeComponent = -1
  126. this.componentsData.splice(index, 1)
  127. this.$emit('showRightBox', false)
  128. }).catch(() => {
  129. })
  130. },
  131. cleckLoading(){
  132. if(typeof(uni) !== 'undefined'){
  133. uni.getStorage({
  134. key: 'sendNum',
  135. success: function (res) {
  136. let sendNum = res.data;
  137. this.loading = parseInt(sendNum) !== 0
  138. }
  139. })
  140. } else {
  141. let sendNum = localStorage.getItem('sendNum')
  142. this.loading = parseInt(sendNum) !== 0
  143. }
  144. },
  145. // 检查组件是否为空
  146. checkIsNoData(dataList) {
  147. for(let i=0;i<dataList.length;i++){
  148. const newVal = dataList[i].componentContent
  149. let isEmpty = true
  150. let _data = ''
  151. switch (dataList[i].type){
  152. case 'banner':
  153. _data=newVal.bannerData
  154. _data.forEach(function(value ){
  155. if(value.bannerUrl){
  156. isEmpty = false
  157. }
  158. })
  159. break
  160. case 'header':
  161. case 'notice':
  162. case 'text':
  163. case 'imageTextNav':
  164. case 'imageText':
  165. case 'imageTextList':
  166. case 'brandList':
  167. case 'categoryList':
  168. case 'assistDiv':
  169. case 'vip':
  170. case 'live':
  171. case 'videoBox':
  172. isEmpty = false
  173. break
  174. case 'productList':
  175. _data = newVal.productData
  176. if((_data.sourceType=='1' && _data.productIdList.length > 0) || (_data.sourceType=='2' && _data.categoryId != 0)){
  177. isEmpty = false
  178. }
  179. break
  180. case 'custom':
  181. _data=newVal.imgData
  182. _data.forEach(function(value ){
  183. if(value.src){
  184. isEmpty = false
  185. }
  186. })
  187. break
  188. case 'groupList':
  189. if(this.typeId === 1){
  190. isEmpty = false
  191. }
  192. else {
  193. if(newVal.shopGroupWorkId){
  194. isEmpty = false
  195. }
  196. }
  197. break
  198. case 'spikeList':
  199. if(newVal.shopSeckillId){
  200. isEmpty = false
  201. }
  202. break
  203. case 'discountList':
  204. if(newVal.discountId){
  205. isEmpty = false
  206. }
  207. break
  208. case 'priceList':
  209. if(newVal.priceId){
  210. isEmpty = false
  211. }
  212. break
  213. case 'coupon':
  214. if(newVal.selectedCoupon.length > 0){
  215. isEmpty = false
  216. }
  217. break
  218. case 'newProduct':
  219. _data = newVal.productData
  220. if((_data.sourceType=='1' && _data.productIdList.length > 0) || (_data.sourceType=='2' && _data.categoryId != 0)){
  221. isEmpty = false
  222. }
  223. break
  224. case 'shop':
  225. _data=newVal.imgTextData
  226. _data.forEach(function(value ){
  227. if(value.img){
  228. isEmpty = false
  229. }
  230. })
  231. break
  232. }
  233. dataList[i].isEmpty = isEmpty
  234. this.$forceUpdate()
  235. }
  236. console.log(dataList)
  237. },
  238. },
  239. // 监控组件是否为空
  240. watch: {
  241. 'componentsData': {
  242. handler(newVal, oldVal) {
  243. this.checkIsNoData(newVal)
  244. },
  245. deep: true
  246. }
  247. }
  248. }
  249. </script>
  250. <style lang="scss" scoped>
  251. .hom-layout {
  252. background-color: #fff;
  253. ::v-deep .sortable-chosen {
  254. .contentBox {
  255. display: none;
  256. }
  257. .cloneText {
  258. display: block;
  259. width: 100%;
  260. height: 50px;
  261. line-height: 50px;
  262. font-size: 18px;
  263. text-align: center;
  264. background-color: $mainColor;
  265. color: #fff;
  266. }
  267. }
  268. .list-group {
  269. min-height: calc(100vh - 50px);
  270. }
  271. .list-group-item {
  272. position: relative;
  273. cursor: move;
  274. background-color: #fff;
  275. min-height: 100px;
  276. &.item-assistDiv,&.item-notice,&.item-text{
  277. min-height: 0px;
  278. }
  279. .btns {
  280. display: none;
  281. }
  282. &:hover {
  283. &:after {
  284. content: '';
  285. position: absolute;
  286. width: 100%;
  287. height: 100%;
  288. left: 0;
  289. top: 0;
  290. border: 1px $mainColor dashed;
  291. z-index: 2;
  292. }
  293. }
  294. &.on {
  295. &:after {
  296. content: '';
  297. position: absolute;
  298. width: 100%;
  299. height: 100%;
  300. left: 0;
  301. top: 0;
  302. border: 1px $mainColor solid;
  303. z-index: 2;
  304. }
  305. .btns {
  306. display: block;
  307. position: absolute;
  308. right: -13px;
  309. top: 50%;
  310. margin-top: -13px;
  311. z-index: 3;
  312. span {
  313. display: block;
  314. width: 26px;
  315. height: 26px;
  316. line-height: 26px;
  317. text-align: center;
  318. color: #666;
  319. background-color: #fff;
  320. box-shadow: 0 0 2px rgba(51, 51, 51, 0.2);
  321. cursor: pointer;
  322. }
  323. }
  324. }
  325. }
  326. }
  327. .no-data {
  328. width: 100%;
  329. display: flex;
  330. height: 300px;
  331. -webkit-box-align: center;
  332. align-items: center;
  333. -webkit-box-pack: center;
  334. justify-content: center;
  335. color: #999;
  336. text-align: center;
  337. font-size: 16px;
  338. line-height: 1.8;
  339. .iconfont {
  340. font-size: 100px;
  341. color: $mainColor;
  342. margin-right: 50px;
  343. }
  344. }
  345. </style>
  346. <style lang="scss">
  347. .warp {
  348. width: 710px;
  349. margin: 0 auto;
  350. max-width: 100%;
  351. &.terminal4 {
  352. width: 1200px;
  353. max-width: 100%;
  354. }
  355. }
  356. .flex-box {
  357. display: flex;
  358. }
  359. </style>