rsbi 4 éve
szülő
commit
3928409996

+ 169 - 27
src/view/portal/LayoutOptarea.vue

@@ -1,10 +1,14 @@
 <!-- 布局器 -->
 <script>
 import { baseUrl } from "@/common/biConfig";
+import PortalText from "./PortalText.vue"
 import $ from "jquery";
+import * as utils from './Utils'
 
 export default {
-  components: {},
+  components: {
+    PortalText
+  },
   props: {
     pageInfo: {
       type: Object,
@@ -12,6 +16,17 @@ export default {
     },
   },
   render(h) {
+    //在render函数执行后绑定拖拽事件
+    this.$nextTick(()=>{
+      if(this.$parent.isbindTdEvent===true){
+        //绑定布局器的事件
+        this.bindTdEvent();
+        //绑定组件的事件
+        utils.findAllComps(this.pageInfo).forEach(e=>this.bindCompEvent(e));
+        this.$parent.isbindTdEvent = false;
+      }
+    });
+
     var json = this.pageInfo.body;
     var trs = [];
     for (var i = 1; true; i++) {
@@ -22,6 +37,15 @@ export default {
       var tds = [];
       for (var j = 0; j < tr.length; j++) {
         var td = tr[j];
+        
+        let cmps = [];
+        if(td.children){
+          for(var k=0; k<td.children.length; k++){
+            var comp = td.children[k];
+            cmps.push(this.renderComp(comp, h, td.id));
+          }
+        }
+
         tds.push(
           h("td", {
             attrs: {
@@ -32,23 +56,19 @@ export default {
               colspan: td.colspan,
               rowspan: td.rowspan,
             },
-          }, "xxx")
+          }, cmps)
         );
-        /**
-        if(td.children){
-          for(var k=0; k<td.children.length; k++){
-            var comp = findTCompById(td.children[k]);
-            var str = compStr(comp, false);
-            ret = ret + str;
-            cps.push(comp);
-          }
-        }
-         */
       }
       trs.push(h('tr', {}, tds));
     }
     let table = h('table', {attrs:{border:"0", cellspacing:"0", cellpadding:"0", class:"r_layout", id:"layout_table"}}, [h('tbody', trs)]);
-    return h("div", {attrs:{id:"optarea", class:"layout-center-body", align:"center"}}, [table, h('div', {class:"indicator"}, '==>')]);
+    return h("div", {attrs:{id:"optarea", class:"layout-center-body", align:"center"}}, 
+      [
+        table, 
+        h('div', {class:"indicator"}, '==>'),
+        h('PortalText',{ref:"portalTextForm"},'')
+      ]
+    );
   },
   data() {
     return {
@@ -63,6 +83,40 @@ export default {
     setUpdate(){
       this.$parent.isupdate = true;
     },
+    addComp(layoutId, comp){
+        var layout = utils.findLayoutById(layoutId, this.pageInfo);
+        if(!layout.children){
+          layout.children = [];
+        }
+        layout.children.push(comp);
+        this.$nextTick(()=>this.bindCompEvent(comp));
+    },
+    renderComp(comp, h, layoutId){
+      let tools = [
+        h('button', {class:"btn btn-outline btn-success btn-xs", attrs:{title:"设置组件"}, on:{click:()=>{alert(3)}}}, [h('i', {class:"fa fa-wrench"})]),
+        h('span',' '),
+        h('button', {class:"btn btn-outline btn-danger btn-xs", attrs:{title:"删除组件"}, on:{click:()=>{this.deleteComp(comp, layoutId)}}}, [h('i', {class:"fa fa-times"})])
+      ];
+      let title = h('div', {class:"ibox-title"}, [h('div', {class:"ctit"}, [h('h5', comp.name)]), h('div', {class:"ibox-tools"}, tools)]);
+      let ctx = h('div', {class:"cctx ibox-content", style:{padding:"3px"}}, [h('div', {class:"ccctx"}, comp.desc)]);
+      return h('div', {attrs:{class:"ibox", id:"c_" + comp.id}}, [title, ctx]);
+    },
+    deleteComp(comp, layoutId){
+      if(!confirm("是否确认删除组件?")){
+        return;
+      }
+      //从布局器中删除,
+      var td = utils.findLayoutById(layoutId, this.pageInfo);
+      var compIdx = -1;
+      for(var i=0; i<td.children.length; i++){
+        if(td.children[i].id == comp.id){
+          compIdx = i;
+          break;
+        }
+      }
+      td.children.splice(compIdx, 1);
+      this.setUpdate();
+    },
     //table 布局器拖拽事件
     bindTdEvent(){
       let ts = this;
@@ -104,7 +158,7 @@ export default {
         },
         out:function(e, ui){
           $(ui.helper[0]).find("span").removeClass("glyphicon-ok").addClass("glyphicon-remove");
-          $(".indicator").hide();
+          //$(".indicator").hide();
           delete curTmpInfo.id;
           delete curTmpInfo.tp;
         },
@@ -140,7 +194,7 @@ export default {
             var layoutId = $(this).attr("id").split("_")[1];
             var tp = node.id;
             if(tp == "text"){
-              insertText("insert", layoutId, '', curTmpInfo.id, curTmpInfo.tp);
+              ts.$refs['portalTextForm'].insertText("insert", layoutId, '', curTmpInfo.id, curTmpInfo.tp);
             }else if(tp == "table"){
               var comp = {"id":newGuid(), "name":"交叉表", "type":"table"};
               var str = addComp(comp, layoutId, true);
@@ -156,10 +210,6 @@ export default {
               //注册拖放事件
               bindCompEvent(comp);
               bindResizeEvent(comp.id, 'table');
-              //滚动位置
-              window.setTimeout(function(){
-                $("#optarea").scrollTop($("#c_"+comp.id).offset().top);
-              }, 500);
             }else if(tp == "chart"){
               setcharttype(true, layoutId, curTmpInfo.id, curTmpInfo.tp)					
             }else if(tp == "grid"){
@@ -177,10 +227,6 @@ export default {
               //注册拖放事件
               bindCompEvent(comp);
               bindResizeEvent(comp.id, 'grid');
-              //滚动位置
-              window.setTimeout(function(){
-                $("#optarea").scrollTop($("#c_"+comp.id).offset().top);
-              }, 500);
             }else if(tp == "box"){
               var comp = {"id":newGuid(), "name":"数据块", "type":"box"};
               var str = addComp(comp, layoutId, true);
@@ -204,11 +250,77 @@ export default {
         }
 
       });
+    },
+    //绑定组件拖拽事件
+    bindCompEvent(obj){
+      let ts = this;
+      let curTmpInfo = ts.curTmpInfo;
+      //注册移动事件
+      $("#c_" + obj.id).draggable({
+        revertDuration: 200,
+        handle:$("#c_" + obj.id + " div.ibox-title"),
+        delay:300,
+        cursorAt: { top: 0, left:  -10 },
+        scroll: false,
+        cursor: "point",
+        appendTo: "body",
+        revert: 'invalid',
+        helper:function(e){
+          var id = $(this).find("div.ibox-title").text();
+          return "<div class=\"vakata-dnd\"><span class=\"miconcancel glyphicon glyphicon-remove\"></span>"+id+"</div>";
+        },
+        start:function(e){
+          //resetWindows('min');
+          //$(this).hide();
+        },
+        stop:function(e){
+          $(".indicator").hide();
+          //resetWindows('max');
+          //$(this).show();
+        }
+      });
+      $("#c_" + obj.id).droppable({
+        accept:"div.ibox, #comptree .jstree-node",
+        over:function(e, ui){
+          curTmpInfo.mouseOnDiv = true;
+          curTmpInfo.id = $(this).attr("id");
+          curTmpInfo.tp = "before";
+          $(".indicator").css({
+            display:'block',
+            left:$(this).offset().left,
+            top:$(this).offset().top - 10
+          });
+        },
+        out:function(e, ui){
+          var source = ui.draggable[0];
+          curTmpInfo.mouseOnDiv = false;
+          var obj = $(this).parent();
+          var last = obj.children().last();
+          if(last.attr("id") ==  $(source).attr("id")){
+            last = last.prev();
+          }
+          if(last.length == 0){
+            $(".indicator").css({
+              display:'block',
+              left:obj.offset().left,
+              top:obj.offset().top - 10
+            });
+          }else{
+            curTmpInfo.id = last.attr("id");
+            curTmpInfo.tp = "after";
+            $(".indicator").css({
+              display:'block',
+              left:last.offset().left,
+              top:last.offset().top + last.height()
+            });
+          }	
+        },
+        drop:function(e, ui){
+          //alert(ui); 
+        }
+      });
     }
-  },
-  watch: {},
-  beforeMount() {},
-  beforeDestroy() {},
+  }
 };
 </script>
 
@@ -240,4 +352,34 @@ table.r_layout {
 	display:none;
 	color:red;
 }
+.ibox-title {
+    height: 30px;
+    border-color: #edf1f2;
+    background-color: #f6f8f8;
+    color: #333;
+    font-weight: 700;
+    padding: 8px 15px 3px 15px;
+    border-bottom: 1px solid transparent;
+    display: block;
+    clear: both;
+    cursor: move;
+}
+.ibox-title h5 {
+    display: inline-block;
+    font-size: 14px;
+    margin: 0 0 7px;
+    padding: 0;
+    text-overflow: ellipsis;
+    float: left;
+}
+.ibox-tools {
+    display: inline-block;
+    float: right;
+    margin-top: 0;
+    position: relative;
+    padding: 0;
+}
+#optarea .ibox {
+    margin-bottom: 10px !important;
+}
 </style>

+ 3 - 1
src/view/portal/PortalIndexCustomiz.vue

@@ -64,7 +64,8 @@ export default {
           name:[
 						{ required: true, message: '必填', trigger: 'blur' }
           ]
-         }
+        },
+        isbindTdEvent:false  //是否给布局器table的 td 绑定拖拽事件
     }
   },
   methods: {
@@ -76,6 +77,7 @@ export default {
         type:"GET",
         success:(resp)=>{
           this.pageInfo = JSON.parse(resp.rows);
+          this.isbindTdEvent = true; //需要重新绑定事件
         }
 
       }, this);

+ 4 - 0
src/view/portal/PortalLayoutDailog.vue

@@ -49,6 +49,7 @@ export default {
   },
   methods: {
      setLayout(){
+       this.layoutId = this.pageInfo.layout;
        this.show = true;
      },
      selectRadio(l){
@@ -59,10 +60,13 @@ export default {
        if(l === 6){  //自定义
 
        }else{
+         let comps = layout.findAllComps(this.pageInfo);
          let json = layout.layout["l"+l];
          this.pageInfo.layout = l;
          this.pageInfo.body = json;
+         json['tr1'][0].children = comps;  //都放入第一个布局td
          this.show = false;
+         this.$parent.isbindTdEvent = true;
        }
      }
   }

+ 36 - 6
src/view/portal/PortalText.vue

@@ -1,12 +1,23 @@
 <template>
-  	<div>
-      Text
-  	</div>
+  	<el-dialog :title="title" :visible.sync="show" :close-on-click-modal="false" custom-class="nopadding">
+      <el-input
+        type="textarea"
+        :rows="5"
+        v-model="ctx">
+      </el-input>
+      <div slot="footer" class="dialog-footer">
+			    <el-button type="primary" @click="save()">确 定</el-button>
+				<el-button @click="show = false">取 消</el-button>
+			  </div>
+  	</el-dialog>
 </template>
 
 <script>
-import {baseUrl} from '@/common/biConfig'
+import {baseUrl,newGuid} from '@/common/biConfig'
 import PortalIndex from "./PortalIndex.vue"
+import { Message } from 'element-ui'
+import * as utils from './Utils'
+
 
 export default {
   components:{
@@ -14,7 +25,10 @@ export default {
   },
   data(){
     return {
-      
+      ctx:"",
+      title:"",
+      show:false,
+      layoutId:null
     }
   },
   mounted(){
@@ -23,7 +37,23 @@ export default {
   computed: {
   },
   methods: {
-
+    insertText(tp, layoutId){
+      this.title = "请输入文本内容 - 文本框";
+      this.show = true;
+      this.ctx = "";
+      this.layoutId = layoutId;
+    },
+    save(){
+      if(this.ctx.length === 0 ){
+        Message.error({message:"请录入文本内容", type:"error",showClose: true});
+        return;
+      }
+      var obj = {"id":newGuid(), type:'text', name:"文本", desc:this.ctx};
+      this.show = false;
+      this.$parent.addComp(this.layoutId, obj);
+      this.$parent.setUpdate();
+      this.$parent.$forceUpdate();
+    }
   }
 }
 </script>

+ 38 - 0
src/view/portal/Utils.js

@@ -50,3 +50,41 @@ export const getParamTypeDesc = (paramType)=>{
 	}
 	return tpname;
 }
+
+//从布局器中查询td(容器)
+export const findLayoutById = (layoutId, pageInfo)=>{
+	var ret = null;
+	for(var i=1; true; i++){
+		var tr = pageInfo.body["tr"+i];
+		if(!tr || tr == null){
+			break;
+		}
+		for(var j=0; j<tr.length; j++){
+			var td = tr[j];
+			if(td.id == layoutId){
+				ret = td;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+//查询布局器中所以组件
+export const findAllComps = (pageInfo)=>{
+	let ret = [];
+	for(var i=1; true; i++){
+		var tr = pageInfo.body["tr"+i];
+		if(!tr || tr == null){
+		  break;
+		}
+		for(var j=0; j<tr.length; j++){
+		  var td = tr[j];
+		  if(td.children){
+			td.children.forEach(element => {
+			  ret.push(element);
+			});
+		  }
+		}
+	}
+	return ret;
+}