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

363 lines
9.7 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
1 year ago
2 years ago
1 year ago
2 years ago
1 year 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 'classify-header':
  162. case 'notice':
  163. case 'text':
  164. case 'imageTextNav':
  165. case 'imageText':
  166. case 'imageTextList':
  167. case 'brandList':
  168. case 'categoryList':
  169. case 'assistDiv':
  170. case 'vip':
  171. case 'live':
  172. case 'videoBox':
  173. isEmpty = false
  174. break
  175. case 'productList':
  176. _data = newVal.productData
  177. if((_data.sourceType=='1' && _data.productIdList.length > 0) || (_data.sourceType=='2' && _data.categoryId != 0) || (_data.sourceType!='1' && _data.sourceType!='2')){
  178. isEmpty = false
  179. }
  180. break
  181. case 'custom':
  182. _data=newVal.imgData
  183. _data.forEach(function(value ){
  184. if(value.src){
  185. isEmpty = false
  186. }
  187. })
  188. break
  189. case 'groupList':
  190. if(this.typeId === 1){
  191. isEmpty = false
  192. }
  193. else {
  194. if(newVal.shopGroupWorkId){
  195. isEmpty = false
  196. }
  197. }
  198. break
  199. case 'spikeList':
  200. if(newVal.shopSeckillId){
  201. isEmpty = false
  202. }
  203. break
  204. case 'discountList':
  205. if(newVal.discountId){
  206. isEmpty = false
  207. }
  208. break
  209. case 'priceList':
  210. if(newVal.priceId){
  211. isEmpty = false
  212. }
  213. break
  214. case 'coupon':
  215. if(newVal.selectedCoupon.length > 0){
  216. isEmpty = false
  217. }
  218. break
  219. case 'newProduct':
  220. _data = newVal.productData
  221. if((_data.sourceType=='1' && _data.productIdList.length > 0) || (_data.sourceType=='2' && _data.categoryId != 0)){
  222. isEmpty = false
  223. }
  224. break
  225. case 'shop':
  226. _data=newVal.imgTextData
  227. _data.forEach(function(value ){
  228. if(value.img){
  229. isEmpty = false
  230. }
  231. })
  232. break
  233. }
  234. dataList[i].isEmpty = isEmpty
  235. this.$forceUpdate()
  236. }
  237. console.log(dataList)
  238. },
  239. },
  240. // 监控组件是否为空
  241. watch: {
  242. 'componentsData': {
  243. handler(newVal, oldVal) {
  244. this.checkIsNoData(newVal)
  245. },
  246. deep: true
  247. }
  248. }
  249. }
  250. </script>
  251. <style lang="scss" scoped>
  252. .hom-layout {
  253. background-color: #FAFAFA;
  254. ::v-deep .sortable-chosen {
  255. .contentBox {
  256. display: none;
  257. }
  258. .cloneText {
  259. display: block;
  260. width: 100%;
  261. height: 50px;
  262. line-height: 50px;
  263. font-size: 18px;
  264. text-align: center;
  265. background-color: $mainColor;
  266. color: #fff;
  267. }
  268. }
  269. .list-group {
  270. min-height: calc(100vh - 50px);
  271. }
  272. .list-group-item {
  273. position: relative;
  274. cursor: move;
  275. background-color: #FAFAFA;
  276. min-height: 60px;
  277. &.item-assistDiv,&.item-notice,&.item-text{
  278. min-height: 0px;
  279. }
  280. .btns {
  281. display: none;
  282. }
  283. &:hover {
  284. &:after {
  285. content: '';
  286. position: absolute;
  287. width: 100%;
  288. height: 100%;
  289. left: 0;
  290. top: 0;
  291. border: 1px $mainColor dashed;
  292. z-index: 2;
  293. }
  294. }
  295. &.on {
  296. &:after {
  297. content: '';
  298. position: absolute;
  299. width: 100%;
  300. height: 100%;
  301. left: 0;
  302. top: 0;
  303. border: 1px $mainColor solid;
  304. z-index: 2;
  305. }
  306. .btns {
  307. display: block;
  308. position: absolute;
  309. right: -13px;
  310. top: 50%;
  311. margin-top: -13px;
  312. z-index: 3;
  313. span {
  314. display: block;
  315. width: 26px;
  316. height: 26px;
  317. line-height: 26px;
  318. text-align: center;
  319. color: #666;
  320. background-color: #fff;
  321. box-shadow: 0 0 2px rgba(51, 51, 51, 0.2);
  322. cursor: pointer;
  323. }
  324. }
  325. }
  326. }
  327. }
  328. .no-data {
  329. width: 100%;
  330. display: flex;
  331. height: 300px;
  332. -webkit-box-align: center;
  333. align-items: center;
  334. -webkit-box-pack: center;
  335. justify-content: center;
  336. color: #999;
  337. text-align: center;
  338. font-size: 16px;
  339. line-height: 1.8;
  340. .iconfont {
  341. font-size: 100px;
  342. color: $mainColor;
  343. margin-right: 50px;
  344. }
  345. }
  346. </style>
  347. <style lang="scss">
  348. .warp {
  349. width: 710px;
  350. margin: 0 auto;
  351. max-width: 100%;
  352. &.terminal4 {
  353. width: 1200px;
  354. max-width: 100%;
  355. }
  356. }
  357. .flex-box {
  358. display: flex;
  359. }
  360. </style>