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

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