Przeglądaj źródła

add path search

cnwangzd@gmail.com 3 lat temu
rodzic
commit
f971df4976

Plik diff jest za duży
+ 1 - 0
app/matrix/m3graph/css/app.790aa966.css


Plik diff jest za duży
+ 0 - 1
app/matrix/m3graph/css/app.a3952eaa.css


Plik diff jest za duży
+ 1 - 1
app/matrix/m3graph/index.html


Plik diff jest za duży
+ 0 - 1
app/matrix/m3graph/js/app.a7ca9dce.js


Plik diff jest za duży
+ 1 - 0
app/matrix/m3graph/js/app.ee157be6.js


+ 4 - 2
src/components/graph/GraphHandler.vue

@@ -638,7 +638,7 @@ export default {
             };
             
             if(loadSvg()) {
-                _.delay(()=>{
+                setTimeout(()=>{
                     editor.execute("fit");
                     toCenter();
                 },500)
@@ -777,7 +777,9 @@ export default {
 
             this.executeLayout();
 
-            this.onGraphToCenter(true);
+            setTimeout(()=>{
+                this.onGraphToCenter(true);
+            },500)
 
         }
     },

+ 17 - 17
src/components/graph/searchbar/AdvBar.vue

@@ -12,23 +12,17 @@
                 </el-button>
             </template>
         </el-header>
-        <div v-show="control.show">
-            <el-main style="width:100%;height:30vh;border-top:1px solid #409EFF;">
-                <Editor
-                    v-model="editor.data"
-                    @init="onEditorInit"
-                    :lang="editor.lang.value"
-                    :theme="editor.theme.value"
-                    width="100%"
-                    height="80%"
-                    style="border:1px solid #f2f2f2;"
-                    ref="editorRef">
-                </Editor>
-            </el-main>
-            <el-footer>
-                <div :loading="search.loading">保存中...</div>
-            </el-footer>
-        </div>
+        <el-main class="adv-main" v-show="control.show">
+            <Editor
+                v-model="editor.data"
+                @init="onEditorInit"
+                :lang="editor.lang.value"
+                :theme="editor.theme.value"
+                width="100%"
+                height="100%"
+                ref="editorRef">
+            </Editor>
+        </el-main>
     </el-container>
 </template>
 
@@ -194,6 +188,12 @@ export default {
         background-color: transparent;
         color: #777777;
     }
+
+    .adv-bar .adv-main{
+        width:100%;
+        height:30vh;
+        border-top:1px solid #409EFF;
+    }
 </style>
 <style>
     .adv-bar .el-input-group__append, .el-input-group__prepend{

+ 68 - 23
src/components/graph/searchbar/PathBar.vue

@@ -17,7 +17,7 @@
                 <el-button type="text" @click="$emit('toggle-view','SearchBar')">
                     <span class="el-icon-close" style="font-size:14px;font-weight: 900;"></span>
                 </el-button>
-                <el-tooltip content="路劲查询" open-delay="500" placement="top">
+                <el-tooltip content="路劲查询" placement="top">
                     <el-button type="success" class="search" :loading="entity.search.loading">
                         <span class="el-icon-search"></span>
                     </el-button>
@@ -25,28 +25,11 @@
                 
             </template>
         </el-header>
-        <el-main style="width:100%;height:40vh;padding:0px;border-top:1px solid #409EFF;" v-show="searchResultStatus">
-            <div class="div-hover-effect" style="display:flex;padding:10px;cursor:pointer;" 
-                v-for="(item,index) in entity.search.result"
-                :key="index"
-                @click="onEntitySelect(item)"
-                draggable="true" 
-                @dragstart="onEntityDragStart(item,$event)">
-                <el-image :src="item | pickIcon" style="width:15%;height:15%;max-width:48px;min-width:48px;" slot="suffix">
-                    <div slot="error" class="image-slot">
-                        <i class="el-icon-picture-outline"></i>
-                    </div>
-                </el-image>
-                <div style="height:48px;line-height:48px;width:80%;padding-left:10px;">{{ item.value }}</div>
-                <el-tooltip content="拖动到画布">
-                    <el-button type="text" icon="el-icon-menu" style="padding-left:10px;cursor:pointer;"></el-button>
-                </el-tooltip>
-                <el-tooltip content="实体分析">
-                    <el-button type="text" icon="el-icon-postcard" style="padding-left:10px;cursor:pointer;" @click="onEntityDiagnosis(item)">
-                    </el-button>
-                </el-tooltip>
-            </div>
-            <el-button type="text" icon="el-icon-down"></el-button>
+        <el-main class="path-main" v-show="control.show">
+            <PathView class="graphAction" 
+                :model="model" 
+                :pathType="entity.path.type" 
+                ref="pathRef"></PathView>
         </el-main>
     </el-container>
 </template>
@@ -55,12 +38,17 @@
 
 import _ from 'lodash';
 import toggleBarMixin from '../../mixins/index.js';
+import PathView from './path/index';
 
 export default {
     name: "PathBar",
     mixins: [toggleBarMixin],
+    components:{
+        PathView
+    },
     data(){
         return {
+            model: null,
             control: {
                 show: true
             },
@@ -336,6 +324,13 @@ export default {
     .path-bar .search span{
         color: #ffffff;
     }
+
+    .path-bar .path-main{
+        width:100%;
+        height:60vh;
+        padding:0px;
+        border-top:1px solid #409EFF;
+    }
 </style>
 <style>
     .path-bar .el-radio-button__orig-radio:checked+.el-radio-button__inner {
@@ -353,4 +348,54 @@ export default {
     .path-bar .el-radio-button:first-child .el-radio-button__inner {
         border-left: unset;
     }
+
+    .path-bar .el-textarea__inner,
+    .path-bar .el-radio-button__inner{
+        border:unset;
+    }
+    .path-bar .el-radio-button__orig-radio:checked+.el-radio-button__inner {
+        color: #333333;
+        background-color: transparent;
+        border-color: #ffffff;
+        -webkit-box-shadow: unset;
+        box-shadow: unset;
+    }
+    .path-bar .el-radio-button__orig-radio:checked+.el-radio-button__inner:before {
+        content: "";
+        position: absolute;
+        bottom: -2px;
+        left: 29px;
+        border-width: 0 6px 6px;
+        border-style: solid;
+        border-color: #2790e2 transparent;
+        display: block;
+        width: 0;
+        -webkit-transition-duration: 0.3s;
+        transition-duration: 0.3s;
+        -webkit-transition-property: transform;
+        transition-property: transform;
+    }
+    .path-bar .el-radio-button__orig-radio:checked+.el-radio-button__inner:after {
+        content: "";
+        position: absolute;
+        bottom: -2px;
+        left: 30px;
+        border-width: 0 5px 5px;
+        border-style: solid;
+        border-color: #f2f2f2 transparent;
+        display: block;
+        width: 0;
+        -webkit-transition-duration: 0.3s;
+        transition-duration: 0.3s;
+        -webkit-transition-property: transform;
+        transition-property: transform;
+    }
+
+    .path-bar .el-radio-group {
+        display: flex;
+    }
+
+    .path-bar .el-radio-group > .el-radio {
+        margin-right: 20px;
+    }
 </style>

+ 143 - 0
src/components/graph/searchbar/path/InputBar.vue

@@ -0,0 +1,143 @@
+<template>
+    <el-container>
+        <el-header style="height:30px;ling-height:30px;padding:0px;">
+            <el-autocomplete placeholder="请输入实体" 
+                            v-model="model.id" 
+                            :fetch-suggestions="querySearchAsync"
+                            @select="handleSelect"
+                            :trigger-on-focus="false"
+                            style="width:100%;">
+                <el-button slot="prepend" icon="el-icon-menu" class="handleSort input-el-button"></el-button>
+                <el-button slot="append" icon="el-icon-arrow-down"  @click="edge.show = !edge.show" v-if="edge.show"></el-button>
+                <el-button slot="append" icon="el-icon-arrow-right" @click="edge.show = !edge.show" v-else></el-button>
+                <el-button slot="append" icon="el-icon-postcard" @click="onDiagnosis(model)"></el-button>
+                <el-button slot="append" @click="onRemove(model.id)">
+                    <span class="el-icon-circle-close" style="font-size:16px;font-weight:600;"></span>
+                </el-button>
+            </el-autocomplete>
+        </el-header>
+        <el-main v-if="edge.show" style="background:#ffffff;">
+            <el-form label-width="50px" label-position="top">
+                <el-form-item label="关系" style="font-weight:noomal;">
+                    <el-select v-model="edge.edgeType" placeholder="请选择关系类型">
+                        <el-option
+                            v-for="item in edge.list"
+                            :key="item.name"
+                            :label="item.remedy"
+                            :value="item.name">
+                            <span style="float: left">{{ item.remedy }}</span>
+                            <span style="float: right; color: #8492a6; font-size: 13px">{{ item.name }}</span>
+                        </el-option>
+                    </el-select>
+                    <el-popover
+                        placement="top-start"
+                        width="200"
+                        trigger="hover"
+                        content="实体连接关系选择">
+                        <span slot="reference" class="el-icon-question" style="float:right;"></span>
+                    </el-popover>
+                </el-form-item>
+                <el-form-item label="几跳" style="font-weight:normal;">
+                    <el-input-number v-model="edge.edgeStep" :min="1"></el-input-number>
+                    <el-popover
+                        placement="top-start"
+                        width="200"
+                        trigger="hover"
+                        content="实体连接层级设置,实体直接连接为1跳,间接连接为2跳,以此类推。">
+                        <span slot="reference" class="el-icon-question" style="float:right;"></span>
+                    </el-popover>
+                </el-form-item>
+                <el-form-item label="自定义" style="font-weight:normal;">
+                    <el-input type="textarea" :rows=3 v-model="edge.edgeCustom" @blur="onBlur" clearable style="border: 1px solid #ddd;"></el-input>
+                    <el-popover
+                        placement="top-start"
+                        width="200"
+                        trigger="hover"
+                        content="请参考图查询文档,自定义关系类型及实体连接层级设置,举例:[:connect*1]">
+                        <span slot="reference" class="el-icon-question" style="float:right;"></span>
+                    </el-popover>
+                </el-form-item>
+            </el-form>
+        </el-main>
+    </el-container>
+</template>
+<script>
+import _ from 'lodash';
+
+export default {
+    name: "InputBar",
+    props: {
+        model: Object
+    },
+    data(){
+        return {
+            entity: {
+                list: [],
+                timeout:  null,
+            },
+            edge: {
+                show: false,
+                list: null,
+                edgeType: "*",
+                edgeStep: 0,
+                edgeCustom: ""
+            }
+        }
+    },
+    watch:{
+        'edge.edgeCustom':function(val){
+            this.edge.edgeType = val.split("*")[0].replace(/:/,"");
+            this.edge.edgeStep = val.split("*")[1];
+        }
+    },
+    created(){
+        this.m3.callFS("/matrix/m3graph/edges.js",null).then(res=>{
+            this.edge.list = res.message;
+        })
+    },
+    methods:{
+        onBlur(){
+            this.edge.edgeType = this.edge.edgeCustom?this.edge.edgeCustom.split("*")[0].replace(/:/,""):"*";
+            this.edge.edgeStep = this.edge.edgeCustom?this.edge.edgeCustom.split("*")[1]:0;
+        },
+        onDiagnosis(node){
+            //inst.app.$refs.graphDiagnosisRef.diagnosisAdd( node );
+        },
+        onRemove(id){
+            const self = this;
+            self.$parent.$parent.$parent.trace.nodes.splice(_.findIndex(self.$parent.$parent.$parent.trace.nodes,{id:id}),1);
+        },
+        querySearchAsync(term, cb) {
+            
+            try{
+                if(_.isEmpty(term)){
+                    return false;
+                }
+
+                this.m3.callFS("/matrix/m3graph/entity-search-by-term.js", encodeURIComponent(term)).then(res=>{
+                    let entitys = res.message;
+
+                    let results = term ? entitys.filter(this.createStateFilter(term)) : entitys;
+        
+                    clearTimeout(this.entity.timeout);
+                    this.entity.timeout = setTimeout(() => {
+                        cb(results);
+                    }, 3000 * Math.random()); 
+                })
+                
+            } catch(err){
+                console.error(err);
+            }
+            
+        },
+        createStateFilter(term) {
+            return (state) => {
+                return (state.value.toLowerCase().indexOf(term.toLowerCase()) === 0);
+            };
+        },
+        handleSelect(item) {
+            console.log(item);
+        }
+    }
+}
+</script>

+ 76 - 0
src/components/graph/searchbar/path/NewInputBar.vue

@@ -0,0 +1,76 @@
+<template>
+    <el-autocomplete placeholder="请输入实体" 
+                    v-model="newModel.id" 
+                    class="input-with-select topological-analysis-input"
+                    :fetch-suggestions="querySearchAsync"
+                    :trigger-on-focus="false"
+                    @select="handleSelect"
+                    @keyup.enter.native="onNew">
+        <template slot="prepend">
+            <span class="el-icon-place"></span>
+        </template>
+        <el-button slot="append" @click="onNew">
+            <span class="el-icon-circle-plus-outline" style="font-size:16px;font-weight:600;color:green;"></span>
+        </el-button>
+    </el-autocomplete>
+</template>
+
+<script>
+import _ from 'lodash';
+
+export default {
+    name: "NewInputBar",
+    data(){
+        return {
+            newModel: {
+                id: "",
+                value: ""
+            },
+            entity: {
+                list: [],
+                timeout:  null
+            }
+        }
+    },
+    methods:{
+        onNew(){
+            const self = this;
+            
+            let id = this.newModel.id && this.newModel.id.trim()
+            if (!id) {
+                return;
+            }
+            self.$parent.$parent.$parent.trace.nodes.push({
+                id: this.newModel.id,
+                cell: {edge:false}
+            })
+            this.newModel.id = "";
+            
+        },
+        querySearchAsync(term, cb) {
+            
+            if(_.isEmpty(term)){
+                return false;
+            }
+
+            this.m3.callFS("/matrix/graph/entity-search-by-term.js",encodeURIComponent(term)).then(res=>{
+                let entitys = res.message;
+                let results = term ? entitys.filter(this.createStateFilter(term)) : entitys;
+            
+                clearTimeout(this.entity.timeout);
+                this.entity.timeout = setTimeout(() => {
+                    cb(results);
+                }, 50 * Math.random());
+            })
+        },
+        createStateFilter(term) {
+            return (state) => {
+                return (state.value.toLowerCase().indexOf(term.toLowerCase()) === 0);
+            };
+        },
+        handleSelect(item) {
+            this.onNew();
+        }
+    }
+}
+</script>

+ 139 - 0
src/components/graph/searchbar/path/index.vue

@@ -0,0 +1,139 @@
+<template>
+    <el-container>
+        <el-header style="height:100%;line-height:100%;padding:10px;display:flex;flex-direction: column;">
+            <InputBar :model="item" 
+                :data-id="item.id" 
+                :key="item.id" v-for="item in uniqBy(trace.nodes,'id')" 
+                :ref="item.id">
+            </InputBar>
+            <br>
+            <NewInputBar></NewInputBar>
+        </el-header>
+        <el-main style="padding:0px 10px;" class="topological-analysis">
+            <el-table :data="trace.paths.rows" 
+                    ref="multipleTable"
+                    tooltip-effect="dark"
+                    @selection-change="onSelectionChange"
+                    style="width: 100%"
+                    v-if="trace.paths.rows.length > 0">
+                <el-table-column type="expand">
+                    <template slot-scope="props">
+                        <el-form>
+                        <el-form-item v-for="(v,k) in omitBy(props.row,['num','class'])" :key="k">
+                            <template slot="label">
+                                <i class="el-icon-place" style="color: #67c239;"></i>
+                            </template>
+                            <span>#{ v }#</span>
+                        </el-form-item>
+                        </el-form>
+                    </template>
+                </el-table-column>
+                <el-table-column type="selection" width="55"></el-table-column>
+                <el-table-column :prop="col.data" :label="col.title" v-for="(col,index) in trace.paths.columns" :key="index"></el-table-column>
+            </el-table>
+        </el-main>
+    </el-container>
+</template>
+
+<script>
+import _ from 'lodash';
+import InputBar from './InputBar';
+import NewInputBar from './NewInputBar';
+
+export default {
+    name: 'index',    
+    props: {
+        pathType: String
+    },
+    components:{
+        InputBar,
+        NewInputBar
+    },
+    data(){
+        return {
+            trace: {
+                newItem: {
+                    id: "",
+                    type: "",
+                    value: ""
+                },
+                nodes: [],
+                paths: {
+                    rows: [], 
+                    columns: []
+                },
+                selectedPaths: []
+            }
+        }
+    },
+    created(){
+        //eventHub.$on("TOPOLOGICAL-ANALYISS-TRACE",this.setTrace);
+    },
+    mounted(){
+        
+        /* _.delay(()=>{
+            let sortable = Sortable.create(this.$refs.topologicalAnalysisInputList,{
+                handle: ".handleSort",
+                dataIdAttr: 'data-id',
+                onChange(evt) {
+                    let nodes = _.cloneDeep(this.trace.nodes);
+                    this.trace.nodes = _.map(sortable.toArray(),(v)=>{
+                        return _.find(nodes,{id:v});
+                    });
+                }
+            });
+        },1000) */
+    },
+    methods:{
+        uniqBy(arr,prop){
+            return _.uniqBy(arr,prop);
+        },
+        omitBy(arr,prop){
+            return _.omit(arr,prop);
+        },
+        setTrace(node){
+            this.trace.nodes.push(node);
+        },
+        onSearch(){
+            
+            if(this.trace.nodes.length < 2){
+                this.$message("请选择节点!");
+                return false;
+            }
+            let term = {
+                        pathType: this.pathType,
+                        nodes: _.map(this.trace.nodes,(v)=>{
+                            return _.extend(_.omit(v,["cell"]),{ edgeProperty: _.omit(this.$refs[v.id][0].edge,["list","show"]) });
+                        })
+                    };
+            
+            let rows = [];
+            let cols = [];
+
+            try{
+
+                this.m3.callFS("/matrix/m3graph/paths-by-id.js",encodeURIComponent(JSON.stringify(term))).then(res=>{
+                    let rtn = res.message.result.data[0].graph;  
+                    
+                    if(!_.isEmpty(rtn.paths)){
+                        _.forEach(rtn.paths,(v,index)=>{
+                            rows.push( _.merge({num:`路径${++index}`,class:"path"},v));
+                        })
+                        cols = _.concat([{data:"num",title:"序号"}],_.map(rtn.pathtags,function(v){ return {data:v,title:v}}));
+                    }
+                    _.extend(this.trace.paths, {rows: rows,  columns: cols});
+                })
+
+                
+
+            } catch(err){
+                _.extend(this.trace.paths, {rows: rows,  columns: cols});
+            }
+            
+        },
+        onSelectionChange(val){
+            
+        }
+    }
+}
+</script>