From fa88c82524447e1e978637ff7f7dc7a3af20b956 Mon Sep 17 00:00:00 2001 From: hanbaoshan <hanbaoshan@aiotlink.com> Date: 星期三, 29 七月 2020 10:25:42 +0800 Subject: [PATCH] 添加系统设置 --- src/components/serfDiagram/vue-d3-network/assets/node.svg | 13 src/pages/algorithmManage/index/mixins.ts | 0 src/pages/settings/index/App.vue | 166 + src/pages/desktop/index/components/ToolsEntry.vue | 40 src/pages/desktop/index/components/DFrame.vue | 1 src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.eot | 0 src/pages/settings/components/LogManagement.vue | 190 + src/pages/desktop/index/mock/userData.json | 8 src/components/serfDiagram/index.vue | 288 ++ src/components/serfDiagram/vue-d3-network/components/canvasRenderer.vue | 452 +++ src/pages/settings/components/AuthorityManagement.vue | 265 ++ src/components/serfDiagram/vue-d3-network/lib/js/canvasStyles.js | 56 src/components/subComponents/FileUpload/index.vue | 16 src/pages/desktop/index/components/Tools.vue | 7 src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.woff | 0 src/components/serfDiagram/vue-d3-network/lib/styl/node-style.styl | 6 src/components/serfDiagram/vue-d3-network/assets/css/icons.css | 95 src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.ttf | 0 src/components/serfDiagram/vue-d3-network/lib/js/stylePicker.js | 78 src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.svg | 28 src/components/serfDiagram/icons.js | 16 src/components/serfDiagram/vue-d3-network/lib/js/svgExport.js | 143 + src/pages/settings/components/RadioSet.vue | 189 + src/pages/settings/components/SystemMaintenance.vue | 514 ++++ src/components/serfDiagram/vue-d3-network/components/svgRenderer.vue | 207 + src/components/serfDiagram/vue-d3-network/lib/js/saveImage.js | 28 src/pages/settings/components/ClusterManagement.vue | 620 +++++ src/pages/algorithmManage/index/App.vue | 1648 ++++++++++++++ src/pages/settings/index/main.ts | 11 src/components/serfDiagram/vue-d3-network/index.vue | 504 ++++ package.json | 5 src/pages/settings/components/BasicSetting.vue | 1307 +++++++++++ src/components/serfDiagram/vue-d3-network/assets/github.svg | 1 src/components/serfDiagram/vue-d3-network/lib/styl/vars.styl | 21 src/assets/gif/green.gif | 0 35 files changed, 6,881 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 68f1fee..d3e822c 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,16 @@ "dependencies": { "@hscmap/vue-window": "^2.4.2", "axios": "^0.19.2", + "d3-force": "^2.0.1", "element-ui": "^2.4.6", "less-loader": "^6.2.0", + "pug": "^3.0.0", + "pug-plain-loader": "^1.0.0", "qs": "^6.9.4", "simple-uploader.js": "^0.5.4", "spark-md5": "^3.0.1", + "stylus": "^0.54.8", + "stylus-loader": "^3.0.2", "vue": "^2.6.11", "vue-awesome-swiper": "^3.1.3", "vue-qrcode-component": "^2.1.1", diff --git a/src/assets/gif/green.gif b/src/assets/gif/green.gif new file mode 100644 index 0000000..a5e4077 --- /dev/null +++ b/src/assets/gif/green.gif Binary files differ diff --git a/src/components/serfDiagram/icons.js b/src/components/serfDiagram/icons.js new file mode 100644 index 0000000..c774809 --- /dev/null +++ b/src/components/serfDiagram/icons.js @@ -0,0 +1,16 @@ +const nodeIcon = { + master: + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><path stroke="null" id="svg_1" d="m2.94198,33.37473l-0.05707,0c-0.05707,-0.73562 0.39952,-2.29565 1.55369,-4.50252a17.173,17.173 0 0 1 -1.56637,-2.38443c-2.39712,4.12837 -3.21518,7.40062 -1.85174,8.76406a2.6381,2.6381 0 0 0 1.90247,0.63416c1.68052,0 4.06495,-0.9005 6.84257,-2.53663a16.72275,16.72275 0 0 1 -2.39078,-1.57271c-2.65078,1.45856 -4.0269,1.59808 -4.43276,1.59808zm29.98299,-30.07177l0.05707,0c0.05707,0.73562 -0.39952,2.29565 -1.55369,4.50252a17.173,17.173 0 0 1 1.56637,2.38443c2.39712,-4.12837 3.21518,-7.40062 1.85174,-8.76406a2.6381,2.6381 0 0 0 -1.90247,-0.63416c-1.68052,0 -4.06495,0.9005 -6.84257,2.53663a16.72275,16.72275 0 0 1 2.39078,1.57271c2.65078,-1.45856 4.0269,-1.59808 4.43276,-1.59808z"/> <path stroke="null" id="svg_2" d="m17.95567,2.57535a15.46011,15.46011 0 1 0 15.46011,15.46011a15.46011,15.46011 0 0 0 -15.46011,-15.46011zm4.29447,19.75458a68.13899,68.13899 0 0 1 -8.21676,7.06012a11.76686,11.76686 0 0 1 -2.37628,-1.14519a63.10014,63.10014 0 0 0 8.97259,-7.53537a62.6707,62.6707 0 0 0 7.55827,-8.97259a12.09897,12.09897 0 0 1 1.14519,2.36482a67.62938,67.62938 0 0 1 -7.08302,8.22821z"/></svg>', + db: + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="26" height="36" viewBox="0 0 26 36"><path stroke="null" id="svg_1" d="m12.92858,32.09526c-7.13873,0 -12.92858,-1.93175 -12.92858,-4.30953c0,-1.3004 0,-2.72254 0,-4.30953c0,-0.37493 0.18746,-0.73046 0.45681,-1.07738c1.44154,1.85633 6.45352,3.23215 12.47177,3.23215s11.03023,-1.37582 12.47177,-3.23215c0.26935,0.34692 0.45681,0.70245 0.45681,1.07738c0,1.24761 0,2.57171 0,4.30953c0,2.37778 -5.79093,4.30953 -12.92858,4.30953zm0,-8.61905c-7.13873,0 -12.92858,-1.93175 -12.92858,-4.30953c0,-1.30148 0,-2.72147 0,-4.30953c0,-0.2284 0.08619,-0.45035 0.20255,-0.67013l0,0c0.06572,-0.1379 0.15191,-0.27365 0.25426,-0.40725c1.44154,1.85525 6.45352,3.23215 12.47177,3.23215s11.03023,-1.37689 12.47177,-3.23215c0.10343,0.1336 0.18962,0.26935 0.25426,0.40725l0,0c0.11528,0.21979 0.20255,0.44173 0.20255,0.67013c0,1.24761 0,2.57063 0,4.30953c0,2.37778 -5.79093,4.30953 -12.92858,4.30953zm0,-8.61905c-7.13873,0 -12.92858,-1.93067 -12.92858,-4.30953c0,-0.68091 0,-1.4006 0,-2.15476c0,-0.68521 0,-1.39629 0,-2.15476c0,-2.37886 5.78985,-4.30953 12.92858,-4.30953s12.92858,1.93067 12.92858,4.30953c0,0.67229 0,1.38551 0,2.15476c0,0.65936 0,1.35535 0,2.15476c0,2.37886 -5.79093,4.30953 -12.92858,4.30953zm0,-10.77382c-4.75987,0 -8.61905,0.96318 -8.61905,2.15476s3.85918,2.15476 8.61905,2.15476s8.61905,-0.96318 8.61905,-2.15476s-3.85918,-2.15476 -8.61905,-2.15476z"/></svg>', + dbserver: + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="30" height="36" viewBox="0 0 30 36"><path stroke="null" id="svg_1" d="m13.43636,35.89747l4.41887,0l11.04719,0l4.41887,0l-19.88494,0l0.00001,0zm-11.04719,-22.35074l8.65437,0l12.70427,0l0.73574,0l2.20944,0l0,-13.41044l-26.51326,0l0,35.76118l11.04719,0l0,-2.23507l-8.83776,0l0,-2.23508l0,-17.8806l0.00001,0.00001zm0,-11.17536l22.09439,0l0,4.47014l-22.09439,0l0,-4.47014z"/> <path d="m29.57845,15.69168c0,0.60082 -3.23941,1.08788 -7.23544,1.08788m7.23544,-1.08788l0,0c0,0.60082 -3.23941,1.08788 -7.23544,1.08788c-3.99602,0 -7.23543,-0.48706 -7.23543,-1.08788m0,0l0,0c0,-0.60082 3.23941,-1.08788 7.23543,-1.08788c3.99602,0 7.23544,0.48706 7.23544,1.08788l0,4.35153c0,0.60082 -3.23941,1.08788 -7.23544,1.08788c-3.99602,0 -7.23543,-0.48706 -7.23543,-1.08788l0,-4.35153z" id="svg_2"/> <path d="m29.57476,23.23011c0,0.60082 -3.23941,1.08788 -7.23543,1.08788m7.23543,-1.08788l0,0c0,0.60082 -3.23941,1.08788 -7.23543,1.08788c-3.99602,0 -7.23543,-0.48706 -7.23543,-1.08788m0,0l0,0c0,-0.60082 3.23941,-1.08788 7.23543,-1.08788c3.99602,0 7.23543,0.48706 7.23543,1.08788l0,4.35153c0,0.60082 -3.23941,1.08788 -7.23543,1.08788c-3.99602,0 -7.23543,-0.48706 -7.23543,-1.08788l0,-4.35153z" id="svg_3" stroke="null"/> <path d="m29.5729,30.51667c0,0.60082 -3.23941,1.08788 -7.23543,1.08788m7.23543,-1.08788l0,0c0,0.60082 -3.23941,1.08788 -7.23543,1.08788c-3.99602,0 -7.23543,-0.48706 -7.23543,-1.08788m0,0l0,0c0,-0.60082 3.23941,-1.08788 7.23543,-1.08788c3.99602,0 7.23543,0.48706 7.23543,1.08788l0,4.35153c0,0.60082 -3.23941,1.08788 -7.23543,1.08788c-3.99602,0 -7.23543,-0.48706 -7.23543,-1.08788l0,-4.35153z" id="svg_4"/></svg>', + server: + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="26" height="36" viewBox="0 0 26 36"><path stroke="null" id="svg_1" d="m-0.13764,0.92824l0,34.34228l25.75671,0l0,-34.34228l-25.75671,0zm23.61032,27.9031l-21.42568,0.03825l-0.03825,-15.063l21.46393,0l0,15.02475zm0,-21.46392l-21.46393,0l0,-4.29279l21.46393,0l0,4.29279zm-2.14639,12.87835l-2.1464,0l0,-2.14639l2.1464,0l0,2.14639z"/></svg>', + pc: + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path stroke="null" id="svg_1" d="m28.01904,24.6202l-8.07171,0l0,3.57741l1.78675,0c0.32522,-0.01175 0.63477,0.15673 0.79933,0.43885c0.16849,0.28212 0.16849,0.63085 0,0.91297c-0.16849,0.28212 -0.47412,0.45061 -0.79933,0.43885l-10.72832,0c-0.49371,0 -0.89337,-0.39967 -0.89337,-0.89337s0.39967,-0.89337 0.89337,-0.89337l1.78675,0l0,-3.57741l-8.96508,0c-1.97483,0 -3.57741,-1.60259 -3.57741,-3.57741l0,-16.0964c0,-1.97483 1.60259,-3.5735 3.57741,-3.5735l24.19554,0c1.97483,0 3.5735,1.59867 3.57741,3.5735l0,16.09248c-0.00392,1.97483 -1.60651,3.57741 -3.58133,3.57741zm-25.98229,-5.36416l0,1.79067c0,0.98741 0.79933,1.78675 1.78675,1.78675l24.19554,0c0.98741,0 1.79067,-0.80325 1.79067,-1.78675l0,-1.79067l-27.77295,0zm0,0"/></svg>', + pad: + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="38" viewBox="0 0 32 38"><path d="m28.84877,0.63462l-25.95664,0c-1.19162,0 -2.17601,0.98438 -2.17601,2.17601l0,32.82142c0,1.19162 0.98438,2.17601 2.17601,2.17601l25.95664,0c1.19162,0 2.17601,-0.98438 2.17601,-2.17601l0,-32.82142c0.0259,-1.19162 -0.95848,-2.17601 -2.17601,-2.17601zm-12.97832,33.62447c-0.67353,0 -1.21753,-0.544 -1.21753,-1.21753s0.544,-1.21753 1.21753,-1.21753s1.21753,0.544 1.21753,1.21753s-0.544,1.21753 -1.21753,1.21753z"/></svg>' +} + +export default nodeIcon diff --git a/src/components/serfDiagram/index.vue b/src/components/serfDiagram/index.vue new file mode 100644 index 0000000..0e87121 --- /dev/null +++ b/src/components/serfDiagram/index.vue @@ -0,0 +1,288 @@ +<template lang='pug'> + .net + .arrow_box(:style="toolTipStyle") + p {{toolTipAddr}} + d3-network( + ref='net' + :net-nodes="nodes" + :net-links="links" + :options="options" + :selection="{nodes: nodeSelected, links: linksSelected}" + @drag-start='dragStart' + @node-click='nodeClick' + @node-hover='nodeHover' + @node-out='nodeOut' + ) +</template> + +<script> +import D3Network from "./vue-d3-network"; +import RoleIcon from "./icons.js"; + +export default { + name: "SerfDiagram", + components: { + D3Network + }, + props: { + agent: String, + members: Array + }, + data() { + return { + nodeSize: 20, + fontSize: 20, + canvas: false, + toolTipStyle: { + display: "none", + height: "30px", + width: "120px" + } + }; + }, + computed: { + nodes() { + let n = new Array(); + this.members.forEach((v, i) => { + n.push({ + id: i, + name: v.nodeName, + svgSym: RoleIcon[v.role], + _color: + this.agent === v.nodeName + ? "red" + : v.role === "master" + ? "orange" + : "" + }); + }); + + return n; + }, + links() { + let arr = new Array(); + let dup = new Array(); // Deduplicate to ensure that two nodes have only one line + const count = this.members.length; + + switch (count) { + case 0: + case 1: + break; + case 2: + arr = [{ sid: 0, tid: 1 }]; + break; + case 3: + arr = [{ sid: 0, tid: 1 }, { sid: 1, tid: 2 }, { sid: 0, tid: 2 }]; + break; + default: + for (let i = 0; i < count; i++) { + let loop = Math.round(Math.random() * 5 + 2); // At least 2 times + for (let j = 0; j < loop; j++) { + let target = Math.round(Math.random() * (count - 1)); + if (target === i) { + // is me? skip + continue; + } + + if (!dup["d" + target + i]) { + arr.push({ sid: i, tid: target }); + dup["d" + i + target] = 1; + } + } + } + } + + return arr; + }, + options() { + return { + force: 3000, + nodeSize: this.nodeSize, + fontSize: this.fontSize, + nodeLabels: true, + canvas: this.canvas, + linkWidth: 0, + size: { + w: 745, + h: 426 + } + }; + } + }, + created() { + this.reset(); + }, + methods: { + nodeHover(event, node) { + console.log(node); + node._opacity = 1; + node._size = 28; + let width = document.body.clientWidth; + this.toolTipStyle.display = "block"; + this.toolTipStyle.top = node.y - 10 + "px"; + this.toolTipStyle.left = node.x + width / 2 - 30 + "px"; + + this.toolTipNode = this.members[node.id].nodeName; + this.toolTipAddr = this.members[node.id].Address; + }, + nodeOut(event, node) { + node._opacity = node.opacity; + node._size = node.size; + this.toolTipStyle.display = "none"; + }, + dragStart(event) { + if (event) { + this.movement = event.timeStamp; + } + }, + nodeClick(event, node) { + // if (this.nodeSelected[node.id]) { + // this.unSelectNode(node.id) + // // is not nodeSelected + // } else { + // this.selectNode(node) + + // } + // this.selectNodesLinks() + // this.$set(this.nodes, node.index, node) + + if (event.timeStamp - this.movement < 200) { + this.$emit("selected-node", event, this.members[node.id]); + } + }, + reset() { + this.nodeSelected = {}; + this.linksSelected = {}; + (this.toolTipNode = ""), (this.toolTipAddr = ""), (this.movement = 0); + }, + unSelectNode(nodeId) { + if (this.nodeSelected[nodeId]) { + delete this.nodeSelected[nodeId]; + } + this.selectNodesLinks(); + }, + unSelectLink(linkId) { + if (this.linksSelected[linkId]) { + delete this.linksSelected[linkId]; + } + }, + selectNode(node) { + this.nodeSelected[node.id] = node; + }, + selectLink(link) { + this.$set(this.linksSelected, link.id, link); + }, + selectNodesLinks() { + for (let link of this.links) { + // node is nodeSelected + if (this.nodeSelected[link.sid] || this.nodeSelected[link.tid]) { + this.selectLink(link); + } else { + this.unSelectLink(link.id); + } + } + } + } +}; +</script> + +<style> +.net { + height: 100%; + margin: 0; +} + +.node { + /* stroke: rgba(18, 120, 98, 0.7); */ + stroke: rgba(76, 78, 78, 0.7); + stroke-width: 3px; + -webkit-transition: fill 0.5s ease; + transition: fill 0.5s ease; + /* fill: #dcfaf3; */ + fill: #e3e4e4; +} + +.node.selected { + stroke: #caa455; +} + +.node.pinned { + stroke: rgba(190, 56, 93, 0.6); +} + +.link { + stroke: rgba(18, 120, 98, 0.3); +} + +.link, +.node { + stroke-linecap: round; +} + +.link:hover, +.node:hover { + stroke: #df8108; + stroke-width: 1px; + cursor: pointer; +} + +.link.selected { + stroke: rgba(202, 164, 85, 0.6); +} + +.curve { + fill: none; +} + +.link-label, +.node-label { + /* fill: #127862; */ + fill: rgba(76, 78, 78, 0.7); +} + +.link-label { + -webkit-transform: translateY(-0.5em); + transform: translateY(-0.5em); + text-anchor: middle; +} + +.arrow_box { + position: absolute; + background: #fff; + /* border: 1px solid #127862; */ + border: 1px solid rgba(76, 78, 78, 0.7); + font-size: 11px; + padding-left: 5px; +} + +.arrow_box p { + height: 30px; + line-height: 30px; + width: 100px; + overflow: hidden; +} +.arrow_box:after, +.arrow_box:before { + right: 100%; + top: 50%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} + +.arrow_box:after { + border-color: rgba(136, 183, 213, 0); + border-right-color: #fff; + border-width: 5px; + margin-top: -5px; +} +.arrow_box:before { + border-color: rgba(194, 225, 245, 0); + border-right-color: #323333; + border-width: 6px; + margin-top: -6px; +} +</style> diff --git a/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.eot b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.eot new file mode 100644 index 0000000..aa85672 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.eot Binary files differ diff --git a/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.svg b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.svg new file mode 100644 index 0000000..62f4915 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.svg @@ -0,0 +1,28 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata>Generated by IcoMoon</metadata> +<defs> +<font id="vue-d3-icons" horiz-adv-x="1024"> +<font-face units-per-em="1024" ascent="960" descent="-64" /> +<missing-glyph horiz-adv-x="1024" /> +<glyph unicode=" " horiz-adv-x="512" d="" /> +<glyph unicode="" glyph-name="pointer, mouse" d="M531.291 380.328l148.709-345.66-112.001-55.999-130.087 354.984-205.913-186.984v727.999l559.999-448.001-260.707-46.339z" /> +<glyph unicode="" glyph-name="move, drag" d="M575.488 749.195v-258.016h256v128l192.512-192.512-192.512-192.48v130.976h-256v-258.016h128.992l-192.48-192.48-192.512 192.48h128v258.016h-256v-129.984l-191.488 191.488 191.488 191.488v-126.976h256v258.016h-124.992l189.504 189.472 189.504-189.472h-126.016z" /> +<glyph unicode="" glyph-name="pin2" horiz-adv-x="519" d="M196 234.667l64-320 64 320c-20-2-43-3-64-3s-44 1-64 3zM450 533.667c-33 17-62 59-62 85v64c0 22 12 39 23 52 15 13 24 29 24 45 0 53-61 95-175 95s-175-42-175-95c0-16 9-32 24-45 11-13 23-30 23-52v-64c0-26-29-68-62-85-38-19-70-54-70-88 0-74 101-148 260-148s260 73 260 148c0 33-31 68-70 88z" /> +<glyph unicode="" glyph-name="repo-forked" horiz-adv-x="768" d="M720.048 762.715c0 62.135-49.881 112.016-112.016 112.016s-112.016-49.881-112.016-112.016c0-41.132 22.754-77.885 56.008-97.139v-92.764l-168.024-185.525-168.024 185.525v92.764c33.254 19.252 56.008 55.134 56.008 97.139 0 62.135-49.881 112.016-112.016 112.016s-112.016-49.881-112.016-112.016c0-41.132 22.754-77.885 56.008-97.139v-136.518l224.032-246.783v-95.389c-33.254-19.252-56.008-55.134-56.008-97.139 0-62.135 49.881-112.016 112.016-112.016s112.016 49.881 112.016 112.016c0 41.132-22.754 77.885-56.008 97.139v95.389l224.032 246.783v136.518c33.254 19.252 56.008 55.134 56.008 97.139zM159.968 817.846c29.755 0 54.257-24.503 54.257-54.257s-24.503-54.257-54.257-54.257-54.257 24.503-54.257 54.257 24.503 54.257 54.257 54.257zM384 38.113c-29.755 0-54.257 24.503-54.257 54.257s24.503 54.257 54.257 54.257 54.257-24.503 54.257-54.257-24.503-54.257-54.257-54.257zM608.032 817.846c29.755 0 54.257-24.503 54.257-54.257s-24.503-54.257-54.257-54.257-54.257 24.503-54.257 54.257 24.503 54.257 54.257 54.257z" /> +<glyph unicode="" glyph-name="reload-alt, refresh, reset, arrow" d="M576 170.667c141.248 0 256 114.752 256 256s-114.752 256-256 256-256-114.752-256-256v-128l128.64-0.736-192.64-192.384-192 192.384h128v128.736c0 212 172 384 384 384s384-172 384-384-172-384-384-384v128z" /> +<glyph unicode="" glyph-name="cubes" horiz-adv-x="1243" d="M365.714 6.096l219.429 109.714v179.429l-219.429-93.714v-195.429zM329.143 265.524l230.857 98.857-230.857 98.857-230.857-98.857zM950.857 6.096l219.429 109.714v179.429l-219.429-93.714v-195.429zM914.286 265.524l230.857 98.857-230.857 98.857-230.857-98.857zM658.286 432.953l219.429 94.286v152l-219.429-93.714v-152.571zM621.714 649.524l252 108-252 108-252-108zM1243.429 353.524v-237.714c0-27.429-15.429-53.143-40.571-65.143l-256-128c-10.286-5.714-21.143-8-32.571-8s-22.286 2.286-32.571 8l-256 128c-1.714 0.571-2.857 1.143-4 2.286-1.143-1.143-2.286-1.714-4-2.286l-256-128c-10.286-5.714-21.143-8-32.571-8s-22.286 2.286-32.571 8l-256 128c-25.143 12-40.571 37.714-40.571 65.143v237.714c0 29.143 17.714 55.429 44.571 67.429l248 106.286v228.571c0 29.143 17.714 55.429 44.571 67.429l256 109.714c9.143 4 18.857 5.714 28.571 5.714s19.429-1.714 28.571-5.714l256-109.714c26.857-12 44.571-38.286 44.571-67.429v-228.571l248-106.286c27.429-12 44.571-38.286 44.571-67.429z" /> +<glyph unicode="" glyph-name="cube" horiz-adv-x="951" d="M512 7.81l365.714 199.429v363.429l-365.714-133.143v-429.714zM475.429 502.096l398.857 145.143-398.857 145.143-398.857-145.143zM950.857 646.096v-438.857c0-26.857-14.857-51.429-38.286-64l-402.286-219.429c-10.857-6.286-22.857-9.143-34.857-9.143s-24 2.857-34.857 9.143l-402.286 219.429c-23.429 12.571-38.286 37.143-38.286 64v438.857c0 30.857 19.429 58.286 48 68.571l402.286 146.286c8 2.857 16.571 4.571 25.143 4.571s17.143-1.714 25.143-4.571l402.286-146.286c28.571-10.286 48-37.714 48-68.571z" /> +<glyph unicode="" glyph-name="pin" d="M713.771 756.438c-16.597 16.683-43.563 16.768-60.331 0.171-4.437-4.437-7.509-9.685-9.6-15.147-35.499-74.069-74.581-115.84-123.904-140.501-55.339-27.307-118.869-46.293-221.269-46.293-5.547 0-11.093-1.067-16.299-3.243-10.453-4.352-18.731-12.672-23.083-23.083-4.309-10.411-4.309-22.187 0-32.597 2.176-5.248 5.291-9.984 9.259-13.909l138.368-138.368-193.579-258.133 258.133 193.579 138.325-138.325c3.925-4.011 8.661-7.083 13.909-9.259 5.205-2.176 10.752-3.328 16.299-3.328s11.093 1.152 16.299 3.328c10.453 4.352 18.773 12.587 23.083 23.083 2.176 5.163 3.285 10.752 3.285 16.256 0 102.4 18.944 165.931 46.208 220.416 24.619 49.323 66.389 88.405 140.501 123.904 5.504 2.091 10.709 5.163 15.104 9.6 16.597 16.768 16.512 43.733-0.171 60.331l-170.539 171.52z" /> +<glyph unicode="" glyph-name="menu" d="M128 682.667h768v-86h-768v86zM128 384.667v84h768v-84h-768zM128 170.667v86h768v-86h-768z" /> +<glyph unicode="" glyph-name="camera" d="M512 212.667c118 0 214 96 214 214s-96 214-214 214-214-96-214-214 96-214 214-214zM384 852.667h256l78-84h136c46 0 84-40 84-86v-512c0-46-38-86-84-86h-684c-46 0-84 40-84 86v512c0 46 38 86 84 86h136zM376 426.667c0 76 60 136 136 136s136-60 136-136-60-136-136-136-136 60-136 136z" /> +<glyph unicode="" glyph-name="delete_forever" d="M662 768.667h148v-86h-596v86h148l44 42h212zM360 432.667l92-92-90-90 60-60 90 90 90-90 60 60-90 90 90 92-60 60-90-92-90 92zM256 128.667v512h512v-512c0-46-40-86-86-86h-340c-46 0-86 40-86 86z" /> +<glyph unicode="" glyph-name="delete" d="M810 768.667v-86h-596v86h148l44 42h212l44-42h148zM256 128.667v512h512v-512c0-46-40-86-86-86h-340c-46 0-86 40-86 86z" /> +<glyph unicode="" glyph-name="settings" d="M512 276.667c82 0 150 68 150 150s-68 150-150 150-150-68-150-150 68-150 150-150zM830 384.667l90-70c8-6 10-18 4-28l-86-148c-6-10-16-12-26-8l-106 42c-22-16-46-32-72-42l-16-112c-2-10-10-18-20-18h-172c-10 0-18 8-20 18l-16 112c-26 10-50 24-72 42l-106-42c-10-4-20-2-26 8l-86 148c-6 10-4 22 4 28l90 70c-2 14-2 28-2 42s0 28 2 42l-90 70c-8 6-10 18-4 28l86 148c6 10 16 12 26 8l106-42c22 16 46 32 72 42l16 112c2 10 10 18 20 18h172c10 0 18-8 20-18l16-112c26-10 50-24 72-42l106 42c10 4 20 2 26-8l86-148c6-10 4-22-4-28l-90-70c2-14 2-28 2-42s0-28-2-42z" /> +<glyph unicode="" glyph-name="equalizerh" d="M448 810.667v16c0 26.4-21.6 48-48 48h-160c-26.4 0-48-21.6-48-48v-16h-192v-128h192v-16c0-26.4 21.6-48 48-48h160c26.4 0 48 21.6 48 48v16h576v128h-576zM256 682.667v128h128v-128h-128zM832 506.667c0 26.4-21.6 48-48 48h-160c-26.4 0-48-21.6-48-48v-16h-576v-128h576v-16c0-26.4 21.6-48 48-48h160c26.4 0 48 21.6 48 48v16h192v128h-192v16zM640 362.667v128h128v-128h-128zM448 186.667c0 26.4-21.6 48-48 48h-160c-26.4 0-48-21.6-48-48v-16h-192v-128h192v-16c0-26.4 21.6-48 48-48h160c26.4 0 48 21.6 48 48v16h576v128h-576v16zM256 42.667v128h128v-128h-128z" /> +<glyph unicode="" glyph-name="equalizerv" d="M896 490.667h16c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v192h-128v-192h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-576h128v576zM768 682.667h128v-128h-128v128zM592 106.667c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v576h-128v-576h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-192h128v192h16zM448 298.667h128v-128h-128v128zM272 490.667c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v192h-128v-192h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-576h128v576h16zM128 682.667h128v-128h-128v128z" /> +<glyph unicode="" glyph-name="github" d="M512.008 926.025c-282.738 0-512.008-229.218-512.008-511.998 0-226.214 146.704-418.132 350.136-485.836 25.586-4.738 34.992 11.11 34.992 24.632 0 12.204-0.48 52.542-0.696 95.324-142.448-30.976-172.504 60.41-172.504 60.41-23.282 59.176-56.848 74.916-56.848 74.916-46.452 31.778 3.51 31.124 3.51 31.124 51.4-3.61 78.476-52.766 78.476-52.766 45.672-78.27 119.776-55.64 149.004-42.558 4.588 33.086 17.852 55.68 32.506 68.464-113.73 12.942-233.276 56.85-233.276 253.032 0 55.898 20.004 101.574 52.76 137.428-5.316 12.9-22.854 64.972 4.952 135.5 0 0 43.006 13.752 140.84-52.49 40.836 11.348 84.636 17.036 128.154 17.234 43.502-0.198 87.336-5.886 128.256-17.234 97.734 66.244 140.656 52.49 140.656 52.49 27.872-70.528 10.35-122.6 5.036-135.5 32.82-35.856 52.694-81.532 52.694-137.428 0-196.654-119.778-239.95-233.79-252.624 18.364-15.89 34.724-47.046 34.724-94.812 0-68.508-0.596-123.644-0.596-140.508 0-13.628 9.222-29.594 35.172-24.566 203.322 67.776 349.842 259.626 349.842 485.768 0 282.78-229.234 511.998-511.992 511.998z" /> +<glyph unicode="" glyph-name="git-merge" horiz-adv-x="768" d="M615.62 484.571c-43.089 0-80.185-23.806-100.089-58.724-5.202 0.368-10.291 0.82-15.721 0.82-118.58 0-231.11 90.336-272.164 202.158 24.683 21.233 40.544 52.335 40.544 87.366 0 63.926-51.882 115.81-115.81 115.81s-115.81-51.882-115.81-115.81c0-42.722 23.382-79.676 57.904-99.779v-379.519c-34.522-20.074-57.904-57-57.904-99.75 0-63.899 51.882-115.81 115.81-115.81s115.81 51.911 115.81 115.81c0 42.75-23.382 79.676-57.904 99.75v208.349c76.142-80.551 181.291-134.385 289.524-134.385 5.767 0 10.517 0.396 15.721 0.565 20.017-34.777 57.113-58.471 100.089-58.471 63.899 0 115.81 51.911 115.81 115.81 0 63.926-51.911 115.81-115.81 115.81zM152.38 79.239c-31.949 0-57.904 25.899-57.904 57.904 0 31.949 25.956 57.904 57.904 57.904 32.034 0 57.904-25.956 57.904-57.904 0-32.006-25.87-57.904-57.904-57.904zM152.38 658.287c-31.949 0-57.904 25.87-57.904 57.904s25.956 57.904 57.904 57.904c32.034 0 57.904-25.87 57.904-57.904s-25.87-57.904-57.904-57.904zM615.62 310.857c-31.949 0-57.904 25.899-57.904 57.904 0 32.034 25.956 57.904 57.904 57.904 32.006 0 57.904-25.87 57.904-57.904 0-32.006-25.899-57.904-57.904-57.904z" /> +<glyph unicode="" glyph-name="pulse" horiz-adv-x="896" d="M736 426.729l-172.812 166.344-140.782-198.406-70.406 441.594-199.562-409.532h-152.438v-128.062h230.406l57.594 115.188 57.594-345.562 230.406 326.374 102.375-96h217.625v128.062h-160z" /> +</font></defs></svg> \ No newline at end of file diff --git a/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.ttf b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.ttf new file mode 100644 index 0000000..1c2b915 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.ttf Binary files differ diff --git a/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.woff b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.woff new file mode 100644 index 0000000..8db129b --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/css/fonts/vue-d3-icons.woff Binary files differ diff --git a/src/components/serfDiagram/vue-d3-network/assets/css/icons.css b/src/components/serfDiagram/vue-d3-network/assets/css/icons.css new file mode 100644 index 0000000..f43041c --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/css/icons.css @@ -0,0 +1,95 @@ +@font-face { + font-family: 'vue-d3-icons'; + src: url('fonts/vue-d3-icons.eot?oa3tyj'); + src: url('fonts/vue-d3-icons.eot?oa3tyj#iefix') format('embedded-opentype'), + url('fonts/vue-d3-icons.ttf?oa3tyj') format('truetype'), + url('fonts/vue-d3-icons.woff?oa3tyj') format('woff'), + url('fonts/vue-d3-icons.svg?oa3tyj#vue-d3-icons') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'vue-d3-icons' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-reload-alt:before { + content: "\e904"; +} +.icon-refresh:before { + content: "\e904"; +} +.icon-reset:before { + content: "\e904"; +} +.icon-arrow:before { + content: "\e904"; +} +.icon-git-merge:before { + content: "\f023"; +} +.icon-pulse:before { + content: "\f085"; +} +.icon-pointer:before { + content: "\e900"; +} +.icon-mouse:before { + content: "\e900"; +} +.icon-move:before { + content: "\e901"; +} +.icon-drag:before { + content: "\e901"; +} +.icon-cubes:before { + content: "\e907"; +} +.icon-cube:before { + content: "\e908"; +} +.icon-pin:before { + content: "\e909"; +} +.icon-menu:before { + content: "\e90a"; +} +.icon-camera:before { + content: "\e90b"; +} +.icon-delete_forever:before { + content: "\e90c"; +} +.icon-delete:before { + content: "\e90d"; +} +.icon-settings:before { + content: "\e90e"; +} +.icon-pin2:before { + content: "\e902"; +} +.icon-repo-forked:before { + content: "\e903"; +} +.icon-equalizerh:before { + content: "\e992"; +} +.icon-equalizerv:before { + content: "\e993"; +} +.icon-github:before { + content: "\eab0"; +} diff --git a/src/components/serfDiagram/vue-d3-network/assets/github.svg b/src/components/serfDiagram/vue-d3-network/assets/github.svg new file mode 100644 index 0000000..158038f --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/github.svg @@ -0,0 +1 @@ +<svg height="128" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" width="128" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg> \ No newline at end of file diff --git a/src/components/serfDiagram/vue-d3-network/assets/node.svg b/src/components/serfDiagram/vue-d3-network/assets/node.svg new file mode 100644 index 0000000..b6de4ff --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/assets/node.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 33.866666 33.866668"> + <g id="fill" style="opacity:1;" transform="matrix(0.2575943,0,0,0.23849115,-9.1120023,-50.435759)"> + <path id="path8251-2-6-5-9-2" d="m 156.78907,230.06236 a 54.165703,13.707579 0 0 1 -54.1657,13.70758 54.165703,13.707579 0 0 1 -54.165706,-13.70758 54.165703,13.707579 0 0 1 54.165706,-13.70758 54.165703,13.707579 0 0 1 54.1657,13.70758 z M 48.404512,229.55428 v 0.2202 c 0.01214,-0.0734 0.02647,-0.14685 0.04327,-0.2202 z m 108.290078,0 c 0.0147,0.083 0.0269,0.16638 0.0356,0.24943 2.4e-4,7.57053 -24.25098,13.70738 -54.16604,13.70738 -29.849952,-7.9e-4 -54.071017,-6.11278 -54.159668,-13.6668 v 31.89855 a 54.184263,15.828606 0 0 1 -0.183897,-1.1851 v 37.13064 a 54.184263,15.828607 0 0 0 -0.0057,0.0269 54.184263,15.828607 0 0 0 0.0057,0.0388 v 0.45411 h 0.04136 v 36.24689 a 54.184263,15.828607 0 0 0 -0.0057,0.0269 54.184263,15.828607 0 0 0 0.0057,0.0388 v 0.45411 h 0.05536 a 54.184263,15.828607 0 0 0 54.124675,15.33644 54.184263,15.828607 0 0 0 54.09986,-15.33644 h 0.0891 v -37.98873 h -0.0414 a 54.184263,15.828606 0 0 1 0.035,0.28702 54.184263,15.828606 0 0 1 -0.035,0.20408 v -0.4911 -34.41793 c 0.0186,-0.0385 0.0395,-0.0767 0.0573,-0.11517 0.18386,-10.752 0.0891,-21.98037 0.0891,-32.89866 z M 48.220615,260.2188 v 0.25123 a 54.184263,15.828606 0 0 1 0.04327,-0.25123 z"/> + </g> + <g transform="matrix(0.31703209,0,0,0.2753999,-15.226615,0.59173245)"> + <path id="bottom" d="m 58.574418,71.818443 v 0.21756 a 44.004366,13.707578 0 0 1 0.03481,-0.21756 z m 87.975532,5.3e-4 a 44.004366,13.707578 0 0 1 0.0281,0.24857 44.004366,13.707578 0 0 1 -44.00433,13.70766 44.004366,13.707578 0 0 1 -43.999312,-13.66323 v 32.155137 a 44.004366,13.707579 0 0 0 -0.0045,0.0233 44.004366,13.707579 0 0 0 0.0045,0.0336 v 0.39325 h 0.04496 a 44.004366,13.707579 0 0 0 43.955642,13.28134 44.004366,13.707579 0 0 0 43.93593,-13.28136 h 0.0726 V 71.818963 Z" style="opacity:0.2;fill:black"/> + <path id="mid" d="m 58.540832,39.978483 v 0.21756 a 44.004366,13.707578 0 0 1 0.03481,-0.21756 z m 87.975528,5.3e-4 a 44.004366,13.707578 0 0 1 0.0281,0.24857 44.004366,13.707578 0 0 1 -44.00432,13.70769 44.004366,13.707578 0 0 1 -43.99931,-13.66326 v 32.15514 a 44.004366,13.707579 0 0 0 -0.0045,0.0233 44.004366,13.707579 0 0 0 0.0045,0.0336 v 0.39325 h 0.04487 a 44.004366,13.707579 0 0 0 43.95565,13.28136 44.004366,13.707579 0 0 0 43.93592,-13.28136 h 0.0726 v -32.8983 z" style="opacity:0.3;fill:black"/> + <g transform="matrix(0.81212445,0,0,0.86600028,19.379501,-185.37111)"> + <path id="top" d="m 182.94531,867.60742 v 0.83203 c 0.0459,-0.27745 0.10057,-0.5548 0.16407,-0.83203 z m 409.28711,0 c 0.0555,0.31369 0.0998,0.62751 0.13281,0.94141 9.1e-4,28.61302 -91.65592,51.80858 -204.7207,51.80859 -112.81873,-0.003 -204.36415,-23.10367 -204.69922,-51.6543 v 121.54493 c -0.006,0.0293 -0.0118,0.0586 -0.0176,0.0879 0.006,0.0417 0.0115,0.0833 0.0176,0.125 v 1.48633 h 0.20899 c 9.08883,25.83352 97.38326,56.20372 207.91946,56.22112 110.50057,-0.03 187.36844,-26.7045 200.97702,-56.22112 0.69493,-40.63748 0.33789,-83.07388 0.33789,-124.33986 z" style="opacity:0.4;fill:black" transform="scale(0.26458333)"/> + <ellipse id="cap" cx="102.62337" cy="230.06236" rx="54.165703" ry="13.707579" style="opacity:0.5;fill:black"/> + </g> + </g> +</svg> diff --git a/src/components/serfDiagram/vue-d3-network/components/canvasRenderer.vue b/src/components/serfDiagram/vue-d3-network/components/canvasRenderer.vue new file mode 100644 index 0000000..58342ad --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/components/canvasRenderer.vue @@ -0,0 +1,452 @@ +<template lang="pug"> + canvas(id='canvas' ref='canvas' + :width='size.w' + :height='size.h' + :style='canvasStyle' + @mouseup.prevent='canvasClick' + @mousedown.prevent='canvasClick' + @touchstart.prevent='canvasClick' + @touchend.passive='canvasClick' + v-render-canvas='{links, nodes}' + ) +</template> +<script> +import canvasStyles from '../lib/js/canvasStyles.js' +import stylePicker from '../lib/js/stylePicker.js' +import svgExport from '../lib/js/svgExport.js' +export default { + name: 'canvas-renderer', + props: [ + 'size', + 'offset', + 'padding', + 'nodes', + 'selected', + 'linksSelected', + 'links', + 'nodeSize', + 'fontSize', + 'strLinks', + 'linkWidth', + 'nodeLabels', + 'labelOffset', + 'canvasStyles', + 'nodeSym', + 'noNodes' + ], + data () { + return { + hitCanvas: null, + shapes: {}, + drag: null, + stylesReady: false, + CssStyles: true, // load style from css props + // canvas styles + styles: canvasStyles, + sprites: {} + } + }, + computed: { + nodeSvg () { + return this.nodeSym + }, + canvasStyle () { + let left = this.padding.x + 'px' + let top = this.padding.y + 'px' + return { left, top } + } + }, + directives: { + renderCanvas (canvas, data, vnode) { + let nodes = data.value.nodes + let links = data.value.links + vnode.context.draw(nodes, links, canvas) + } + }, + created () { + if (this.canvasStyles) { + for (let o in this.canvasStyles) { + this.styles[o] = this.canvasStyles[o] + } + } + }, + mounted () { + let vm = this + this.$nextTick(() => { + vm.hitCanvas.width = vm.size.w + vm.hitCanvas.height = vm.size.h + }) + }, + watch: { + nodeSize () { + this.resetSprites() + }, + canvasStyles () { + this.resetSprites() + } + }, + methods: { + // canvas to png + canvasScreenShot (cb, bgColor) { + let graph = this.$refs.canvas + let canvas = document.createElement('canvas') + canvas.width = graph.width + canvas.height = graph.height + // background color + let background = this.styles.background + if (bgColor) background = this.getCssColor(bgColor) + let ctx = canvas.getContext('2d') + ctx = this.setCtx(ctx, background) + ctx.fillRect(0, 0, canvas.width, canvas.height) + ctx.drawImage(graph, 0, 0) + let img = canvas.toDataURL('image/png') + if (img) cb(null, img) + else cb(new Error('error generating canvas image')) + }, + // emits events as 'action' + emit (e, args) { + this.$emit('action', e, args) + }, + // creates 'virtual' canvas to catch mouse interaction + canvasInit () { + let hitCanvas = document.createElement('canvas') + hitCanvas.width = this.size.w + hitCanvas.height = this.size.h + hitCanvas.top = this.offset.y + hitCanvas.left = this.offset.x + hitCanvas.id = 'hit-canvas' + this.hitCanvas = hitCanvas + this.resetSprites() + }, + resetSprites () { + this.sprites = {} + let sprites = ['node', 'nodeSelected', 'nodePinned', 'nodeSelectedPinned'] + for (let sp of sprites) { + this.sprites[sp] = this.nodeSprite(this.styles[sp]) + } + }, + // canvas click handler + canvasClick (event) { + let hitCtx = this.hitCanvas.getContext('2d') + let e = (event.touches) ? event.touches[0] || event.changedTouches[0] : event + let scrollTop = document.body.scrollTop + let scrollLeft = document.body.scrollLeft + let x = e.clientX + scrollLeft - this.padding.x + let y = e.clientY + scrollTop - this.padding.y + + let pixel = hitCtx.getImageData(x, y, 1, 1).data + let color = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})` + let shape = this.shapes[color] + if (shape) { + let col = shape.type + 's' + let item = this[col][shape.index] + if (item) { + if (event.type === 'mouseup' || event.type === 'touchend') { + if (this.drag) { + this.drag = null + this.emit('dragEnd') + } + this.emit(shape.type + 'Click', [event, item]) + } else if (event.type === 'mousedown' || event.type === 'touchstart') { + this.drag = item + this.emit('dragStart', [event, item.index]) + } + } + } + }, + // draw circ node to canvas + drawNode (ctx, node) { + ctx.beginPath() + ctx.arc(node.x, node.y, this.nodeSize / 2, 0, 2 * Math.PI, false) + let fillStyle = ctx.fillStyle + let strokeStyle = ctx.strokeStyle + if (node._color) ctx.fillStyle = node._color + if (node._borderColor) ctx.strokeStyle = node._borderColor + ctx.fill() + ctx.stroke() + ctx.closePath() + ctx.fillStyle = fillStyle + ctx.strokeStyle = strokeStyle + }, + // draw link to canvas + drawLink (ctx, link) { + ctx.beginPath() + ctx.moveTo(link.source.x, link.source.y) + ctx.lineTo(link.target.x, link.target.y) + ctx.lineWidth = this.linkWidth + ctx.strokeStyle = (link._color) ? link._color : link.color + ctx.stroke() + }, + // draw text to canvas + drawText (item, ctx, style, key) { + ctx = this.setCtx(ctx, style) + if (this.fontSize) ctx.font = this.fontSize + 'px ' + style.fontFamily + let text = (key) ? item[key] : item.name + // let x = (item.size) ? item.x + item.size : item.x + // let y = (item.size) ? item.y + (item.size / 2) : item.y + let x = item.x + this.labelOffset.x + let y = item.y + this.labelOffset.y + ctx.fillText(text, x, y) + }, + // render canvas + draw (nodes, links, canvas) { + if (!this.hitCanvas) this.canvasInit() + let ctx = canvas.getContext('2d') + let hitCtx = this.hitCanvas.getContext('2d') + if (!this.stylesReady && this.CssStyles) { + this.getCssStyles() + this.resetSprites() + } + // clean canvas + ctx.clearRect(0, 0, this.size.w, this.size.h) + + // draw links + ctx = this.setCtx(ctx, this.styles.link) + for (let link of links) { + if (!this.linksSelected[link.id]) { + this.drawLink(ctx, link) + } + this.mapShape(link, 'link', this.drawLink, hitCtx) + } + + // draw selected links + ctx = this.setCtx(ctx, this.styles.linkSelected) + for (let lid in this.linksSelected) { + let link = this.linksSelected[lid] + + if (this.isOnView(link.source) && this.isOnView(link.target)) { + this.drawLink(ctx, link) + } + } + + // draw nodes + ctx = this.setCtx(ctx, this.styles.node) + for (let node of nodes) { + if (this.isOnView(node)) { + if (!this.noNodes) { + let sprite = this.getNodeSprite(node) + ctx.drawImage(sprite, node.x - sprite.width / 2, node.y - sprite.height / 2) + // map node shape + this.mapShape(node, 'node', this.drawNode, hitCtx) + } + // draw node labels + if (this.nodeLabels) { + node.size = this.nodeSize + this.drawText(node, ctx, this.labelStyle(node)) + // ctx = this.setCtx(ctx, this.styles.node) + } + } + } + // draw selected nodes + ctx = this.setCtx(ctx, this.styles.nodeSelected) + for (let nid in this.selected) { + let node = this.selected[nid] + if (this.isOnView(node)) { + // this.drawNode(node, ctx) + // let sprite = this.sprites.nodeSelected + let sprite = this.getNodeSprite(node) + ctx.drawImage(sprite, node.x - sprite.width / 2, node.y - sprite.height / 2) + } + } + }, + getNodeSprite (node) { + let name = this.nodeSpriteName(node) + let sprite = this.sprites[name] + if (!sprite) { // set style and create sprite + let style = this.loadNodeStyle(node) + sprite = this.nodeSprite(style) + this.sprites[name] = sprite + } + return sprite + }, + nodeSpriteName (node) { + let name = 'node' + if (this.selected[node.id]) name += 'Selected' + if (node.pinned) name += 'Pinned' + if (node._cssClass) name += '-' + node._cssClass + if (node._color) name += '-' + stylePicker.compColor(node._color) + return name + }, + nodeSprite (style) { + let size = this.nodeSize + this.styles.node.lineWidth + let canvasSize = (this.nodeSvg) ? size : size * 2 + let canvas = this.spriteCanvas(canvasSize) + let ctx = canvas.getContext('2d') + if (this.nodeSvg) { + let attrs = { width: size, height: size, class: style._cssClass || '', style: style._cssStyle || '' } + let url = svgExport.svgDataToUrl(this.nodeSvg, attrs) + if (url) { + let img = new Image() + img.onload = () => { + ctx.drawImage(img, 0, 0) + URL.revokeObjectURL(url) + } + img.onerror = (error) => { + // eslint-disable-next-line + console.log('error creating node image', error) + } + img.src = url + } + } else { + ctx = this.setCtx(ctx, style) + this.drawNode(ctx, { x: size, y: size }) + } + return canvas + }, + spriteCanvas (size) { + let canvas = document.createElement('canvas') + canvas.width = size + canvas.height = size + return canvas + }, + isOnView (obj) { + return (obj.x > 0 && obj.y > 0 && obj.x < this.size.w && obj.y < this.size.h) + }, + // index shapes by random colors + mapShape (shape, type, drawFunc, hitCtx) { + // search unique color index + if (!shape.colorIndex) shape.colorIndex = this.newColorIndex() + let nShape = Object.assign({}, shape) + nShape.color = shape.colorIndex.rgb + nShape.borderColor = shape.colorIndex.rgb + nShape.type = type + // uncoment to debug + // hitCtx = this.$refs.canvas.getContext('2d') // to debug + let sprite = this.sprites[type] // the color is not important + if (sprite) { + sprite = this.cloneCanvas(sprite) + sprite = this.fillCanvas(sprite, shape.colorIndex) + hitCtx.drawImage(sprite, shape.x - sprite.width / 2, shape.y - sprite.height / 2) + } else { + drawFunc(hitCtx, nShape) + } + this.shapes[shape.colorIndex.rgb] = nShape + }, + fillCanvas (canvas, color) { + let ctx = canvas.getContext('2d') + let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height) + let pixels = canvas.width * canvas.height * 4 + for (let p = 3; p <= pixels; p += 4) { + if (imgData.data[p] > 0) { // a + imgData.data[p] = 255 // sers alpha max to prevent transparency match + imgData.data[p - 3] = color.r // r + imgData.data[p - 2] = color.g // g + imgData.data[p - 1] = color.b // b + } + } + ctx.putImageData(imgData, 0, 0) + return canvas + }, + // generates color intex to shapes + newColorIndex () { + while (true) { + let color = this.randomColor() + if (!this.shapes[color.rgb]) return color + } + }, + // generates random color + randomColor () { + const r = Math.round(Math.random() * 255) + const g = Math.round(Math.random() * 255) + const b = Math.round(Math.random() * 255) + return { r, g, b, rgb: `rgb(${r},${g},${b})` } + }, + // sets canvas context style + setCtx (ctx, conf) { + for (let p in conf) { + ctx[p] = conf[p] + } + return ctx + }, + cloneCanvas (canvas) { + let newCanvas = document.createElement('canvas') + let ctx = newCanvas.getContext('2d') + newCanvas.width = canvas.width + newCanvas.height = canvas.height + ctx.drawImage(canvas, 0, 0) + return newCanvas + }, + Sprite (name, cb) { + if (!this.sprites[name]) { + this.sprites[name] = cb() + } + return this.sprites[name] + }, + // sets canvas properties form css properies + getCssStyles () { + let svg = stylePicker.create('svg', 'css-picker') + for (let styleName in this.styles) { + let style = this.styles[styleName] || {} + style = stylePicker.fillStyle(style, svg) + } + document.body.removeChild(svg) + this.stylesReady = true + }, + loadNodeStyle (node) { + let styleName = 'node' + let selected = this.selected[node.id] + if (selected) styleName = 'nodeSelected' + if (node.pinned) styleName = 'nodePinned' + if (selected && node.pinned) styleName = 'nodeSelectedPinned' + // merge styles and update + if (node._cssClass) { + let name = styleName + '-' + node._cssClass + if (!this.styles[name]) { + let cStyle = Object.assign({}, this.styles[styleName] || {}) + cStyle._cssClass = cStyle._cssClass || '' + cStyle._cssClass += ' ' + node._cssClass + this.updateStyle(name, cStyle) + } + styleName = name + } + let style = Object.assign({}, this.styles[styleName] || this.updateStyle(styleName)) + if (node._color) { + style.fillStyle = node._color + style._cssStyle = 'fill:' + node._color + } + if (node._cssClass) { + style._cssClass += ' ' + node._cssClass + } + return style + }, + updateStyle (styleName, style) { + style = style || this.styles[styleName] || {} + let svg = stylePicker.create('svg', 'css-picker') + style = stylePicker.fillStyle(style, svg) + this.styles[styleName] = style + document.body.removeChild(svg) + return style + }, + getCssColor (color) { + let el = stylePicker.create('div', 'color-picker') + let id = el.id + el.setAttribute('style', 'background-color:' + color) + let style = stylePicker.mapStyle(id, { fillStyle: 'background-color' }, []) + document.body.removeChild(el) + return style + }, + labelStyle (node) { + let style = this.styles.labels + let labelClass = node._labelClass + if (labelClass) { + let styleName = 'labels-' + labelClass + let labelStyle = this.styles[styleName] + if (!labelStyle) { + labelStyle = Object.assign({}, style) + labelStyle._cssClass += ' ' + labelClass + labelStyle = this.updateStyle(styleName, labelStyle) + } + style = labelStyle + } + return style + } + } +} +</script> +<style lang="scss"> + canvas{ + position:absolute; + top:0; + left:0; + } +</style> diff --git a/src/components/serfDiagram/vue-d3-network/components/svgRenderer.vue b/src/components/serfDiagram/vue-d3-network/components/svgRenderer.vue new file mode 100644 index 0000000..ce5f8f3 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/components/svgRenderer.vue @@ -0,0 +1,207 @@ +<template lang="pug"> + svg( + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink= "http://www.w3.org/1999/xlink" + ref="svg" + :width="size.w" + :height="size.h" + class="net-svg" + @mouseup='emit("dragEnd",[$event])' + @touchend.passive='emit("dragEnd",[$event])' + @touchstart.passive='' + ) + + //-> links + g.links#l-links + path(v-for="link in links" + :d="linkPath(link)" + :id="link.id" + @click='emit("linkClick",[$event,link])' + @touchstart.passive='emit("linkClick",[$event,link])' + v-bind='linkAttrs(link)' + :class='linkClass(link.id)' + :style='linkStyle(link)' + ) + + //- -> nodes + g.nodes#l-nodes(v-if='!noNodes') + template(v-for='(node,key) in nodes') + svg(v-if='svgIcon(node)' + :key='key' + :viewBox='svgIcon(node).attrs.viewBox' + :width='getNodeSize(node, "width")' + :height='getNodeSize(node, "height")' + @click='emit("nodeClick",[$event,node])' + @mouseover='emit("nodeHover",[$event,node])' + @mouseout='emit("nodeOut",[$event,node])' + @touchend.passive='emit("nodeClick",[$event,node])' + @mousedown.prevent='emit("dragStart",[$event,key])' + @touchstart.prevent='emit("dragStart",[$event,key])' + :x='node.x - getNodeSize(node, "width") / 2' + :y='node.y - getNodeSize(node, "height") / 2' + :style='nodeStyle(node)' + :title="node.name" + :class='nodeClass(node,["node-svg"])' + v-html='svgIcon(node).data' + v-bind='node._svgAttrs' + ) + + //- default circle nodes + circle(v-else + :key='key' + :r="getNodeSize(node) / 2" + @click='emit("nodeClick",[$event,node])' + @mouseover='emit("nodeHover",[$event,node])' + @mouseout='emit("nodeOut",[$event,node])' + @touchend.passive='emit("nodeClick",[$event,node])' + @mousedown.prevent='emit("dragStart",[$event,key])' + @touchstart.prevent='emit("dragStart",[$event,key])' + :cx="node.x" + :cy="node.y" + :style='nodeStyle(node)' + :title="node.name" + :class="nodeClass(node)" + v-bind='node._svgAttrs' + ) + + //-> Links Labels + g.labels#link-labels(v-if='linkLabels') + text.link-label(v-for="link in links" :font-size="fontSize" ) + textPath(v-bind:xlink:href="'#' + link.id" startOffset= "50%") {{ link.name }} + + //- -> Node Labels + g.labels#node-labels( v-if="nodeLabels") + text.node-label(v-for="node in nodes" + :x='node.x + (getNodeSize(node) / 2) + (node._size / 2)' + :y='node.y + labelOffset.y' + :font-size="node._size" + :class='(node._labelClass) ? node._labelClass : ""' + :style='{opacity:node._opacity}' + :stroke-width='node._size / 8' + ) {{ node.name }} +</template> +<script> +import svgExport from "../lib/js/svgExport.js"; + +export default { + name: "svg-renderer", + props: [ + "size", + "nodes", + "noNodes", + "selected", + "linksSelected", + "links", + "nodeSize", + "padding", + "fontSize", + "strLinks", + "linkWidth", + "nodeLabels", + "linkLabels", + "labelOffset", + "nodeSym" + ], + + computed: { + nodeSvg() { + if (this.nodeSym) { + return svgExport.toObject(this.nodeSym); + } + return null; + } + }, + methods: { + getNodeSize(node, side) { + let size = node._size || this.nodeSize; + if (side) size = node["_" + side] || size; + return size; + }, + svgIcon(node) { + return node.svgObj || this.nodeSvg; + }, + emit(e, args) { + this.$emit("action", e, args); + }, + svgScreenShot(cb, toSvg, background, allCss) { + let svg = svgExport.export(this.$refs.svg, allCss); + if (!toSvg) { + if (!background) background = this.searchBackground(); + let canvas = svgExport.makeCanvas(this.size.w, this.size.h, background); + svgExport.svgToImg(svg, canvas, (err, img) => { + if (err) cb(err); + else cb(null, img); + }); + } else { + cb(null, svgExport.save(svg)); + } + }, + linkClass(linkId) { + let cssClass = ["link"]; + if (this.linksSelected.hasOwnProperty(linkId)) { + cssClass.push("selected"); + } + if (!this.strLinks) { + cssClass.push("curve"); + } + return cssClass; + }, + linkPath(link) { + let d = { + M: [link.source.x | 0, link.source.y | 0], + X: [link.target.x | 0, link.target.y | 0] + }; + if (this.strLinks) { + return "M " + d.M.join(" ") + " L" + d.X.join(" "); + } else { + d.Q = [link.source.x, link.target.y]; + return "M " + d.M + " Q " + d.Q.join(" ") + " " + d.X; + } + }, + nodeStyle(node) { + return ( + (node._color ? "fill: " + node._color : "") + + ";opacity:" + + node._opacity + ); + }, + linkStyle(link) { + let style = {}; + if (link._color) style.stroke = link._color; + return style; + }, + nodeClass(node, classes = []) { + let cssClass = node._cssClass ? node._cssClass : []; + if (!Array.isArray(cssClass)) cssClass = [cssClass]; + cssClass.push("node"); + classes.forEach(c => cssClass.push(c)); + if (this.selected[node.id]) cssClass.push("selected"); + if (node.fx || node.fy) cssClass.push("pinned"); + return cssClass; + }, + searchBackground() { + let vm = this; + while (vm.$parent) { + let style = window.getComputedStyle(vm.$el); + let background = style.getPropertyValue("background-color"); + let rgb = background.replace(/[^\d,]/g, "").split(","); + let sum = rgb.reduce((a, b) => parseInt(a) + parseInt(b), 0); + if (sum > 0) return background; + vm = vm.$parent; + } + return "white"; + }, + spriteSymbol() { + let svg = this.nodeSym; + if (svg) { + return svgExport.toSymbol(svg); + } + }, + linkAttrs(link) { + let attrs = link._svgAttrs || {}; + attrs["stroke-width"] = attrs["stroke-width"] || this.linkWidth; + return attrs; + } + } +}; +</script> diff --git a/src/components/serfDiagram/vue-d3-network/index.vue b/src/components/serfDiagram/vue-d3-network/index.vue new file mode 100644 index 0000000..6b7ff4e --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/index.vue @@ -0,0 +1,504 @@ +<script> +import * as forceSimulation from "d3-force"; +import svgRenderer from "./components/svgRenderer.vue"; +import canvasRenderer from "./components/canvasRenderer.vue"; +import saveImage from "./lib/js/saveImage.js"; +import svgExport from "./lib/js/svgExport.js"; +const d3 = Object.assign({}, forceSimulation); + +export default { + name: "d3-network", + components: { + canvasRenderer, + svgRenderer + }, + props: { + netNodes: { + type: Array + }, + netLinks: { + type: Array + }, + options: { + type: Object + }, + nodeSym: { + type: String + }, + nodeCb: { + type: Function + }, + linkCb: { + type: Function + }, + simCb: { + type: Function + }, + customForces: { + type: Object + }, + selection: { + type: Object, + default: () => { + return { + nodes: {}, + links: {} + }; + } + } + }, + data() { + return { + canvas: false, + nodes: [], + links: [], + size: { + w: 500, + h: 420 + }, + offset: { + x: 0, + y: 0 + }, + clientOffset: { + x: 0, + y: 0 + }, + force: 500, + forces: { + Center: false, + X: 0.5, + Y: 0.5, + ManyBody: true, + Link: true + }, + noNodes: false, + strLinks: true, + fontSize: 10, + dragging: false, + linkWidth: 1, + nodeLabels: false, + linkLabels: false, + nodeSize: 5, + mouseOfst: { + x: 0, + y: 0 + }, + padding: { + x: 0, + y: 0 + }, + simulation: null, + nodeSvg: null, + resizeListener: true + }; + }, + render(createElement) { + let ref = "svg"; + let props = {}; + let renderer = "svg-renderer"; + let bindProps = [ + "size", + "nodes", + "links", + "selected", + "linksSelected", + "strLinks", + "linkWidth", + "nodeLabels", + "linkLabels", + "fontSize", + "labelOffset", + "offset", + "padding", + "nodeSize", + "noNodes" + ]; + + for (let prop of bindProps) { + props[prop] = this[prop]; + } + props.nodeSym = this.nodeSvg; + + if (this.canvas) { + renderer = "canvas-renderer"; + ref = "canvas"; + props.canvasStyles = this.options.canvasStyles; + } + + return createElement( + "div", + { + attrs: { class: "net" }, + on: { mousemove: this.move, "&touchmove": this.move } + }, + [ + createElement(renderer, { + props, + ref, + on: { action: this.methodCall } + }) + ] + ); + }, + created() { + this.updateOptions(this.options); + this.buildNodes(this.netNodes); + this.links = this.buildLinks(this.netLinks); + this.updateNodeSvg(); + }, + mounted() { + this.$nextTick(() => { + this.onResize(); + this.animate(); + }); + if (this.resizeListener) window.addEventListener("resize", this.onResize); + }, + beforeDestroy() { + if (this.resizeListener) + window.removeEventListener("resize", this.onResize); + }, + computed: { + selected() { + return this.selection.nodes; + }, + linksSelected() { + return this.selection.links; + }, + center() { + return { + x: this.size.w / 2 + this.size.w / 200 + this.offset.x, + y: this.size.h / 2 + this.size.h / 200 + this.offset.y + }; + }, + labelOffset() { + return { + x: this.nodeSize / 2 + this.fontSize / 2, + y: this.fontSize / 2 + }; + } + }, + watch: { + netNodes(newValue) { + this.buildNodes(newValue); + this.reset(); + }, + netLinks(newValue, oldValue) { + this.links = this.buildLinks(newValue); + this.reset(); + }, + nodeSym() { + this.updateNodeSvg(); + }, + options(newValue, oldValue) { + this.updateOptions(newValue); + if (oldValue.size && newValue.size) { + if ( + oldValue.size.w !== newValue.size.w || + oldValue.size.h !== newValue.size.h + ) { + this.onResize(); + } + } + this.animate(); + } + }, + methods: { + updateNodeSvg() { + let svg = null; + if (this.nodeSym) { + svg = svgExport.svgElFromString(this.nodeSym); + } + this.nodeSvg = svg; + }, + methodCall(action, args) { + let method = this[action]; + if (method && typeof method === "function") { + if (args) method(...args); + else method(); + } + }, + onResize() { + let size = this.options.size; + if (!size || !size.w) this.size.w = this.$el.clientWidth; + if (!size || !size.h) this.size.h = this.$el.clientHeight; + this.padding.x = 0; + this.padding.y = 0; + // serach offsets of parents + let vm = this; + while (vm.$parent) { + this.padding.x += vm.$el.offsetLeft || 0; + this.padding.y += vm.$el.offsetTop || 0; + vm = vm.$parent; + } + this.animate(); + }, + // -- Data + updateOptions(options) { + for (let op in options) { + if (this.hasOwnProperty(op)) { + this[op] = options[op]; + } + } + }, + buildNodes(nodes) { + let vm = this; + this.nodes = nodes.map((node, index) => { + // node formatter option + node = this.itemCb(this.nodeCb, node); + // index as default node id + if (!node.id && node.id !== 0) vm.$set(node, "id", index); + // initialize node coords + if (!node.x) vm.$set(node, "x", 0); + if (!node.y) vm.$set(node, "y", 0); + // node default name, allow string 0 as name + if (!node.name && node.name !== "0") + vm.$set(node, "name", "node " + node.id); + if (node.svgSym) { + node.svgIcon = svgExport.svgElFromString(node.svgSym); + if (!this.canvas && node.svgIcon && !node.svgObj) + node.svgObj = svgExport.toObject(node.svgIcon); + } + + if (!node._size) { + vm.$set( + node, + "_size", + parseInt(Math.random() * (30 - 15 + 1) + 10, 10) + ); + vm.$set(node, "size", node._size); + } + + if (!node.opacity) { + vm.$set(node, "_opacity", node._size / 30); + vm.$set(node, "opacity", node._opacity); + } + + return node; + }); + }, + + buildLinks(links) { + let vm = this; + return links.concat().map((link, index) => { + // link formatter option + link = this.itemCb(this.linkCb, link); + // source and target for d3 + link.source = link.sid; + link.target = link.tid; + if (!link.id) vm.$set(link, "id", "link-" + index); + return link; + }); + }, + itemCb(cb, item) { + if (cb && typeof cb === "function") item = cb(item); + return item; + }, + // -- Animation + simulate(nodes, links) { + let forces = this.forces; + let sim = d3 + .forceSimulation() + .stop() + .alpha(0.5) + // .alphaMin(0.05) + .nodes(nodes); + + if (forces.Center !== false) + sim.force("center", d3.forceCenter(this.center.x, this.center.y)); + if (forces.X !== false) { + sim.force("X", d3.forceX(this.center.x).strength(forces.X)); + } + if (forces.Y !== false) { + sim.force("Y", d3.forceY(this.center.y).strength(forces.Y)); + } + if (forces.ManyBody !== false) { + sim.force("charge", d3.forceManyBody().strength(-this.force)); + } + if (forces.Link !== false) { + sim.force( + "link", + d3.forceLink(links).id(function(d) { + return d.id; + }) + ); + } + sim = this.setCustomForces(sim); + sim = this.itemCb(this.simCb, sim); + return sim; + }, + setCustomForces(sim) { + let forces = this.customForces; + if (forces) { + for (let f in forces) { + let d3Func = this.getD3Func("force" + f); + if (d3Func) { + let args = forces[f]; + sim.force("custom" + f, d3Func(...args)); + } + } + } + return sim; + }, + getD3Func(name) { + let func = d3[name]; + if (func && typeof func === "function") return func; + return null; + }, + animate() { + if (this.simulation) this.simulation.stop(); + if (this.forces.Link !== false) + this.simulation = this.simulate(this.nodes, this.links); + else this.simulation = this.simulate(this.nodes); + this.simulation.restart(); + }, + reset() { + this.animate(); + this.nodes = this.simulation.nodes(); + if (this.forces.links) this.links = this.simulation.force("link").links(); + }, + // -- Mouse Interaction + move(event) { + let pos = this.clientPos(event); + if (this.dragging !== false) { + if (this.nodes[this.dragging]) { + this.simulation.restart(); + this.simulation.alpha(0.5); + this.nodes[this.dragging].fx = pos.x - this.mouseOfst.x; + this.nodes[this.dragging].fy = pos.y - this.mouseOfst.y; + } + } + }, + clientPos(event) { + let x = event.touches ? event.touches[0].clientX : event.clientX; + let y = event.touches ? event.touches[0].clientY : event.clientY; + x = x || 0; + y = y || 0; + return { x, y }; + }, + dragStart(event, nodeKey) { + this.dragging = nodeKey === false ? false : nodeKey; + this.setMouseOffset(event, this.nodes[nodeKey]); + if (this.dragging === false) { + this.simulation.alpha(0.1); + this.simulation.restart(); + this.setMouseOffset(); + } + this.$emit("drag-start", event, nodeKey); + }, + dragEnd(event) { + let node = this.nodes[this.dragging]; + if (node && !node.pinned) { + // unfix node position + node.fx = null; + node.fy = null; + } + this.dragStart(false); + this.$emit("drag-end", event); + }, + // -- Render helpers + nodeClick(event, node) { + this.$emit("node-click", event, node); + }, + nodeHover(event, node) { + this.$emit("node-hover", event, node); + }, + nodeOut(event, node) { + this.$emit("node-out", event, node); + }, + linkClick(event, link) { + this.$emit("link-click", event, link); + }, + setMouseOffset(event, node) { + let x = 0; + let y = 0; + if (event && node) { + let pos = this.clientPos(event); + x = pos.x ? pos.x - node.x : node.x; + y = pos.y ? pos.y - node.y : node.y; + } + this.mouseOfst = { x, y }; + }, + screenShot(name, bgColor, toSVG, svgAllCss) { + let exportFunc; + let args = []; + if (this.canvas) { + toSVG = false; + exportFunc = this.$refs.canvas.canvasScreenShot; + args = [bgColor]; + } else { + exportFunc = this.$refs.svg.svgScreenShot; + args = [toSVG, bgColor, svgAllCss]; + } + if (toSVG) name = name || "export.svg"; + + exportFunc((err, url) => { + if (!err) { + if (!toSVG) saveImage.save(url, name); + else saveImage.download(url, name); + } + this.$emit("screen-shot", err); + }, ...args); + } + } +}; +</script> + +<style lang="stylus"> +@import 'lib/styl/vars.styl'; + +.net { + height: 100%; + margin: 0; +} + +.net-svg { + // fill: white // background color to export as image +} + +.node { + stroke: alpha($dark, 0.7); + stroke-width: 3px; + transition: fill 0.5s ease; + fill: $white; +} + +.node.selected { + stroke: $color2; +} + +.node.pinned { + stroke: alpha($warn, 0.6); +} + +.link { + stroke: alpha($dark, 0.3); +} + +.node, .link { + stroke-linecap: round; + + &:hover { + stroke: $warn; + stroke-width: 5px; + } +} + +.link.selected { + stroke: alpha($color2, 0.6); +} + +.curve { + fill: none; +} + +.node-label { + fill: $dark; +} + +.link-label { + fill: $dark; + transform: translate(0, -0.5em); + text-anchor: middle; +} +</style> diff --git a/src/components/serfDiagram/vue-d3-network/lib/js/canvasStyles.js b/src/components/serfDiagram/vue-d3-network/lib/js/canvasStyles.js new file mode 100644 index 0000000..fb181f1 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/lib/js/canvasStyles.js @@ -0,0 +1,56 @@ +/** + * This styles are used to 'map' svg-css styles to canvas elements + * creating svg elements and getting computed styles properties from them + * + * Object keys as style names. + * Property '_cssClass', Required, String, css class to pick style + * Property '_svgElement', Optional, String type of svg element, + * Property '_svgAttrs', Optional,Object, svg element attributes + * see supported elements in stylePicker -> canvasPicker() + * or add property _svgAttrs to use any svg element + * + */ +export default { + background: { + _cssClass: 'net-svg', + fillStyle: 'white' + }, + node: { + _cssClass: 'node', // name of the class to pick properties + fillStyle: 'green', + strokeStyle: 'orange', + lineWidth: 2 + }, + link: { + _cssClass: 'link', + strokeStyle: 'blue', + lineWidth: 1 + }, + labels: { + _cssClass: 'node-label', + _svgElement: 'text', // svg element to pick properties + fillStyle: 'black', + fontFamily: 'Arial' + }, + nodeSelected: { + _cssClass: 'node selected', + fillStyle: 'red', + strokeStyle: 'orange', + lineWidth: 2 + }, + linkSelected: { + _cssClass: 'link selected', + strokeStyle: 'green', + lineWidth: 2 + }, + nodePinned: { + _cssClass: 'node pinned', + fillStyle: 'green', + strokeStyle: 'red' + }, + nodeSelectedPinned: { + _cssClass: 'node selected pinned', + fillStyle: 'green', + strokeStyle: 'red' + } +} diff --git a/src/components/serfDiagram/vue-d3-network/lib/js/saveImage.js b/src/components/serfDiagram/vue-d3-network/lib/js/saveImage.js new file mode 100644 index 0000000..a51e968 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/lib/js/saveImage.js @@ -0,0 +1,28 @@ +export default { + save (img, name) { + if (img) { + img = this.dataURIToBlob(img, (blob) => { + let url = URL.createObjectURL(blob) + this.download(url, name) + }) + } + }, + dataURIToBlob (dataURI, cb) { + let binStr = atob(dataURI.split(',')[1]) + let len = binStr.length + let arr = new Uint8Array(len) + for (var i = 0; i < len; i++) { + arr[i] = binStr.charCodeAt(i) + } + cb(new Blob([arr])) + }, + download (url, name) { + name = name || '' + let link = document.createElement('a') + link.setAttribute('href', url) + link.setAttribute('download', name) + let el = document.body.appendChild(link) + link.click() + document.body.removeChild(el) + } +} diff --git a/src/components/serfDiagram/vue-d3-network/lib/js/stylePicker.js b/src/components/serfDiagram/vue-d3-network/lib/js/stylePicker.js new file mode 100644 index 0000000..6b68f38 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/lib/js/stylePicker.js @@ -0,0 +1,78 @@ +export default { + randomId () { + return Math.random().toString(36).substring(7) + }, + + // gets canvas style from css properties + fillStyle (style, svg) { + let pseudo = null + let id = 'picker-' + this.randomId() + let el = this.canvasPicker(style, id) + // to replace 'px' + svg.appendChild(el) + let props = { + fillStyle: 'fill', + strokeStyle: 'stroke', + lineWidth: 'stroke-width', + fontFamily: 'font-family' + } + style = this.mapStyle(id, props, style, pseudo) + svg.removeChild(el) + return style + }, + mapStyle (id, props, style, pseudo, numberValues) { + let cStyle = window.getComputedStyle(document.getElementById(id), pseudo) + numberValues = numberValues || ['lineWidth'] + for (let p in props) { + let value = cStyle.getPropertyValue(props[p]) + if (numberValues.indexOf(p) > -1) value = parseInt(value, 10) + if (value) { + style[p] = value + } + } + return style + }, + // creates svg elements to pick css properties + canvasPicker (style, id) { + let attrs = style._svgAttrs || {} + let element = style._svgElement || 'circle' + if (!style._svgAttrs) { + switch (element) { + case 'text': + attrs = { x: 10, y: 10, fontSize: 20 } + break + case 'circle': + attrs = { cx: 10, cy: 10, r: 10 } + break + } + } + attrs.class = style._cssClass + attrs.id = id + return this.svgCreate(element, attrs) + }, + compColor (color) { + let el = document.createElement('div') + el.style.backgroundColor = color + document.body.appendChild(el) + let nColor = window.getComputedStyle(el, null).getPropertyValue('background-color') + document.body.removeChild(el) + return nColor + }, + // creates svg element + svgCreate (element, attrs) { + let el = document.createElementNS('http://www.w3.org/2000/svg', element) + for (let a in attrs) { + el.setAttributeNS(null, a, attrs[a]) + } + return el + }, + create (element, idPref, appendTo) { + appendTo = appendTo || 'body' + let el = document.createElement(element) + let id = idPref || '' + id += this.randomId() + el.setAttribute('id', id) + document[appendTo].appendChild(el) + return el + } +} diff --git a/src/components/serfDiagram/vue-d3-network/lib/js/svgExport.js b/src/components/serfDiagram/vue-d3-network/lib/js/svgExport.js new file mode 100644 index 0000000..9ed7c58 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/lib/js/svgExport.js @@ -0,0 +1,143 @@ +export default { + NS: 'http://www.w3.org/2000/svg', + // svgOrg: svg element + // allCss : true includes all svg css styles, false includes only matched styles + export (svgOrg, allCss) { + let svg = null + if (this.isSvgData(svgOrg)) { + svg = svgOrg.cloneNode(true) + let childs = svgOrg.parentNode.querySelectorAll('*') + let cssStyle = {} + let rules = this.getcssRules() + + for (let child of childs) { + let elRules = rules + if (!allCss) { + elRules = rules.filter((rule) => { + return child.matches(rule.selectorText) + }) + } + for (let rule of elRules) { + cssStyle[rule.selectorText] = rule.cssText + } + } + let css = Object.values(cssStyle).join('\n') + if (css) { + let style = document.createElementNS(this.NS, 'style') + style.type = 'text/css' + svg.insertBefore(style, svg.childNodes[0]) + style.innerHTML = css + svg.appendChild(style) + } + } + return svg + }, + + makeCanvas (width, height, background) { + let canvas = document.createElement('canvas') + canvas.width = width + canvas.height = height + let ctx = canvas.getContext('2d') + ctx.fillStyle = background || 'white' + ctx.fillRect(0, 0, canvas.width, canvas.height) + return canvas + }, + + serialize (svg) { + return (new XMLSerializer()).serializeToString(svg) + }, + + svgToImg (svg, canvas, cb) { + let xml = this.serialize(svg) + let img = new Image() + let ctx = canvas.getContext('2d') + img.onload = function () { + ctx.drawImage(this, 0, 0) + let png = canvas.toDataURL('image/png') + cb(null, png, ctx) + } + img.onerror = function (err) { + cb(err) + } + img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(xml))) + }, + + save (svg) { + return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(this.serialize(svg)) + }, + + getcssRules () { + let rules = [] + for (let styles of document.styleSheets) { + let styleRules = this.readRules(styles) + for (let rule of styleRules) { + if (rule && rule.cssText) { + rules.push(rule) + } + } + } + return rules + }, + + readRules (styles) { + try { + if (!styles.cssRules) return styles.rules || [] + } catch (e) { + // Firefox returns Security Error if stylesheet originates from different domain + if (e.name !== 'SecurityError') throw e + return [] + } + return styles.cssRules + }, + + toDom (svgData) { + let div = document.createElement('div') + div.innerHTML = svgData + return div.firstChild || null + }, + + toObject (svg) { + if (svg) { + let attrs = {} + if (svg.attributes) { + for (let i = svg.attributes.length; i >= 0; i--) { + let a = svg.attributes[i] + if (a) attrs[a.name] = a.value + } + } + let data = svg.innerHTML + if (data) return { attrs, data } + } + return null + }, + + svgElFromString (svgData) { + let svgEl = this.toDom(svgData) + if (!this.isSvgData(svgEl)) return + svgEl.setAttribute('xmlns', 'http://www.w3.org/2000/svg') + return svgEl + }, + + svgDataToUrl (svgData, attrs) { + if (typeof (attrs) === 'object') { + for (let a in attrs) { + let attribute = (attrs[a]) ? (attrs[a]) : '' + svgData.setAttribute(a, attribute) + } + } + let svg = this.export(svgData) + if (svg) return this.svgToUrl(this.serialize(svg)) + return null + }, + + isSvgData (svgData) { + if (!svgData.firstChild) return false + return (svgData.firstChild.parentNode.nodeName === 'svg') + }, + + svgToUrl (svg) { + let xml = new Blob([svg], { type: 'image/svg+xml' }) + let url = URL.createObjectURL(xml) + return url + } +} diff --git a/src/components/serfDiagram/vue-d3-network/lib/styl/node-style.styl b/src/components/serfDiagram/vue-d3-network/lib/styl/node-style.styl new file mode 100644 index 0000000..da31e19 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/lib/styl/node-style.styl @@ -0,0 +1,6 @@ +@import 'vars.styl' +.node #fill + fill $mid +.node.selected + #fill + fill lighten($color2,40%) \ No newline at end of file diff --git a/src/components/serfDiagram/vue-d3-network/lib/styl/vars.styl b/src/components/serfDiagram/vue-d3-network/lib/styl/vars.styl new file mode 100644 index 0000000..42a23e2 --- /dev/null +++ b/src/components/serfDiagram/vue-d3-network/lib/styl/vars.styl @@ -0,0 +1,21 @@ +$color2 = #caa455 +$color = #1aad8d +// $color2 = #E3A826 +$white = lightness($color, 92%) +$dark = lightness($color, 27%) +$darkness = #225057 +$bg = saturation(lightness($color,25%),30%) +//$bg = saturation(lightness($color,30%),20%) +$bg = saturation(lightness($color,80%),15%) +$bg-plus = saturation(lightness($color,75%),30%) +$warn = #be385d +$light = #f5fffc +$mid = lightness($color, 55%) + +$border = $color solid 2px +$txt-sh = 1px 1px 1px rgba(0,0,0,.5) +$box-sh = 1px 1px 2px rgba(0,0,0,0.7) +$sh = 1px 1px 2px rgba(0,0,0,0.5) +$hard-sh = 2px 2px 4px rgba(0,0,0,.8) + +$sym-close = "鉁�" \ No newline at end of file diff --git a/src/components/subComponents/FileUpload/index.vue b/src/components/subComponents/FileUpload/index.vue index 97c4562..b5ff901 100644 --- a/src/components/subComponents/FileUpload/index.vue +++ b/src/components/subComponents/FileUpload/index.vue @@ -149,14 +149,14 @@ }, computeMD5Success(md5, file) { // 灏嗚嚜瀹氫箟鍙傛暟鐩存帴鍔犺浇uploader瀹炰緥鐨刼pts涓� - if (this.$route.path.indexOf("VideoManage") >= 0) { - Object.assign(this.uploader.opts, { - query: { - stackId: this.DataStackPool.selectedDir.id - // ...this.params, - } - }) - } + // if (this.$route.path.indexOf("VideoManage") >= 0) { + // Object.assign(this.uploader.opts, { + // query: { + // stackId: this.DataStackPool.selectedDir.id + // // ...this.params, + // } + // }) + // } file.uniqueIdentifier = md5; file.resume(); this.statusText.paused = "鏆傚仠涓�"; diff --git a/src/pages/algorithmManage/index/App.vue b/src/pages/algorithmManage/index/App.vue index 34488d2..c2966a5 100644 --- a/src/pages/algorithmManage/index/App.vue +++ b/src/pages/algorithmManage/index/App.vue @@ -63,9 +63,10 @@ <div class="list-complete-item-handle"> <!-- <span :class="`iconfont ${item.icon}`" style="font-size:3rem;"></span> --> <div class="svg-wrap"> - <svg class="icon" aria-hidden="true" style="font-size:7rem;"> + <!-- <svg class="icon" aria-hidden="true" style="font-size:7rem;"> <use :xlink:href="`#${item.icon}`" /> - </svg> + </svg> --> + <img class="baseImg" :src="`data:image/png;base64,${item.iconBlob}`" alt=""> </div> <div class="alg-name"> <div style="padding:0px 10px 0px 10px;"> @@ -729,16 +730,38 @@ installSdk } from "./api"; import FileUploader from "@/components/subComponents/FileUpload/index"; - +import TaskManage from "@/Pool/TaskMange"; +import VideoManageData from "@/Pool/VideoManageData"; export default { name: "algorithmManage", props: {}, components: { FileUploader }, - + computed: { + notInstalledList() { + return this.TaskMange.list1.filter(sdk => { + return sdk.installed === false; + }); + }, + installedList() { + return this.TaskMange.list1.filter(sdk => { + debugger + return sdk.installed === true; + }); + }, + ungradeList() { + // 鍗囩骇澶勭悊浼氬鑷撮噸澶嶇殑key,闇�瑕佷慨鏀� + return []; + return this.TaskMange.list1.filter(sdk => { + return sdk.isUpgrade === true; + }); + } + }, data() { return { + TaskMange: new TaskManage, + VideoManageData: new VideoManageData, activeName: "myAlgorithm", patchUpdateStatus: "", dragging: false, @@ -804,8 +827,818 @@ installPercentage: 0 } }, - methods: {}, - mounted() {} + watch: { + list2: { + handler(newVal, oldVal) { + // window.console.log(newVal, oldVal, '鐩戝惉list2') + if (newVal !== oldVal) { + // window.console.log(newVal, '鐩戝惉list2') + newVal.map((i, index) => { + i.child.map(j => { + this.$set(j, "parentId", i.id); + }); + }); + } + }, + deep: true + } + }, + directives: { + focus: { + inserted: function(el) { + el.querySelector("input").focus(); + } + } + }, + mounted() { + this.findAllSdk(); + this.findByType(); + this.getBaseList(); + this.findAll(); + this.getUser(); + // this.TaskMange.findAllSdk(); + // this.TaskMange.findByType(); + this.VideoManageData.init(); + }, + methods: { + installFormat(percentage) { + return percentage === 100 ? '瀹夎鎴愬姛' : `${percentage}%`; + }, + actived() { + //this.activeCode + this.actStep++ + }, + getCodeDetail() {}, + checkMyAlgorith() { + this.actDrawerShow = false; + this.activeName = "myAlgorithm"; + }, + onFileUpload(file) { + //this.patchUpdateStatus = `<span style="color:green">涓婁紶鎴愬姛, 鐐瑰嚮鍗囩骇鎸夐挳寮�濮嬪畨瑁�</span>`; + this.patchFile = { ...file }; + this.fileAdded = true; + const h = this.$createElement; + // this.$msgbox({ + // title: '绠楁硶淇℃伅', + // message: h('div', null, [ + // h('span', null, '绠楁硶鍚嶇О锛� '), + // h('i', { style: 'color: teal' }, file.filename) + // ]), + // showCancelButton: true, + // confirmButtonText: '纭畾', + // cancelButtonText: '鍙栨秷', + // beforeClose: (action, instance, done) => { + // if (action === 'confirm') { + // instance.confirmButtonLoading = true; + // instance.confirmButtonText = '鎵ц涓�...'; + // setTimeout(() => { + // done(); + // setTimeout(() => { + // instance.confirmButtonLoading = false; + // }, 300); + // }, 3000); + // } else { + // done(); + // } + // } + // }).then(action => { + // this.$message({ + // type: 'info', + // message: 'action: ' + action + // }); + // }); + + this.$confirm('','绠楁硶淇℃伅',{ + message: `<div class="installInfo"> + <div><span>绠楁硶鍚嶇О锛�</span><span>${file.filename}</span></div> + <div><span>瀹夎鐗堟湰锛�</span><span></span></div> + <div><span>鏇存柊鍐呭锛�</span><span></span></div> + <p>纭畾瀹夎姝ょ畻娉曪紵</p> + </div>`, + confirmButtonText: '瀹夎', + cancelButtonText: '鍙栨秷', + dangerouslyUseHTMLString: true, + type: '' + }).then(() => { + this.isInstall = true; + //瀹夎 + installSdk(file).then(res => { + if(res.success){ + debugger + this.isInstall = false; + //this.$refs['progressBar'].style.width = 100% + //this.installPercentage = 100% + this.$message({ + type: 'success', + message: '瀹夎鎴愬姛,灏嗚烦杞嚦鎴戠殑绠楁硶涓煡鐪�' + }); + setTimeout(()=>{ + this.findAllSdk(); + this.activeName = 'myAlgorithm'; + },3000) + } + }); + }).catch(() => { + console.log('鍙栨秷瀹夎') + }) + + }, + + onFileAdded(f) { + debugger; + this.patchUpdateStatus = ""; + }, + // 鏍¢獙杈撳叆鐨勬槸鍚︽槸鏁板瓧 + valiNum(value) { + if (value) { + let re = /[^\-?\d.]*$/; + if (!re.test(value)) { + // this.$toast({ + // type: "warning", + // message: "璇疯緭鍏ユ暟瀛楋紒" + // }); + this.$notify({ + title: "鎻愮ず", + message: "璇疯緭鍏ユ暟瀛楋紒", + type: "warning" + }); + } + } + }, + // 宸﹁竟鎷栧姩妯″潡寰楁嫋鍔ㄧ粨鏉熷悗鐨勮Е鍙戝嚱鏁� + endLeft(env) { + this.dragging = false; + let taskId = env.to.id; + let sdkId = this.TaskMange.list1[env.oldIndex].id; + if (!taskId.length || !sdkId.length) { + return; + } + // 鑾峰彇鍒拌浠诲姟鎵�鍦ㄧ殑鍏冪礌 + let task = this.TaskMange.list2.find(i => { + return i.id === taskId; + }); + let arr = task.child.filter(i => { + return i.id === sdkId; + }); + // window.console.log(task, "鎷栬繘鏉ョ殑浠诲姟淇℃伅", sdkId, arr); + if (arr && arr.length >= 2) { + // this.$toast({ + // type: "warning", + // message: "璇ョ畻娉曞凡瀛樺湪锛�" + // }); + this.$notify({ + title: "鎻愮ず", + message: "璇ョ畻娉曞凡瀛樺湪锛�", + type: "warning" + }); + task.child.splice(env.newIndex, 1); + return true; + } + let list = task.child.map((i, index) => { + let obj = {}; + obj.sdkId = i.id; + obj.sort = index + 1; + return obj; + }); + let json = { + taskId: taskId, + sdks: list + }; + this.addTaskSdk(json); + }, + // 鍙宠竟鎷栧姩妯″潡寮�濮嬫嫋鍔ㄨЕ鍙戝嚱鏁� + startRight(env) { + this.$nextTick(() => { + this.dragging = true; + }); + // window.window.console.log(env, "right start"); + }, + // 鍙宠竟鎷栧姩妯″潡鎷栧姩缁撴潫瑙﹀彂鍑芥暟 + endRight(env) { + // window.window.console.log(env, "right end"); + }, + clickSet(data) { + if (data.isSetting) { + data.isSetting = false; + } else { + data.isSetting = true; + } + }, + clickDel(data, Index) { + this.$confirm("鎻愮ず锛氬垹闄ゅ悗锛屾浠诲姟鍦ㄦ憚鍍忔満涓殑搴旂敤澶辨晥锛屾槸鍚﹀垹闄わ紵", { + center: true, + showConfirmButton: true, + showCancelButton: true, + confirmButtonClass: "comfirm-class-sure", + cancelButtonClass: "comfirm-class-cancle" + }) + .then(() => { + this.deleteTask(data); + }) + .catch(err => {}); + }, + clickSetAlgo(row, data) { + // window.console.log(row, data, "缂栬緫浠诲姟涓煇涓�涓畻娉�"); + if (row.isShowSetAlgo && data.id === this.TaskMange.currentAlgoId) { + row.isShowSetAlgo = false; + data.isSelect = false; + return false; + } + if (data.id !== this.TaskMange.currentAlgoId) { + let isEdit = false; + if (this.argsList && this.argsList.length !== 0) { + this.TaskMange.argsList.map((i, index) => { + if (i.value2 !== this.argsList[index].value2) { + isEdit = true; + } + if (i.value3 !== this.argsList[index].value3) { + isEdit = true; + } + }); + } + if (isEdit) { + this.$notify({ + title: "鎻愮ず", + message: "璇峰厛淇濆瓨鏈繚瀛樼殑閰嶇疆锛�", + type: "warning" + }); + return false; + } else { + let task = this.TaskMange.list2.find(element => { + return element.isShowSetAlgo; + }); + // console.log(task, '鏄惁鏈夊凡缁忔墦寮�缂栬緫鐨�') + if (task !== undefined) { + this.$set(task, "isShowSetAlgo", false); + task.child.map(i => { + this.$set(i, "isSelect", false); + }); + } + } + } + this.TaskMange.currentAlgoId = data.id; + this.TaskMange.currentTaskId = row.id; + let task = this.TaskMange.list2.find(element => { + return element.isShowSetAlgo; + }); + if (task === undefined) { + this.getSdkArgs(data).then(() => { + this.getRulesByTaskSdk(row.id, data.id); + }); + if (row.isShowSetAlgo) { + row.isShowSetAlgo = false; + } else { + row.isShowSetAlgo = true; + data.isSelect = true; + } + } else { + // this.$toast({ + // type: "warning", + // message: "璇峰厛淇濆瓨鏈繚瀛樼殑閰嶇疆锛�" + // }); + // this.$notify({ + // title: "鎻愮ず", + // message: "璇峰厛淇濆瓨鏈繚瀛樼殑閰嶇疆锛�", + // type: "warning" + // }); + } + }, + async getRulesByTaskSdk(taskId, sdkId) { + let res = await getRulesByTaskSdk({ + taskId: taskId, + sdkId: sdkId + }); + if (res && res.success) { + if (res.data.rules && res.data.rules.length !== 0) { + this.TaskMange.argsList = res.data.rules.map((i, index) => { + let sdk = res.data.argList.find(j => { + return j.alias === i.sdk_arg_alias; + }); + let obj = JSON.parse(JSON.stringify(this.TaskMange.baseObject)); + obj.value1 = i.sdk_arg_alias ? i.sdk_arg_alias : ""; + obj.value2 = i.operator ? i.operator : ""; + obj.value3 = i.sdk_arg_value ? i.sdk_arg_value : ""; + obj.unit = sdk.unit ? sdk.unit : ""; + obj.id = i.Id ? i.Id : ""; + obj.algoId = sdkId; + return obj; + }); + } else { + this.TaskMange.argsList = res.data.argList.map(i => { + let obj = JSON.parse(JSON.stringify(this.TaskMange.baseObject)); + obj.value1 = i.alias ? i.alias : ""; + obj.value2 = i.default_operator ? i.default_operator : ""; + obj.value3 = i.default_value ? i.default_value : ""; + obj.unit = i.unit ? i.unit : ""; + obj.id = ""; + obj.algoId = sdkId; + return obj; + }); + } + // window.console.log(res, '鏌ユ壘绠楁硶瑙勫垯', this.argsList) + this.argsList = JSON.parse(JSON.stringify(this.TaskMange.argsList)); + } + }, + async findAllSdk() { + let res = await findAllSdk(); + if (res && res.success) { + // debugger + this.TaskMange.list1 = res.data.map((i, index) => { + this.$set(i, "isEdit", false); + //mock 鏈畨瑁�/寰呭崌绾� + // if (index == 1 || index == 2) { + // this.$set(i, "isUpgrade", true); + // } + // if (index == 3 || index == 4) { + // this.$set(i, "installed", false); + // } + //mock end + return i; + }); + } + }, + addTask() { + let obj = { + id: "", + name: "浠诲姟" + this.TaskMange.list2.length, + child: [], + isSetting: false, + isShowSetAlgo: false + }; + // window.console.log(this.TaskMange.list2, "addTask"); + this.TaskMange.list2.push(obj); + this.addTaskAsync(obj.name); + this.$nextTick(() => { + let taskArea = document.getElementById("taskArea"); + taskArea.scrollTop = taskArea.scrollHeight; + }); + }, + async findAll() { + let res = await findAll(); + if (res && res.success) { + if (res.data && res.data.length !== 0) { + let list = res.data.map(i => { + let obj = {}; + obj.id = i.task.taskid; + obj.name = i.task.taskname; + obj.enable = i.task.enable; + obj.is_alarm = i.task.is_alarm; + obj.child = []; + if (i.sdks && i.sdks.length !== 0) { + obj.child = i.sdks.map(j => { + let t = {}; + t.id = j.id; + t.ipc_id = j.ipc_id; + if (i.sdks.length == 1) { + t.sdk_name = i.task.taskname; + // console.log("鍗曚釜sdk绠楁硶锛�",t.sdk_name) + } else { + t.sdk_name = j.sdk_name; + // console.log("澶氫釜sdk绠楁硶锛�",t.sdk_name) + } + t.icon = j.icon; + t.enable = j.enable; + t.isSelect = false; + return t; + }); + } + obj.isSetting = false; + obj.isShowSetAlgo = false; + return obj; + }); + this.TaskMange.list2 = list; + } + } + }, + clickDelSdk(task, sdk) { + this.$confirm( + "鎻愮ず锛氬垹闄ゅ悗锛屾绠楁硶鍦ㄦ湰浠诲姟涓Щ闄わ紝鍚屾椂鍦ㄦ憚鍍忔満涓殑搴旂敤澶辨晥锛屾槸鍚﹀垹闄わ紵", + { + center: true, + showConfirmButton: true, + showCancelButton: true, + confirmButtonClass: "comfirm-class-sure", + cancelButtonClass: "comfirm-class-cancle" + } + ) + .then(() => { + this.delTaskSdk(task, sdk); + }) + .catch(err => {}); + }, + selectChange(event, type, data) { + if (type === "options1") { + // window.window.console.log(type, data, "閫夋嫨涓嬫媺妗�"); + data.options1.map(i => { + if (i.value === data.value1) { + this.$set(data, "unit", i.unit ? i.unit : ""); + } + }); + } + }, + // 鍒犻櫎浠诲姟绠楁硶 + async delTaskSdk(task, sdk) { + let json = { + taskId: task.id, + sdkId: sdk.id + }; + let res = await delTaskSdk(json); + if (res && res.success) { + // this.$toast({ + // type: "success", + // message: "鍒犻櫎浠诲姟绠楁硶鎴愬姛!" + // }); + this.$notify({ + title: "鎴愬姛", + message: "鍒犻櫎浠诲姟绠楁硶鎴愬姛!", + type: "success" + }); + this.findAll(); + } + }, + // 鍒犻櫎浠诲姟 + async deleteTask(data, index) { + // window.console.log(data, "deleteTask"); + let res = await deleteTask({ taskId: data.id }); + // this.$toast({ + // type: res.success ? "success" : "error", + // message: res.msg + // }); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + if (data.id && res.success) { + this.findAll(); + } + }, + // 鏇存柊浠诲姟鐘舵�� + async updateTaskStatus(data) { + // window.console.log(data, '鏇存柊浠诲姟鐘舵��') + let json = { + taskId: data.id, + enable: data.enable + }; + let res = await updateTaskStatus(json); + // this.$toast({ + // type: res.success ? "success" : "error", + // message: res.msg + // }); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + }, + // 鏇存柊浠诲姟鍚嶇О + async updateTaskName(data) { + let json = { + taskId: data.id, + taskName: data.name + }; + let res = await updateTaskName(json); + // this.$toast({ + // type: res.success ? "success" : "error", + // message: res.msg + // }); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + if (res && res.success) { + this.$set(data, "isSetting", false); + } + }, + // 鑾峰彇搴曞簱鏁版嵁 + async getBaseList() { + // let res = await getTagList(); + // if (res && res.success) { + // let filter = res.data.filter(i => { + // return i.status === 0; + // }); + // let list = filter.map(i => { + // let obj = {}; + // obj.id = i.key; + // obj.name = i.title; + // obj.value = i.value; + // return obj; + // }); + // list.unshift({ + // id: "", + // name: "鍏ㄩ儴搴曞簱", + // value: "" + // }) + + // // this.TaskMange.baseObject.options3 = [...all, ...list]; + // this.TaskMange.baseObject.options3 = [...list]; + // } + + this.TaskMange.baseObject.options3 = [ + { id: true, name: true, value: true }, + { id: false, name: false, value: false } + ]; + }, + // 鑾峰彇绠楁硶鍙傛暟 + async getSdkArgs(data) { + let res = await getSdkArgs({ + sdkId: data.id, + scope: "TASKRULE" + }); + if (res && res.success) { + // window.console.log(res, "鏌ヨ绠楁硶鍙傛暟"); + let list = res.data.map(i => { + let obj = {}; + obj.name = i.name; + obj.id = i.alias; + obj.value = i.alias; + obj.unit = i.unit; + obj.must = i.must; + obj.range = i.range; + obj.sort = i.sort; + return obj; + }); + this.TaskMange.baseObject.options1 = [...list]; + } + }, + // 鏌ヨ瀛楀吀 + async findByType() { + let res = await findByType(); + if (res && res.success) { + let list = res.data.RULECOMPUTEBETWEEN.map(i => { + let obj = {}; + obj.name = i.name; + obj.value = i.value; + return obj; + }); + this.TaskMange.baseObject.options2 = [...list]; + } + }, + // 绠楁硶閰嶇疆锛屾柊寤� + add() { + this.TaskMange.argsList.push( + JSON.parse(JSON.stringify(this.TaskMange.baseObject)) + ); + }, + // 绠楁硶閰嶇疆 鍒犻櫎 + delRule(index) { + this.TaskMange.argsList.splice(index, 1); + }, + // 绠楁硶鍙傛暟淇濆瓨 + async save() { + let list = this.TaskMange.argsList.map(i => { + let obj = {}; + obj.id = i.id; + obj.operator = i.value2; + obj.sdk_arg_alias = i.value1; + obj.sdk_arg_value = i.value3; + return obj; + }); + let json = { + rules: list, + sdkId: this.TaskMange.currentAlgoId, + taskId: this.TaskMange.currentTaskId + }; + let res = await saveTaskSdkRule(json); + this.$notify({ + title: "鎻愮ず", + type: res.success ? "success" : "error", + message: res.msg + }); + if (res && res.success) { + let task = this.TaskMange.list2.find(i => { + return i.id === this.TaskMange.currentTaskId; + }); + if (task) { + this.$set(task, "isShowSetAlgo", false); + this.TaskMange.argsList = []; + task.child.map(i => { + this.$set(i, "isSelect", false); + }); + } + } + }, + getDefault() { + this.deleteTaskSdkRule( + this.TaskMange.currentTaskId, + this.TaskMange.currentAlgoId + ).then(() => { + this.getRulesByTaskSdk( + this.TaskMange.currentTaskId, + this.TaskMange.currentAlgoId + ); + }); + }, + async deleteTaskSdkRule(taskId, sdkId) { + let json = { + taskId: taskId, + sdkId: sdkId + }; + let res = await deleteTaskSdkRule(json); + // this.$toast({ + // type: res.success ? "success" : "error", + // message: res.msg + // }); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + if (res && res.success) { + // window.console.log(res, "鎭㈠榛樿鍊�"); + } + }, + // 缁欎换鍔℃坊鍔犵畻娉� + async addTaskSdk(data) { + let res = await addTaskSdk(data); + if (res && res.success) { + // window.console.log(res, 'res') + this.findAll(); + } + }, + // 鏂版坊鍔犱换鍔� + async addTaskAsync(name) { + let res = await addTask({ taskname: name }); + // this.$toast({ + // type: res.success ? "success" : "error", + // message: res.msg + // }); + // window.console.log(res, "addTaskAsync"); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + if (res && res.success) { + this.findAll(); + } + }, + cancle(row) { + if (row.isShowSetAlgo) { + row.isShowSetAlgo = false; + } + this.TaskMange.argsList = []; + this.TaskMange.currentAlgoId = ""; + row.child.map(i => { + this.$set(i, "isSelect", false); + }); + }, + cancleTask(row) { + if (row.isSetting) { + row.isSetting = false; + } + }, + commandAlgo(command, row, item) { + if (command === 1) { + // console.log('璁剧疆绠楁硶') + this.clickSetAlgo(row, item); + } + if (command === 2) { + // console.log('鍒犻櫎绠楁硶') + this.clickDelSdk(row, item); + } + }, + commandTask(command, row) { + if (command === 1) { + //缂栬緫浠诲姟 + this.clickSet(row); + } + }, + getUser() { + // console.log("鐧诲綍鐢ㄦ埛",JSON.parse(sessionStorage.getItem("userInfo")).username) + if ( + sessionStorage.getItem("userInfo") && + (JSON.parse(sessionStorage.getItem("userInfo")).username == + "superadmin" || + JSON.parse(sessionStorage.getItem("userInfo")).username == "basic") + ) { + this.isSuperUser = true; + } else { + this.isSuperUser = false; + } + }, + donwload(item) { + this.downloading = true; + this.downloadItem = item.id; + + downloadSdk({ path: item.id }) + .then(rsp => { + this.$notify({ + type: "success", + message: "绠楁硶宸插畨瑁�" + }); + this.downloading = false; + this.downloadItem = ""; + this.findAllSdk(); + }) + .catch(err => { + this.$notify({ + type: "warning", + message: err.data + }); + + this.downloading = false; + this.downloadItem = ""; + }); + }, + commandAlgLib(item) { + this.$set(item, "isEdit", true); + }, + inputBlur(item) { + // console.log(item, '淇敼鍚嶇О') + this.$set(item, "isEdit", false); + }, + updateTemplates() { + getAllTemplate().then(rsp => { + if (rsp && rsp.success) { + this.sceneTemplates = rsp.data; + this.sceneTemplates.forEach(element => { + element.icon = [ + "iconrenlianjiance", + "icongetijingzhi", + "iconchouyan-copy", + "iconrenshukouzhao" + ]; + }); + } + }); + }, + cleanTemplateForm() { + this.appSceneForm.name = ""; + this.appSceneForm.desc = ""; + this.appSceneForm.rules = ""; + this.appSceneForm.txt = ""; + + this.$refs.ruleEditor.cleanRule(); + }, + handleTabClick() { + if (this.activeName == "appScenarios") { + this.updateTemplates(); + } + }, + handleCreateScene() { + this.sceneDialogVisible = true; + this.dialogTitle = '鍒涘缓鍦烘櫙妯℃澘'; + + this.sceneSdks = this.TaskMange.list1.filter(sdk => { + return sdk.installed === true; + }); + this.sceneRuleList = ""; + + this.$nextTick(() => { + this.cleanTemplateForm(); + }); + }, + handleDialogClose() { + this.sceneDialogVisible = false; + }, + handleEditScene(item) { + this.appSceneForm.name = item.name; + this.appSceneForm.desc = item.desc; + + this.sceneSdks = item.sdks; + this.sceneRuleList = item.rules; + this.sceneDialogVisible = true; + this.dialogTitle = '缂栬緫鍦烘櫙妯℃澘'; + }, + handleDelScene(item){ + this.$confirm('姝ゆ搷浣滃皢鍒犻櫎璇ュ簲鐢ㄥ満鏅ā鏉�, 鏄惁缁х画?', '鎻愮ず', { + confirmButtonText: '纭畾', + cancelButtonText: '鍙栨秷', + type: 'warning' + }).then(() => { + deleteTemplate(item.id).then(res=>{ + if(res && res.success){ + this.updateTemplates(); + this.$message({ + type: 'success', + message: '鍒犻櫎鎴愬姛!' + }); + } + }) + + }).catch(() => { + console.log('鍙栨秷鍒犻櫎'); + }); + }, + handleSaveTemplate() { + let editorResp = this.$refs.ruleEditor.submitRule(); + this.appSceneForm.rules = JSON.stringify(editorResp.rules); + this.appSceneForm.txt = editorResp.text; + + saveTemplate(this.appSceneForm).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "妯℃澘鍒涘缓鎴愬姛" + }); + this.updateTemplates(); + this.sceneDialogVisible = false; + } + }); + } + } }; </script> <style lang="scss"> @@ -820,7 +1653,7 @@ // background-color: #f2f6fc; .s-video-manage-breadcrumb { height: 5%; - -webkit-box-sizing: border-box; + box-sizing: border-box; border: 1px solid #e4e7ed; background-color: rgb(255, 255, 255); -webkit-box-shadow: #e4e7ed 0px 0px 9px inset; @@ -858,4 +1691,805 @@ color: #606266; cursor: pointer; } + + + +.installInfo{ + text-indent: 2em; + font-size: 14px; + color: #777; + p{ + text-align: center; + color: #666; + } +} +.task-manage { + height: 100%; + .installModel{ + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + position: fixed; + top: 0; + left: 0; + z-index: 100; + .progress-bar{ + width: 70%; + height: 17px; + border-radius: 3px; + background-color: rgb(227, 229, 231); + position: absolute; + top: 50%; + left: 50%; + background: url(../../../assets/gif/green.gif); + overflow: hidden; + transform: translate(-50%,-50%); + .inner-bar{ + position: absolute; + top: 0; + left: 0; + width: 0; + height: 100%; + transition: width 3s; + background-color: #3d68e1; + } + } + } + .el-tab-pane { + height: auto !important; + } + .el-tabs--border-card > .el-tabs__content { + padding: 0 !important; + overflow: auto !important; + } + .el-tabs__content { + padding: 0 !important; + overflow: auto !important; + } + //height: calc(100% - 10px); + // .super { + // .right-box { + // width: 58% !important; + // } + // } + .edit-rules-box{ + padding: 0 2px 0 13px; + } + .common { + .rigth-box { + width: 90% !important; + } + } + .super, + .common { + width: 100%; + height: 100%; + .title { + margin-bottom: 10px; + line-height: 30px; + font-family: PingFangSC-Medium; + font-size: 16px; + color: #222222; + } + .left-box { + // width: 41%; + height: 100%; + padding-top: 10px; + box-sizing: border-box; + // float: left; + + .action-bar { + margin-bottom: 30px; + .el-input { + width: 100%; + } + } + .task-list { + background: #fff; + padding: 30px 20px 20px; + box-sizing: border-box; + .flex-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + // justify-content: space-around; + // align-content: space-around; + // &:after { + // content: ""; + // flex: auto; + // } + .wrap-box { + width: 16.66%; + } + .list-choose-item-left { + // width: 220px; + // height: 214px; + width: 80%; + height: auto; + margin: auto; + margin-bottom: 30px; + // @media screen and(min-width: 1895px) { + // //margin: 20px 25px 20px 20px; + // width: 230px; + // height: 224px; + // } + // @media screen and(min-width: 1695px) and(max-width:1895px ) { + // margin: 20px 10px 20px 15px; + // } + // @media screen and(min-width: 1460px) and(max-width: 1695px) { + // margin: 20px 25px 20px 20px; + // } + // @media screen and(max-width: 1460px) { + // margin: 20px 15px 20px 10px; + // } + } + } + } + .appScenarios-list { + display: flex; + flex-wrap: wrap; + .wrap-box { + width: 16.6%; + margin-bottom: 30px; + .inner { + width: 80%; + + box-sizing: border-box; + position: relative; + font-size: 14px; + padding: 20px 0 50px; + transition: all 1s; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + margin: auto; + &:hover{ + .mask{ + display: block; + } + } + .mask{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(1px) brightness(100%); + text-align: center; + z-index: 1; + border-radius: 3px; + display: none; + .tool{ + position: absolute; + top: 49%; + left: 50%; + transform: translate(-50%,-50%); + i{ + font-size: 50px; + } + i:nth-of-type(1){ + margin-right: 30px; + } + i:nth-of-type(2){ + color: red; + } + } + } + .scenario-icon { + display: flex; + width: 100%; + height: 100%; + margin: auto; + justify-content: center; + align-content: center; + align-items: center; + .single, + .double, + .third, + .four { + width: 80%; + padding-top: 80%; + position: relative; + margin: auto; + display: flex; + flex-wrap: wrap; + justify-content: center; + .svg-wrap { + width: 50%; + position: absolute; + height: 0; + padding-top: 50%; + text-align: center; + box-shadow: 0 0 3px 2px rgb(247, 247, 247) inset; + svg { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + .baseImg { + position: absolute !important; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + } + .single { + margin: auto; + .svg-wrap{ + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + box-shadow: none; + } + } + .double{ + .svg-wrap:nth-of-type(1){ + top: 50%; + transform: translateY(-50%); + left: 0; + } + .svg-wrap:nth-of-type(2){ + top: 50%; + transform: translateY(-50%); + right: 0; + } + } + .third{ + .svg-wrap:nth-of-type(1){ + top: 0; + left: 0; + } + .svg-wrap:nth-of-type(2){ + top: 0; + right: 0; + } + .svg-wrap:nth-of-type(3){ + top: 50%; + left: 50%; + transform: translateX(-50%); + } + } + .four{ + .svg-wrap:nth-of-type(1){ + top: 0; + left: 0; + } + .svg-wrap:nth-of-type(2){ + top: 0; + right: 0; + } + .svg-wrap:nth-of-type(3){ + top: 50%; + left: 0; + } + .svg-wrap:nth-of-type(4){ + top: 50%; + right: 0; + } + } + } + .scenario-name { + width: 100%; + height: 36px; + line-height: 36px; + text-align: center; + position: absolute; + bottom: 10px; + left: 0; + } + } + + } + } + .store-list { + display: flex; + flex-wrap: wrap; + .wrap-box { + width: 16.6%; + margin-bottom: 30px; + .inner { + width: 80%; + box-sizing: border-box; + position: relative; + font-size: 14px; + padding-bottom: 10px; + transition: all 1s; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + margin: auto; + .alg-icon { + position: relative; + width: 80%; + margin: auto; + padding-top: 80%; + svg{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + + } + } + .alg-name { + height: 36px; + text-align: center; + line-height: 36px; + } + .mask { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(1px) brightness(100%); + text-align: center; + z-index: 1; + border-radius: 3px; + display: none; + svg { + position: absolute; + top: 49%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 33; + } + } + &:hover { + .mask { + display: block; + } + } + } + } + } + .drawer-content { + font-family: "PingFangSC-Regular"; + .el-step__title.is-process { + border-color: #3d68e1 !important; + color: #3d68e1 !important; + font-family: Tahoma, Helvetica, Arial, "\5B8B\4F53", sans-serif; + } + .el-step__head.is-process { + border-color: #3d68e1 !important; + color: #3d68e1 !important; + font-family: Tahoma, Helvetica, Arial, "\5B8B\4F53", sans-serif; + } + .el-input { + width: 100%; + margin-bottom: 30px; + } + .current-step { + margin: 40px 30px 30px; + } + .act-code { + padding: 0 30px; + p { + font-size: 15px; + margin-bottom: 16px; + } + } + .desc { + padding: 0 30px; + margin-bottom: 30px; + li { + border-bottom: 1px solid #eee; + height: 45px; + line-height: 45px; + font-size: 14px; + &:last-child { + border-bottom: none; + } + label { + display: inline-block; + width: 90px; + padding-left: 14px; + font-weight: bold; + } + } + } + .text-right { + padding-right: 30px; + .tip{ + color: #999; + line-height: 38px; + } + } + } + .tab-content { + padding: 30px 20px; + } + } + + .right-box { + height: 100%; + padding: 10px 10px; + box-sizing: border-box; + float: left; + .task-manage-table { + height: calc(100% - 30px); + margin-top: 5px; + overflow-x: hidden; + overflow-y: auto; + } + // .task-manage-table::-webkit-scrollbar { + // width: 0 !important ; + // } + } + .mask { + position: absolute; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(1px) brightness(100%); + text-align: center; + z-index: 1; + border-radius: 3px; + display: none; + + i { + color: #fff; + position: relative; + top: 40%; + display: contents; + } + i:hover { + color: rgba(255, 255, 255, 0.685); + } + } + + .text-css { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + } + .move-hear { + margin: 10px 0 0 0; + font-size: 5rem; + } + .list-choose-item { + cursor: pointer; + position: relative; + font-size: 14px; + display: inline-block; + @media screen and(min-width: 1640px) { + margin: 30px 20px 20px 20px; + } + @media screen and(min-width: 1460px) and(max-width: 1640px) { + margin: 30px 20px 20px 10px; + } + @media screen and(max-width: 1460px) { + margin: 30px 10px 20px 10px; + } + min-width: 126px; + height: 120px; + transition: all 1s; + background: #fff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + } + .list-choose-item:hover { + .mask { + display: block; + } + } + + .alg-shadow { + -webkit-box-shadow: 0px 0px 10px 3px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0px 0px 10px 3px rgba(0, 0, 0, 0.3); + box-shadow: 0px 0px 10px 3px rgba(0, 0, 0, 0.3); + } + .select-color { + margin-top: 16px; + text-align: center; + line-height: 28px; + // background-color: #3498DB; + } + .list-choose-item-left { + cursor: pointer; + position: relative; + font-size: 14px; + // display: inline-block; + // @media screen and(min-width: 1895px) { + // //margin: 20px 25px 20px 20px; + // margin: 20px 30px 20px 20px; + // } + // @media screen and(min-width: 1695px) and(max-width:1895px ) { + // margin: 20px 10px 20px 15px; + // } + // @media screen and(min-width: 1460px) and(max-width: 1695px) { + // margin: 20px 25px 20px 20px; + // } + // @media screen and(max-width: 1460px) { + // margin: 20px 15px 20px 10px; + // } + // width: 126px; + // height: 120px; + // width: 220px; + // height: 214px; + transition: all 1s; + background: #ffffff; + border: 1px solid #e2e2e2; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 4px; + p { + display: none; + text-align: right; + width: 100%; + position: absolute; + right: 10px; + top: 5px; + } + .click-download { + position: absolute; + left: 80%; + top: 5%; + } + } + .list-choose-item-left:hover { + .mask { + display: flex; + align-items: flex-end; + .bot-btn { + flex: 1; + } + } + } + .list-choose-item-left-uninstal { + color: darkgray; + background-color: #ddd; + } + .list-complete-item.sortable-chosen { + background: #4ab7bd; + } + .list-choose-item.sortable-ghost { + background: #30b08f; + } + .width-new-line { + word-wrap: break-word; + word-break: break-all; + } + .dndList-list { + max-width: 40%; + } + .dic-border { + width: 98%; + min-height: 170px; + background: #fff; + padding: 10px 10px 10px 20px; + } + .min-h { + min-height: 130px; + } + .parent-div { + border-right: 1px solid rgba(24, 28, 33, 0.5); + max-width: 140px; + position: relative; + } + .list-choose-header { + position: relative; + width: 74px; + height: 74px; + background-image: linear-gradient(-137deg, #7076f2 0%, #3d63e1 100%); + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + border-radius: 37px; + margin: 10px 25px; + } + + .task-name-div { + font-family: PingFangSC-Medium; + font-size: 15px; + color: #4b68e6; + text-align: center; + margin-top: 6px; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .border-dash { + height: 30px; + width: 96%; + margin-bottom: 10px; + border: 1px dashed rgba(24, 28, 33, 0.5); + } + .i-setting { + position: absolute; + font-size: 28px; + margin-top: -25px; + margin-left: -30px; + } + .i-delete { + position: absolute; + font-size: 28px; + margin-top: -25px; + margin-left: -8px; + color: red; + } + .i-bell { + float: left; + position: relative; + left: 10px; + top: 10px; + font-size: 24px; + color: red; + } + .task-msg { + padding-left: 10px; + } + .b-top { + width: 100%; + padding-top: 10px; + } + .b-bottom { + width: 100%; + border-bottom: 1px solid rgba(24, 28, 33, 0.5); + } + .i-set-right { + position: absolute; + left: 80px; + top: -11px; + font-size: 24px; + } + .i-remove-right { + position: absolute; + right: -1px; + top: -11px; + font-size: 24px; + color: red; + } + .alg-t { + line-height: 31px; + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + } + .alg-name { + margin-top: 12px; + line-height: 36px; + font-family: PingFangSC-Regular; + font-size: 15px; + color: #222222; + // background-color: #ecf5ff; + .el-input { + position: relative; + font-size: 14px; + display: inline-block; + width: 100%; + } + } + .task-name { + text-align: center; + margin-top: 16px; + line-height: 28px; + font-family: PingFangSC-Regular; + font-size: 13px; + color: #222222; + text-align: center; + // background-color: #ecf5ff; + } + .unit-class { + margin-left: 10px; + text-align: center; + line-height: 38px; + } + .el-input { + position: relative; + font-size: 14px; + display: inline-block; + width: 80%; + } + .list-complete-item-handle { + height: 100%; + padding-bottom: 10px; + text-align: center; + .svg-wrap{ + width: 80%; + margin: auto; + padding-top: 80%; + position: relative; + svg{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + } + .baseImg { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + } + } + } + .dragAreaR { + height: 100%; + } + .drag-info { + min-width: 126px; + height: 120px; + border: 1px dashed #3d68e1; + box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07); + // box-shadow: 0px 0px 10px 3px rgba(0,0,0,0.3); + border-radius: 4px; + margin: 30px 10px 20px 10px; + } + .drag-info-text { + letter-spacing: 3px; + line-height: 20px; + width: 80px; + height: 42px; + font-family: PingFangSC-Regular; + font-size: 13px; + color: #3d68e1; + text-align: center; + } + .task-edit { + font-size: 26px; + position: relative; + bottom: -6px; + } + .el-button--cancle { + background: #eaeaea; + border-radius: 2px; + border-color: #eaeaea; + font-family: PingFangSC-Medium; + font-size: 13px; + color: #222222; + margin-right: 12px; + } + .click-changeImg { + cursor: pointer; + display: none; + background: rgba(0, 0, 0, 0.35); + width: 74px; + line-height: 20px; + color: rgb(255, 255, 255); + font-size: 14px; + opacity: 1; + border-radius: 6px; + } + + .task-name-google { + position: relative; + top: 30px; + width: 126px; + height: 120px; + border: 1px solid #fff; + background: #fff; + border-radius: 4px; + cursor: pointer; + .set-task { + display: none; + cursor: pointer; + } + + .el-switch__core { + width: 27px !important; + height: 14px; + } + .el-switch__core:after { + width: 10px; + height: 10px; + } + .el-switch.is-checked .el-switch__core::after { + left: 100%; + margin-left: -11px; + } + } + .task-name-google:hover { + .mask { + display: block; + } + } + } +} </style> + diff --git a/src/pages/algorithmManage/index/mixins.ts b/src/pages/algorithmManage/index/mixins.ts new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/pages/algorithmManage/index/mixins.ts diff --git a/src/pages/desktop/index/components/DFrame.vue b/src/pages/desktop/index/components/DFrame.vue index f7c5feb..ae5e3ac 100644 --- a/src/pages/desktop/index/components/DFrame.vue +++ b/src/pages/desktop/index/components/DFrame.vue @@ -41,6 +41,7 @@ }, mounted() { window.addEventListener('message', e => { + console.log(e) if (e.data && e.data.msg == "logout") { location.assign("/"); } diff --git a/src/pages/desktop/index/components/Tools.vue b/src/pages/desktop/index/components/Tools.vue index a874279..124e00a 100644 --- a/src/pages/desktop/index/components/Tools.vue +++ b/src/pages/desktop/index/components/Tools.vue @@ -1,6 +1,6 @@ <template> <div class="tools"> - <div class="center"> + <div class="tools-left"> <div :class="['tools-icon','tools-show-desktop', {clicked:this.$store.state.desktop.preferenceVisiable}]" @@ -50,7 +50,7 @@ ></span> </div> --> </div> - </div> + </div> </template> @@ -150,7 +150,7 @@ width: 200px; height: 100%; float: left; - margin-left: 8px; + margin-left: 14px; } .tools .tools-middle{ float: left; @@ -206,5 +206,6 @@ .tools .tools-right { float: right; height: 100%; + margin-right: 14px; } </style> \ No newline at end of file diff --git a/src/pages/desktop/index/components/ToolsEntry.vue b/src/pages/desktop/index/components/ToolsEntry.vue index ea7b7cd..c98b1e5 100644 --- a/src/pages/desktop/index/components/ToolsEntry.vue +++ b/src/pages/desktop/index/components/ToolsEntry.vue @@ -21,26 +21,26 @@ data(){ return { publicPath: process.env.BASE_URL, - applist:[ - {src: `/images/app-mid/camera-access.png`, name:'鎽勫儚鏈烘帴鍏�'}, - {src: `/images/app-mid/datastack-config.png`, name:'鏁版嵁鏍堥厤缃�'}, - {src: `/images/app-mid/DVR-access.png`, name:'纭洏褰曞儚鏈烘帴鍏�'}, - {src: `/images/app-mid/data-push.png`, name:'鏁版嵁鎺ㄩ��'}, - {src: `/images/app-mid/GB-config.png`, name:'GB28281閰嶇疆'}, - {src: `/images/app-mid/scene-config.png`, name:'鍦烘櫙閰嶇疆'}, - {src: `/images/app-mid/library.png`, name:'姣斿搴撶鐞�'}, - {src: `/images/app-mid/poll.png`, name:'杞绠$悊'}, - {src: `/images/app-mid/algorithm-manage.png`, name:'绠楁硶绠$悊'}, - {src: `/images/app-mid/algorithm-store.png`, name:'绠楁硶鍟嗗煄'}, - {src: `/images/app-mid/hashrate-manage.png`, name:'绠楀姏绠$悊'}, - {src: `/images/app-mid/monitor.png`, name:'瀹炴椂鐩戞帶-鍦ㄧ嚎鎾斁'}, - {src: `/images/app-mid/search.png`, name:'妫�绱�-缁熻鏌ヨ'}, - {src: `/images/app-mid/360.png`, name:'鍏ㄦ櫙瑙嗛'}, - {src: `/images/app-mid/log-manage.png`, name:'鏃ュ織绠$悊'}, - {src: `/images/app-mid/device.png`, name:'璁惧绠$悊'}, - {src: `/images/app-mid/settings.png`, name:'绯荤粺璁剧疆'}, - {src: `/images/app-mid/vindicate.png`, name:'绯荤粺缁存姢'} - ] + // applist:[ + // {src: `/images/app-mid/camera-access.png`, name:'鎽勫儚鏈烘帴鍏�'}, + // {src: `/images/app-mid/datastack-config.png`, name:'鏁版嵁鏍堥厤缃�'}, + // {src: `/images/app-mid/DVR-access.png`, name:'纭洏褰曞儚鏈烘帴鍏�'}, + // {src: `/images/app-mid/data-push.png`, name:'鏁版嵁鎺ㄩ��'}, + // {src: `/images/app-mid/GB-config.png`, name:'GB28281閰嶇疆'}, + // {src: `/images/app-mid/scene-config.png`, name:'鍦烘櫙閰嶇疆'}, + // {src: `/images/app-mid/library.png`, name:'姣斿搴撶鐞�'}, + // {src: `/images/app-mid/poll.png`, name:'杞绠$悊'}, + // {src: `/images/app-mid/algorithm-manage.png`, name:'绠楁硶绠$悊'}, + // {src: `/images/app-mid/algorithm-store.png`, name:'绠楁硶鍟嗗煄'}, + // {src: `/images/app-mid/hashrate-manage.png`, name:'绠楀姏绠$悊'}, + // {src: `/images/app-mid/monitor.png`, name:'瀹炴椂鐩戞帶-鍦ㄧ嚎鎾斁'}, + // {src: `/images/app-mid/search.png`, name:'妫�绱�-缁熻鏌ヨ'}, + // {src: `/images/app-mid/360.png`, name:'鍏ㄦ櫙瑙嗛'}, + // {src: `/images/app-mid/log-manage.png`, name:'鏃ュ織绠$悊'}, + // {src: `/images/app-mid/device.png`, name:'璁惧绠$悊'}, + // {src: `/images/app-mid/settings.png`, name:'绯荤粺璁剧疆'}, + // {src: `/images/app-mid/vindicate.png`, name:'绯荤粺缁存姢'} + // ] } }, methods:{ diff --git a/src/pages/desktop/index/mock/userData.json b/src/pages/desktop/index/mock/userData.json index 6630892..f6e7281 100644 --- a/src/pages/desktop/index/mock/userData.json +++ b/src/pages/desktop/index/mock/userData.json @@ -116,7 +116,7 @@ "name": "鍏ㄦ櫙瑙嗛" }, { - "id": "14", + "id": "15", "src": "../../images/app-mid/log-manage.png", "alt": "鏃ュ織绠$悊", "type": "2", @@ -124,7 +124,7 @@ "name": "鏃ュ織绠$悊" }, { - "id": "14", + "id": "16", "src": "../../images/app-mid/device.png", "alt": "璁惧绠$悊", "type": "2", @@ -132,7 +132,7 @@ "name": "璁惧绠$悊" }, { - "id": "15", + "id": "17", "src": "../../images/app-mid/settings.png", "alt": "绯荤粺璁剧疆", "type": "2", @@ -140,7 +140,7 @@ "name": "绯荤粺璁剧疆" }, { - "id": "16", + "id": "18", "src": "../../images/app-mid/vindicate.png", "alt": "绯荤粺缁存姢", "type": "2", diff --git a/src/pages/settings/components/AuthorityManagement.vue b/src/pages/settings/components/AuthorityManagement.vue new file mode 100644 index 0000000..ec9c663 --- /dev/null +++ b/src/pages/settings/components/AuthorityManagement.vue @@ -0,0 +1,265 @@ +<template> + <div class="s-authority-management"> + <div class="authority-table s-table" v-if="display"> + <el-table + highlight-current-row + :data="userList" + style="width: 100%" + :header-cell-style="{background:'#f8f8f8',color:'#222222'}" + > + <el-table-column align="center" type="index" label="搴忓彿" width="100"></el-table-column> + <el-table-column :align="'center'" prop="username" label="鐢ㄦ埛鍚�"></el-table-column> + <el-table-column :align="'center'" prop="role" label="瑙掕壊"> + <template slot-scope="scope">{{scope.row.sysRoles | roles}}</template> + </el-table-column> + <el-table-column label="鎿嶄綔" :align="'center'"> + <template slot-scope="scope"> + <el-tooltip content="缂栬緫" placement="top" popper-class="atooltip"> + <i + icon="el-icon-edit" + style="font-size: 28px;" + @click="handleEdit(scope.$index, scope.row)" + ></i> + </el-tooltip> + <el-tooltip content="鍒犻櫎" placement="top" popper-class="atooltip" v-show="false"> + <!-- :disabled="scope.row.sysRoles | roles | isSuper" --> + <i + icon="el-icon-delete" + style="font-size: 28px; color:red;" + @click="handleDelete(scope.$index, scope.row)" + ></i> + </el-tooltip> + </template> + </el-table-column> + </el-table> + </div> + <div class="authority-details" v-if="!display"> + <el-form label-width="80px" :rules="rules" ref="editForm" :model="editForm"> + <el-form-item label="鐢ㄦ埛鍚�" style="width:580px" prop="username"> + <!-- <el-input v-model="editForm.username" placeholder="璇疯緭鍏�" size="small"></el-input> --> + <span class="m10" v-if="editForm.username == 'admin' || editForm.username == 'basic'">{{editForm.username}}</span> + <el-input v-model="editForm.username" size="small" v-else></el-input> + </el-form-item> + + <el-form-item label="鏂板瘑鐮�" style="width:580px" v-show="loginUser != editForm.username"> + <el-input show-password v-model="editForm.newPwd" placeholder="璇疯緭鍏ュ瘑鐮�" size="small"></el-input> + </el-form-item> + + <el-form-item + label="纭瀵嗙爜" + style="width:580px" + prop="checkPass" + v-show="loginUser != editForm.username" + > + <el-input show-password v-model="editForm.checkPass" placeholder="璇疯緭鍏ュ啀娆¤緭鍏ュ瘑鐮�" size="small"></el-input> + </el-form-item> + + <el-form-item label="鏉冮檺閰嶇疆" style="width:580px;"> + <!-- <el-transfer + id="e-transfer" + :titles="['鍏ㄩ儴瑙掕壊', '褰撳墠瑙掕壊']" + v-model="editForm.roleIds" + :props="{key: 'id', label: 'name'}" + :data="roledata" + ></el-transfer>--> + + <el-tree + ref="treeMenus" + :data="sysMenus" + :props="props" + node-key="id" + :default-checked-keys="userMenus" + show-checkbox + check-on-click-node + default-expand-all + style="margin-top: 10px;" + ></el-tree> + </el-form-item> + + <el-form-item style="width:580px;"> + <el-button type="primary" style="float: right" @click="save" size="small">淇濆瓨</el-button> + <el-button type="info" style="margin-right: 10px;float: right" @click="goback" size="small">杩斿洖</el-button> + </el-form-item> + </el-form> + </div> + </div> +</template> + +<script> + +import { getUsers, getSysMenus, updataUser, getUserMenus } from "@/api/user" + +export default { + name: "AuthorityManage", + filters: { + roles(roles) { + return roles.map(r => { + return r.name + }).join(' ') + }, + isSuper(roles) { + return roles.indexOf("瓒呯骇绠$悊鍛�") >= 0 + } + }, + data() { + const generateData = _ => { + const data = []; + for (let i = 1; i <= 15; i++) { + data.push({ + key: i, + label: `澶囬�夐」 ${i}`, + disabled: i % 4 === 0 + }); + } + return data; + }; + const validateCheckPass = (rule, value, callback) => { + if (value !== this.editForm.newPwd) { + callback(new Error('涓ゆ杈撳叆瀵嗙爜涓嶄竴鑷�!')); + } else { + callback() + } + }; + var checkUserName = (rule, value, callback) => { + 聽聽if (value && value !== ''){ + 聽聽聽聽let regEn = /^[A-Za-z_@.]{2,10}$/ + console.log("鐢ㄦ埛鍚嶆牎楠岋紒",value) + 聽聽聽聽if (!regEn.test(value)) { + 聽聽聽聽聽聽callback(new Error('璇疯緭鍏�2浣嶅埌10浣嶅瓧姣嶇殑鐢ㄦ埛鍚嶏紝涓嶈兘浠ユ暟瀛楀紑澶达紝涓斾笉鑳藉寘鍚眽瀛�')) + 聽聽聽聽} else { + 聽聽聽聽聽聽callback() + 聽聽聽聽} + 聽聽} else { + 聽聽聽聽callback() + 聽聽} + } + return { + display: true, + loginUser: JSON.parse(sessionStorage.getItem('userInfo')).username, + acknewpwd: "", + sysMenus: [], + userMenus: [], + rolevalue: [], + userList: [], + editForm: {}, + props: { + label: 'name' + }, + rules: { + username: [ + { validator: checkUserName, trigger: 'blur' } + ], + checkPass: [ + { validator: validateCheckPass, trigger: 'change' } + ] + } + }; + }, + mounted() { + this.fetchUserList(); + this.fetchSysMenus(); + this.initEditForm(); + }, + methods: { + initEditForm() { + this.editForm = { + id: "", + username: "", + newPwd: "", + checkPass: "", + menuIds: [] + } + }, + handleEdit(index, row) { + this.initEditForm() + this.display = !this.display; + this.editForm.id = row.id; + this.editForm.username = row.username; + this.userMenus = [] + getUserMenus({ userId: row.id }).then(rsp => { + if (rsp && rsp.success) { + this.userMenus = rsp.data.menus.map(menu => { + return menu.id + }) + } + }) + + }, + handleDelete(index, row) { + this.$notify({ + type: "warning", + message: "鏃犳硶鍒犻櫎璇ョ敤鎴�" + }) + }, + goback() { + this.display = !this.display; + }, + save() { + this.$refs.editForm.validate((valid) => { + if (valid) { + this.editForm.menuIds = this.$refs.treeMenus.getCheckedKeys() + updataUser(this.editForm).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "淇敼鎴愬姛" + }) + } + }) + } + }); + }, + fetchUserList() { + getUsers().then(rsp => { + if (rsp && rsp.success) { + this.userList = rsp.data; + } + }) + }, + fetchSysMenus() { + getSysMenus().then(rsp => { + if (rsp && rsp.success) { + this.sysMenus = rsp.data; + } + }) + } + } +}; +</script> +<style lang="scss"> +.s-authority-management { + height: 100%; + width: 100%; + .authority-table, + .authority-details { + height: 100%; + width: 100%; + margin-top: 40px; + } + #e-transfer { + .el-button--primary { + color: #fff; + background-color: #bfbfbf; + border-color: #bfbfbf; + } + .el-button--primary:focus, + .el-button--primary:hover { + background: #4c4c4c; + border-color: #4c4c4c; + color: #fff; + } + .el-transfer-panel + .el-transfer-panel__header + .el-checkbox + .el-checkbox__label { + font-size: 14px; + } + } + .el-form-item__content { + text-align: left; + input { + max-width: 498px; + } + } +} +</style> diff --git a/src/pages/settings/components/BasicSetting.vue b/src/pages/settings/components/BasicSetting.vue new file mode 100644 index 0000000..5806be8 --- /dev/null +++ b/src/pages/settings/components/BasicSetting.vue @@ -0,0 +1,1307 @@ +<template> + <div class="s-basic-setting"> + <el-tabs + id="e-basic-setting" + v-model="activeName" + v-loading="loading" + :element-loading-text="loadingText" + > + <!-- 鏈満淇℃伅 --> + <el-tab-pane label="鏈満淇℃伅" name="first"> + <el-menu + :default-openeds="openeds" + background-color="#fff" + text-color="#303133" + active-text-color="#409EFF" + style="height: 100%;" + class="menu-css" + @open="menuOpen" + @close="menuClose" + > + <!-- 鏈満淇℃伅 --> + <el-submenu index="0"> + <template slot="title"> + <b class="tree-font">鏈満淇℃伅</b> + </template> + <el-menu-item-group class="item-group"> + <el-form :model="sysinfo" :rules="rules" ref="sysinfo" label-width="100px"> + <el-row> + <el-col :span="12"> + <el-form-item label="鍚嶇О" prop="server_name"> + <el-input v-model="sysinfo.server_name" placeholder="鏈嶅姟鍣ㄥ悕绉�" size="small"></el-input> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="绔彛" prop="server_port"> + <el-input v-model="sysinfo.server_port" placeholder="WEB鏈嶅姟绔彛" size="small"></el-input> + </el-form-item> + </el-col> + </el-row> + + <el-row> + <el-col :span="12"> + <el-form-item label="IP" prop="ip"> + <ip-input :ip="sysinfo.ip" @on-blur="sysinfo.ip = arguments[0]"></ip-input> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="瀛愮綉鎺╃爜" prop="subMask"> + <ip-input :ip="sysinfo.subMask" @on-blur="sysinfo.subMask = arguments[0]"></ip-input> + </el-form-item> + </el-col> + </el-row> + + <el-row> + <el-col :span="12"> + <el-form-item label="缃戝叧" prop="gateway"> + <ip-input :ip="sysinfo.gateway" @on-blur="sysinfo.gateway = arguments[0]"></ip-input> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="DNS" prop="dns"> + <ip-input :ip="sysinfo.dns" @on-blur="sysinfo.dns = arguments[0]"></ip-input> + </el-form-item> + </el-col> + </el-row> + <div class="mt15 mb10 save-btn"> + <el-button type="primary" @click="submitSysinfo" size="small">淇濆瓨</el-button> + </div> + </el-form> + </el-menu-item-group> + </el-submenu> + + <!-- 璇︾粏淇℃伅 --> + <el-submenu index="1"> + <template slot="title"> + <b class="tree-font">璇︾粏淇℃伅</b> + </template> + <el-menu-item-group class="item-group"> + <el-row :gutter="gutter"> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">ID</div> + <div class="xiangqing-info">{{sysinfo.server_id}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">璁惧缂栧彿</div> + <div class="xiangqing-info">{{sysinfo.deviceNum}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">璁惧鍨嬪彿</div> + <div class="xiangqing-info">{{sysinfo.deviceType}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">璁惧搴忓垪鍙�</div> + <div class="xiangqing-info">{{sysinfo.deviceSerialNum}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">涓绘帶鐗堟湰</div> + <div class="xiangqing-info">{{sysinfo.masterVersion}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">web鐗堟湰</div> + <div class="xiangqing-info">{{sysinfo.webVersion}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">閫氶亾涓暟</div> + <div class="xiangqing-info">{{sysinfo.channelCount}}</div> + </el-col> + <el-col :span="12" class="flex-box"> + <div class="xiangqin-label">纭洏涓暟</div> + <div class="xiangqing-info">{{sysinfo.diskCount}}</div> + </el-col> + </el-row> + </el-menu-item-group> + </el-submenu> + <!-- 浜嬩欢褰曞儚鏃堕暱 --> + <el-submenu index="2"> + <template slot="title"> + <b class="tree-font">浜嬩欢褰曞儚鏃堕暱</b> + </template> + <el-menu-item-group class="item-group"> + <el-form + label-width="150px" + class="alarmSetting" + style="padding-left:5px;padding-right:5px;" + > + <el-form-item label="瑙嗛鎴彇鏈�鐭椂闀�" style="width:724px;"> + <el-slider + id="cut_min_duration" + v-model="alarmConf.min_video_len" + :show-tooltip="false" + ></el-slider> + <el-input-number + v-model="alarmConf.min_video_len" + controls-position="right" + :min="0" + :max="100" + size="small" + ></el-input-number> s + </el-form-item> + <el-form-item label="瑙嗛鎴彇鏈�闀挎椂闀�" style="width:724px"> + <el-slider + id="cut_max_duration" + v-model="alarmConf.max_video_len" + :show-tooltip="false" + ></el-slider> + <el-input-number + v-model="alarmConf.max_video_len" + controls-position="right" + :min="0" + :max="100" + size="small" + ></el-input-number> s + </el-form-item> + <div class="mt15 mb10 save-btn"> + <el-button type="primary" @click="submitAlarm" size="small">淇濆瓨</el-button> + </div> + </el-form> + </el-menu-item-group> + </el-submenu> + <!-- 瀵瑰鏈嶅姟IP 鏀瑰悕涓哄閮ㄧ綉缁�(鏂皌ab)--> + + <!-- 鏂囦欢闊宠棰� --> + <!-- <el-submenu index="4"> + <template slot="title"> + <b class="tree-font">鏂囦欢闊宠棰�</b> + </template> + <el-menu-item-group class="item-group"> + <el-row :gutter="20"> + <el-col :span="8"> + <div class="p5"> + <span class="iconfont iconpicture" style="margin-right: 5px;"></span> + <span class="mr10">鍥剧墖绔彛</span> + <el-input v-model="localFile.picPort" style="width:300px;" placeholder="璇疯緭鍏ュ唴瀹�"></el-input> + </div> + <div class="p5"> + <span class="iconfont iconshipin" style="margin-right: 5px;"></span> + <span class="mr10">瑙嗛绔彛</span> + <el-input v-model="localFile.videoPort" style="width:300px;" placeholder="璇疯緭鍏ュ唴瀹�"></el-input> + </div> + <div class="p5"> + <span class="iconfont iconyinpinx" style="margin-right: 5px;"></span> + <span class="mr10">闊抽绔彛</span> + <el-input v-model="localFile.audioPort" style="width:300px;" placeholder="璇疯緭鍏ュ唴瀹�"></el-input> + </div> + </el-col> + <el-col :span="16"> + <el-table + :data="localFile.fileTable" + border + style="width: 100%"> + <el-table-column + type="index" + label="搴忓彿" + align="center" + width="50"> + </el-table-column> + <el-table-column + prop="date" + label="鍚嶇О" + align="center" + width="180"> + </el-table-column> + <el-table-column + prop="name" + label="ID" + align="center" + width="180"> + </el-table-column> + <el-table-column + prop="name" + label="IP" + align="center" + width="180"> + </el-table-column> + <el-table-column + prop="name" + label="鍦ㄧ嚎鐘舵��" + align="center" + width="80"> + </el-table-column> + <el-table-column + label="绫诲埆" + align="center" + width="100"> + <template> + <span class="iconfont iconpicture" style="margin-right: 5px;"></span> + <span class="iconfont iconshipin" style="margin-right: 5px;"></span> + <span class="iconfont iconyinpinx" style="margin-right: 5px;"></span> + </template> + </el-table-column> + <el-table-column + prop="address" + align="center" + label="澶囨敞"> + <template slot-scope="{row}"> + <div v-if="row.edit"> + <el-input :autofocus="row.edit" v-focus v-model="row.address" size="small" /> + <el-button size="mini" type="info" @click="handleCancel(row)">鍙栨秷</el-button> + <el-button size="mini" type="primary" @click="handleSave(row)">淇濆瓨</el-button> + </div> + <div v-else> + <span>{{ row.address }}</span> + <el-button + type="text" + style="color: black;font-size:16px" + @click="handleEdit(row)" + icon="iconfont iconbianji" + ></el-button> + </div> + </template> + </el-table-column> + </el-table> + </el-col> + </el-row> + </el-menu-item-group> + </el-submenu>--> + </el-menu> + </el-tab-pane> + + <!-- 鏃堕棿閰嶇疆 --> + <el-tab-pane label="鏃堕棿閰嶇疆" name="second"> + <el-form label-width="100px"> + <el-form-item label="璁惧鏃堕棿"> + <!-- <el-input v-model="equipmentTime" placeholder="璇疯緭鍏�" size="small"></el-input> --> + {{ equipmentTime }} + </el-form-item> + + <el-form-item label="鏃跺尯" prop="timezone"> + <el-select + v-model="timezone" + placeholder="璇烽�夋嫨" + style="width: 360px; height: 32px" + size="small" + > + <el-option + v-for="item in timeZoneOption" + :key="item.value" + :label="item.label" + :value="item.value" + ></el-option> + </el-select> + </el-form-item> + <div style="text-align: left;padding: 10px 0px"> + <div class="time-type">NTP鏍℃椂</div> + <div style="padding: 10px 0px;"> + <el-radio v-model="syncType" label="1">NTP鏍℃椂</el-radio> + </div> + </div> + + <el-form-item label="鏈嶅姟鍣ㄥ湴鍧�"> + <ip-input + :ip="ntpServer" + @on-blur="ntpServer= arguments[0]" + :disabled="syncType === '2'" + ></ip-input> + </el-form-item> + + <el-form-item label="鏍℃椂鏃堕棿闂撮殧" style="width: 41.3%;"> + <el-input-number + v-model.number="timeInterval" + :min="1" + :max="60" + placeholder="璇疯緭鍏�" + size="small" + :controls="false" + :disabled="syncType === '2'" + ></el-input-number> 鍒嗛挓 + <el-button + type="text" + style="position: absolute; left: 330px;" + :disabled="syncType === '2'" + @click="testNTP" + >娴嬭瘯</el-button> + </el-form-item> + + <div style="text-align: left;padding: 10px 0px"> + <div class="time-type">鎵嬪姩鏍℃椂</div> + <div style="padding: 10px 0px;"> + <el-radio v-model="syncType" label="2">鎵嬪姩鏍℃椂</el-radio> + </div> + </div> + + <el-form-item label="璁剧疆鏃堕棿"> + <el-date-picker + v-model="settime" + type="datetime" + placeholder="閫夋嫨鏃ユ湡鏃堕棿" + size="small" + value-format="yyyy-MM-dd HH:mm:ss" + :readonly="settimeRadio" + :disabled="syncType === '1'" + ></el-date-picker> + <el-checkbox + v-model="settimeRadio" + style="margin-left: 12px;" + @change="syncBrowser" + :disabled="syncType === '1'" + >鍚屾鏈绠楁満鏃堕棿</el-checkbox> + </el-form-item> + + <el-col :span="12" style="padding-right: 40px;"> + <el-form-item> + <el-button type="primary" @click="submitClock" size="small">淇濆瓨</el-button> + </el-form-item> + </el-col> + </el-form> + </el-tab-pane> + + <!-- 闆嗙兢绠$悊 --> + <el-tab-pane label="闆嗙兢绠$悊" name="third"> + <cluster-management></cluster-management> + </el-tab-pane> + <el-tab-pane label="澶栭儴缃戠粶" name="fourth"> + <el-row :gutter="20"> + <el-col :span="10"> + <div> + <div class="flex-box"> + <div style="line-height:32px;"> + <el-radio v-model="ipServer.diyOrLocalIP" :label="1">璁剧疆澶栭儴IP</el-radio> + <el-radio v-model="ipServer.diyOrLocalIP" :label="0">閫夌敤鏈満IP</el-radio> + </div> + <div class="ml10" style="width:205px;"> + <ip-input :ip="ipServer.ip" @on-blur="ipServer.ip = arguments[0]"></ip-input> + </div> + </div> + <div class="flex-box p5" > + <span style="line-height:32px;">鍩熷悕</span> + <div style="margin-left:14px;width:205px;"> + <el-input size="small" style v-model="ipServer.localhost"></el-input> + </div> + </div> + <div class="flex-box" > + <span style="line-height:32px;">鏈湴鏂囦欢绔彛</span> + <div style="margin-left:14px;width:205px;"> + <el-input size="small" style v-model="ipServer.localFilePort"></el-input> + </div> + </div> + </div> + </el-col> + <!-- <el-col :span="14"> + <div> + <el-table + :data="ipServer.fileTable" + border + fit + style="width: 100%"> + <el-table-column + type="index" + label="搴忓彿" + align="center" + width="50"> + </el-table-column> + <el-table-column + prop="date" + label="鍚嶇О" + align="center" + > + </el-table-column> + <el-table-column + prop="name" + label="ID" + align="center" + > + </el-table-column> + <el-table-column + prop="name" + label="IP" + align="center" + > + </el-table-column> + <el-table-column + prop="name" + label="鍦ㄧ嚎鐘舵��" + align="center" + > + </el-table-column> + </el-table> + </div> + </el-col>--> + </el-row> + <div class="mt15 save-btn" style="width:1000px;float:left;"> + <el-button type="primary" @click="submitResource" size="small">淇濆瓨</el-button> + </div> + </el-tab-pane> + <el-tab-pane label="鏉冮檺绠$悊" name="user" > + <authority-management v-if="activeName === 'user'"></authority-management> + </el-tab-pane> + <el-tab-pane label="骞挎挱璁剧疆" name="radio" > + <radio-set v-if="activeName === 'radio'"></radio-set> + </el-tab-pane> + <!-- GB28181璁剧疆 --> + <el-tab-pane label="GB28181璁剧疆" name="fifth"> + <el-form + :model="gb28181" + :rules="rules" + label-width="140px" + class="alarmSetting" + ref="gb28181" + > + <!-- <el-form-item label="鍥介檯鏈嶅姟鍣↖P" prop="ServerIp"> + <ip-input :ip="gb28181.ServerIp" @on-blur="gb28181.ServerIp = arguments[0]"></ip-input> + </el-form-item>--> + + <div style="text-align: left;margin-bottom: 22px;"> + <el-radio-group v-model="gb28181.idType"> + <el-radio :label="0">杈撳叆宸叉湁ID</el-radio> + <el-radio :label="1">鐢熸垚鏂扮殑ID</el-radio> + </el-radio-group> + </div> + + <el-form-item label="鎵�鍦ㄥ湴"> + <el-select + v-model="locationCity.province" + @change="changeProvince" + size="small" + placeholder="璇烽�夋嫨鐪佷唤" + > + <el-option + v-for="item in locationCity.provinceOptions" + :key="item.id" + :label="item.name" + size="small" + :value="item.id" + ></el-option> + </el-select> + <el-select + class="ml10 mr10" + v-model="locationCity.city" + :disabled="!locationCity.province" + @change="changeCity" + size="small" + placeholder="璇烽�夋嫨鍩庡競" + > + <el-option + v-for="item in locationCity.cityOptions" + :key="item.id" + :label="item.name" + :value="item.id" + ></el-option> + </el-select> + <el-select + v-model="locationCity.county" + :disabled="!locationCity.city" + size="small" + placeholder="璇烽�夋嫨鍖哄幙" + > + <el-option + v-for="item in locationCity.countyOptions" + :key="item.id" + :label="item.name" + :value="item.id" + ></el-option> + </el-select> + <el-button + type="text" + style="position: absolute" + v-show="gb28181.idType === 1" + @click="newGBID" + >鐢熸垚ID</el-button> + </el-form-item> + + <!-- <el-form-item label="鍥介檯鏈嶅姟鍣ㄧ鍙�" prop="GbServerPort"> + <el-input v-model.number="gb28181.ServerPort" placeholder="璇疯緭鍏�" size="small"></el-input> + </el-form-item>--> + + <el-form-item label="鍥芥爣ID"> + <el-input v-model="gb28181.PublicId" placeholder="璇疯緭鍏�" size="small"></el-input> + </el-form-item> + + <el-form-item label="鍥芥爣绔彛" prop="ServerPort"> + <el-input v-model.number="gb28181.GbServerPort" placeholder="璇疯緭鍏�" size="small"></el-input> + </el-form-item> + + <el-form-item label="寮�鍚壌鏉�"> + <el-switch v-model="gb28181.IsAuth"></el-switch> + </el-form-item> + + <el-form-item label="閴存潈瀵嗙爜" v-show="gb28181.IsAuth"> + <el-input v-model="gb28181.Password" placeholder="璇疯緭鍏�" size="small"></el-input> + </el-form-item> + + <el-col :span="12"> + <el-form-item> + <el-button type="primary" @click="submitGB28281" size="small">淇濆瓨</el-button> + </el-form-item> + </el-col> + </el-form> + </el-tab-pane> + </el-tabs> + </div> +</template> + +<script> +import { + getDevInfo, + getAlarmConfig, + getGB28181Config, + saveDevInfo, + saveAlarmConfig, + saveGB28181Config, + getClockInfo, + saveClockInfo, + testNTPserver, + getResourceConfig, + saveResourceConfig, + getGb28181AreaList, + newGb28181ID +} from "@/api/system"; + +import { isPort, isIPv4 } from "@/scripts/validate"; +import ipInput from "@/components/subComponents/IPInput"; +import TimeZones from "@/Pool/TimeZones" + +import ClusterManagement from "./ClusterManagement"; +import AuthorityManagement from "./AuthorityManagement"; +import RadioSet from "./RadioSet"; + +export default { + name: "BasicSettings", + components: { + ipInput, + ClusterManagement, + AuthorityManagement, + RadioSet + }, + computed: { + timeZoneOption() { + let options = [] + TimeZones.forEach(zone => { + options = options.concat(zone.utc.map(v => { + return { value: v, label: v } + })) + }) + return options + } + }, + directives: { + focus: { + inserted: function (el) { + el.querySelector('input').focus() + } + } + }, + data() { + return { + loading: true, + loadingText: "", + gutter: 10, + activeName: "first", + timezone: "", + syncType: "1", + ntpServer: "", + equipmentTime: "", + NYPport: "", + settime: "", + timeInterval: 10, + settimeRadio: false, + clockTimer: null, + browserTimer: null, + timestamp: 0, + sysinfo: {}, + alarmConf: {}, + gb28181: {}, + originNetConfig: { + ip: "", + gw: "", + mask: "", + dns: "" + }, + rules: { + ip: [ + { + required: true, + message: "璇疯緭鍏P鍦板潃", + trigger: "change" + }, + { validator: isIPv4, trigger: "change" } + ], + ServerIp: [ + { + required: true, + message: "璇疯緭鍏P鍦板潃", + trigger: "change" + }, + { validator: isIPv4, trigger: "change" } + ], + ServerPort: [ + { + required: true, + message: "璇疯緭鍏ョ鍙�", + trigger: "change" + }, + { validator: isPort, trigger: "change" } + ], + GbServerPort: [ + { + required: true, + message: "璇疯緭鍏ョ鍙�", + trigger: "change" + }, + { validator: isPort, trigger: "change" } + ], + gateway: [ + { + required: true, + message: "璇疯緭鍏ョ綉鍏�", + trigger: "change" + }, + { validator: isIPv4, trigger: "change" } + ], + dns: [ + { + required: true, + message: "璇疯緭鍏ns鍦板潃", + trigger: "change" + }, + { validator: isIPv4, trigger: "change" } + ], + server_name: [ + { required: true, message: "璇疯緭鍏ュ悕绉�", trigger: "change" } + ], + subMask: [ + { + required: true, + message: "璇疯緭鍏ュ瓙缃戞帺鐮�", + trigger: "change" + }, + { validator: isIPv4, trigger: "change" } + ] + }, + openeds: ["0"], + ipServer: { + diyOrLocalIP: "1", + ip: "", + localhost: "", + localFilePort: "", + fileTable: [ + { + date: '2016-05-02', + name: '鐜嬪皬铏�', + address: '涓婃捣甯傛櫘闄�鍖洪噾娌欐睙璺� 1518 寮�', + edit: false + }, { + date: '2016-05-04', + name: '鐜嬪皬铏�', + address: '涓婃捣甯傛櫘闄�鍖洪噾娌欐睙璺� 1517 寮�', + edit: false + }, { + date: '2016-05-01', + name: '鐜嬪皬铏�', + address: '涓婃捣甯傛櫘闄�鍖洪噾娌欐睙璺� 1519 寮�', + edit: false + }, { + date: '2016-05-03', + name: '鐜嬪皬铏�', + address: '涓婃捣甯傛櫘闄�鍖洪噾娌欐睙璺� 1516 寮�', + edit: false + } + ] + }, + locationCity: { + province: '', + city: '', + county: '', + provinceOptions: [], + cityOptions: [], + countyOptions: [] + }, + }; + webPort: 0; + }, + mounted() { + this.$nextTick(() => { + this.initSysinfo(); + // this.initAlarmConf(); + this.initResourceConfig(); + this.initGB28181Conf(); + this.initClockConf(); + }); + }, + beforeDestroy() { + clearTimeout(this.clockTimer); + clearInterval(this.browserTimer); + }, + methods: { + initSysinfo() { + this.loadingText = "姝e湪鑾峰彇璁惧淇℃伅..."; + getDevInfo().then(rsp => { + if (rsp && rsp.success) { + this.sysinfo = rsp.data; + this.sysinfo.gateway = this.sysinfo.gateway.trim(); + this.originNetConfig.ip = this.sysinfo.ip; + this.originNetConfig.mask = this.sysinfo.subMask; + this.originNetConfig.gw = this.sysinfo.gateway.trim(); + this.originNetConfig.dns = this.sysinfo.dns ? this.sysinfo.dns : ""; + this.alarmConf.min_video_len = rsp.data.min_video_len; + this.alarmConf.max_video_len = rsp.data.max_video_len; + + if (!this.sysinfo.server_port) { + this.sysinfo.server_port = 7003; + } + + this.webPort = this.sysinfo.server_port; + } + + this.loading = false; + }).catch(err => { + this.loading = false; + }); + }, + initClockConf() { + getClockInfo().then(rsp => { + if (rsp && rsp.success) { + this.timezone = rsp.data.time_zone; + this.syncType = rsp.data.ntp ? "1" : "2"; + if (rsp.data.ntp) { + this.ntpServer = rsp.data.ntp_server; + this.timeInterval = rsp.data.interval; + } + this.timestamp = rsp.data.local_time + if (this.clockTimer === null) { + this.runClock(); + } + } + }) + }, + runClock() { + this.equipmentTime = this.formatTime(++this.timestamp, 'Y-M-D h:m:s'); + // console.log(this.equipmentTime) + this.clockTimer = setTimeout(() => { + this.runClock(); + }, 1000) + }, + initAlarmConf() { + // getAlarmConfig().then(rsp => { + // if (rsp && rsp.success) { + // this.alarmConf = rsp.data; + // } + // }); + }, + initResourceConfig() { + getResourceConfig().then(rsp => { + if (rsp && rsp.success) { + this.ipServer.diyOrLocalIP = rsp.data.ipType + this.ipServer.ip = rsp.data.serviceIp + this.ipServer.localhost = rsp.data.domain + this.ipServer.localFilePort = rsp.data.filePort + } + }) + }, + initGB28181Conf() { + getGB28181Config().then(rsp => { + if (rsp && rsp.success) { + this.gb28181 = rsp.data; + this.gb28181.idType = 0; + } + }); + getGb28181AreaList().then(rsp => { + if (rsp && rsp.success) { + this.locationCity.provinceOptions = rsp.data; + } + }) + }, + syncBrowser(enable) { + if (!enable) { + clearInterval(this.browserTimer) + } else { + this.browserTimer = setInterval(() => { + let timestamp = new Date().getTime() / 1000; + this.settime = this.formatTime(timestamp, 'Y-M-D h:m:s') + }, 1000) + } + }, + submitSysinfo() { + this.$refs["sysinfo"].validate(valid => { + if (valid) { + if (this.sysinfo.ip !== this.originNetConfig.ip + || this.sysinfo.subMask !== this.originNetConfig.mask + || this.sysinfo.dns !== this.originNetConfig.dns + || this.sysinfo.gateway !== this.originNetConfig.gw) { + + if (this.sysinfo.ip !== this.originNetConfig.ip) { + let newUri = location.protocol + "//" + this.sysinfo.ip + ":" + this.sysinfo.server_port; + var changeIPTimer = setTimeout(() => { + this.$alert('<strong>鎮ㄥ凡淇敼浜嗘湇鍔″櫒ip, 璇烽噸鏂扮櫥褰�</strong><a href="' + newUri + '"> ' + newUri + '<a/>', '鎻愮ず', { + dangerouslyUseHTMLString: true + }); + }, 10000) + } + + this.$confirm("纭闇�瑕佷慨鏀规湇鍔″櫒缃戠粶閰嶇疆鍚楋紵", { + center: true, + cancelButtonClass: "comfirm-class-cancle", + confirmButtonClass: "comfirm-class-sure" + }).then(() => { + this.loading = true; + this.loadingText = "姝e湪澶勭悊..." + saveDevInfo(this.sysinfo).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "鏈満淇℃伅淇濆瓨鎴愬姛" + }); + } + this.initSysinfo(); + this.loading = false; + }).catch(err => { + this.loading = false; + clearTimeout(changeIPTimer) + this.$notify({ + type: "error", + message: "淇濆瓨澶辫触" + }); + }); + }).catch(err => { + }); + } else { + saveDevInfo(this.sysinfo).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "鏈満淇℃伅淇濆瓨鎴愬姛" + }); + this.initSysinfo(); + } + }); + + if (this.sysinfo.server_port !== this.webPort) { + let newUri = location.protocol + "//" + this.sysinfo.ip + ":" + this.sysinfo.server_port; + var changeIPTimer = setTimeout(() => { + this.$alert('<strong>鎮ㄥ凡淇敼浜嗘湇鍔″櫒绔彛, 璇烽噸鏂扮櫥褰�</strong><a href="' + newUri + '"> ' + newUri + '<a/>', '鎻愮ず', { + dangerouslyUseHTMLString: true + }); + }, 5000) + } + } + } else { + console.log("error submit!!"); + return false; + } + }); + }, + submitClock() { + if (this.syncType === '1') { + if (this.ntpServer === "") { + this.$notify({ + type: "error", + message: "NTP 鏈嶅姟鍣ㄥ湴鍧�涓嶈兘涓虹┖" + }); + return false + } else if (this.timeInterval === "") { + this.timeInterval = 1; + } + } else { + if (this.settime === "") { + this.$notify({ + type: "error", + message: "璁剧疆鏃堕棿涓嶈兘涓虹┖" + }); + return false + } + } + let requestBody = { + timeZone: this.timezone, + ntp: this.syncType === '1', + ntpServer: this.ntpServer, + interval: this.timeInterval, + newTime: this.settime + } + saveClockInfo(requestBody).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "璁剧疆鎴愬姛" + }); + } + }) + }, + testNTP() { + testNTPserver({ server: this.ntpServer }).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "鏃堕棿鍚屾鎴愬姛" + }); + } else { + this.$notify({ + type: "error", + message: "鏃堕棿鍚屾澶辫触" + }); + } + }).catch(err => { + this.$notify({ + type: "error", + message: "鏃堕棿鍚屾澶辫触,璇锋鏌ユ湇鍔″櫒ip" + }); + }) + }, + submitAlarm() { + saveAlarmConfig(this.alarmConf).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "淇濆瓨鎴愬姛" + }); + } + }); + }, + submitResource() { + let regNum = /^[0-9]*$/; + if (!this.vaildHost(this.ipServer.localhost)) { + this.$notify({ + type: "warning", + message: "璇疯緭鍏ユ纭牸寮忓緱鍩熷悕锛�" + }) + return false; + } + if (!regNum.test(this.ipServer.localFilePort)) { + this.$notify({ + type: 'warning', + message: "璇疯緭鍏ユ纭殑绔彛鍙凤紒" + }) + return false; + } + saveResourceConfig({ + domain: this.ipServer.localhost, + ipType: this.ipServer.diyOrLocalIP, + serviceIp: this.ipServer.ip, + filePort: Number(this.ipServer.localFilePort) + }).then(res => { + if (res && res.success) { + this.$notify({ + type: "success", + message: "淇濆瓨鎴愬姛" + }); + } else { + this.$notify({ + type: "error", + message: "淇濆瓨澶辫触" + }); + } + }) + }, + submitGB28281() { + this.$refs["gb28181"].validate(valid => { + if (valid) { + saveGB28181Config(this.gb28181).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "GB28181璁剧疆淇濆瓨鎴愬姛" + }); + } + }); + } else { + console.log("error submit!!"); + return false; + } + }); + }, + onIpBlur(e, ip) { + console.log(e, ip); + }, + formatTime(number, format) { + var formateArr = ['Y', 'M', 'D', 'h', 'm', 's']; + var returnArr = []; + + var date = new Date(number * 1000); + returnArr.push(date.getFullYear()); + returnArr.push(this.formatNumber(date.getMonth() + 1)); + returnArr.push(this.formatNumber(date.getDate())); + + returnArr.push(this.formatNumber(date.getHours())); + returnArr.push(this.formatNumber(date.getMinutes())); + returnArr.push(this.formatNumber(date.getSeconds())); + + for (var i in returnArr) { + format = format.replace(formateArr[i], returnArr[i]); + } + return format; + }, + + //鏁版嵁杞寲 + formatNumber(n) { + n = n.toString() + return n[1] ? n : '0' + n + }, + menuOpen(event) { + + }, + menuClose(event) { + + }, + handleEdit(row) { + console.log(row); + row.edit = true; + }, + handleCancel(row) { + row.edit = false; + console.log(row); + }, + handleSave(row) { + console.log(row); + row.edit = false; + this.$notify({ + message: "淇濆瓨鎴愬姛", + type: "success" + }); + }, + //鏍¢獙鍩熷悕 + vaildHost(str) { + let re = /^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*$/ + return re.test(str) + }, + changeProvince() { + let pid = this.locationCity.province; + getGb28181AreaList({ parentId: pid }).then(rsp => { + if (rsp && rsp.success) { + this.locationCity.cityOptions = rsp.data; + this.locationCity.city = this.locationCity.cityOptions[0].id; + this.changeCity(); + } + }) + }, + changeCity() { + let pid = this.locationCity.city; + getGb28181AreaList({ parentId: pid }).then(rsp => { + if (rsp && rsp.success) { + this.locationCity.countyOptions = rsp.data; + this.locationCity.county = this.locationCity.countyOptions[0].id; + } + }) + }, + newGBID() { + let cCode = this.locationCity.county + ""; + newGb28181ID({ code: cCode }).then(rsp => { + if (rsp && rsp.success) { + this.gb28181.PublicId = rsp.data; + } + }) + } + } +}; +</script> +<style lang="scss"> +.s-basic-setting { + width: 100%; + height: 100%; + .el-form { + width: 1000px; + margin-top: 30px; + // margin-left: -80px; + .el-form-item { + text-align: left; + .el-button { + float: right; + } + + .el-form-item__content { + text-align: left; + input { + max-width: 360px; + } + .el-date-editor.el-input, + .el-date-editor.el-input__inner { + width: 216px; + } + .el-checkbox__label { + padding-left: 5px; + } + } + + .el-form-item__label { + text-align: left; + } + } + } + .alarmSetting { + .el-input { + width: 100%; + // padding-right: 10px; + } + .el-select { + max-width: 113px; + } + .el-slider { + width: calc(100% - 120px); + display: inline-block; + padding-right: 30px; + box-sizing: border-box; + vertical-align: middle; + } + .el-input-number { + width: 100px; + display: inline-block; + .el-input { + width: 100%; + } + } + } + + .time-type { + height: 25px; + width: 413px; + line-height: 28px; + padding: 3px 23px; + font-size: 14px; + font-weight: 600; + background-color: #e4e6ed; + } + #e-basic-setting { + .el-tabs__header { + border: 0px solid #dcdfe6; + .el-tabs__item { + padding: 5px 50px; + height: 50px; + font-family: PingFangSC-Regular; + font-size: 14px; + color: #222222; + text-align: center; + border: 0px solid transparent; + } + .el-tabs__item:nth-child(2) { + padding-left: 50px; + } + .el-tabs__item:last-child { + padding-right: 50px; + } + .el-tabs__item.is-active { + color: #ff7733; + font-weight: bold; + // border-right-color: #fff; + // border-left-color: #fff; + } + .el-tabs__item:not(.is-disabled):hover { + color: #ff7733; + } + } + .el-tabs__active-bar { + background-color: #ff7733; + } + .xiangqin-label { + text-align: left; + width: 85px; + font-size: 14px; + line-height: 30px; + } + .xiangqing-info { + text-align: left; + font-size: 14px; + line-height: 30px; + } + } + + #cut_min_duration { + .el-slider__bar { + background-color: #3d68e1; + } + .el-slider__button { + width: 10px; + height: 10px; + border: 4px solid #3d68e1; + } + } + + #cut_max_duration { + .el-slider__bar { + background-color: #ff9e6e; + } + .el-slider__button { + width: 10px; + height: 10px; + border: 4px solid #ff9e6e; + } + } + .menu-css, + .el-menu { + border-right: none; + list-style: none; + position: relative; + margin: 0; + padding-left: 0; + background-color: #ffffff; + .el-submenu__title { + height: 35px; + line-height: 35px; + font-size: 14px; + color: #303133; + padding: 0 20px; + list-style: none; + cursor: pointer; + position: relative; + -webkit-transition: border-color 0.3s, background-color 0.3s, color 0.3s; + transition: border-color 0.3s, background-color 0.3s, color 0.3s; + -webkit-box-sizing: border-box; + box-sizing: border-box; + white-space: nowrap; + } + .tree-font { + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + text-align: left; + } + li { + text-align: left; + .el-submenu__title { + // border-bottom: solid 1px #e6e6e6; + padding-left: 10px !important; + background-color: #e4e6ed !important; + border-radius: 2px; + .el-submenu__icon-arrow { + position: absolute; + top: 50%; + right: auto; + left: 135px; + margin-top: -7px; + -webkit-transition: -webkit-transform 0.3s; + transition: -webkit-transform 0.3s; + transition: transform 0.3s; + transition: transform 0.3s, -webkit-transform 0.3s; + font-size: 12px; + } + } + } + } + .save-btn { + text-align: right; + position: relative; + right: 40px; + } +} +</style> +<style lang="scss" scoped> +.menu-css, +.el-menu { + border-right: none; + list-style: none; + position: relative; + margin: 0; + padding-left: 0; + background-color: #ffffff; + + .tree-font { + font-family: PingFangSC-Medium; + font-size: 14px; + color: #222222; + text-align: left; + } + li { + text-align: left; + .el-submenu__title { + .el-submenu__icon-arrow { + position: absolute; + top: 50%; + right: 0; + margin-top: -7px; + -webkit-transition: -webkit-transform 0.3s; + transition: -webkit-transform 0.3s; + transition: transform 0.3s; + transition: transform 0.3s, -webkit-transform 0.3s; + font-size: 12px; + } + } + } +} +</style> diff --git a/src/pages/settings/components/ClusterManagement.vue b/src/pages/settings/components/ClusterManagement.vue new file mode 100644 index 0000000..d6d5d65 --- /dev/null +++ b/src/pages/settings/components/ClusterManagement.vue @@ -0,0 +1,620 @@ +<template> + <div class="s-cluster-management"> + <div class="ui-top-view"> + <div class="ui-top-title">瑙嗛鍒嗘瀽闆嗙兢绠$悊</div> + </div> + <el-row> + <el-col :span="12"> + <el-tabs v-model="activeName" id="e-alaycluster" v-if="!isHasColony"> + <el-tab-pane label="鍒涘缓闆嗙兢" name="1" :disabled="isHasColony"> + <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="80px"> + <el-form-item label="闆嗙兢鍚嶇О" prop="clustername"> + <el-input v-model="ruleForm.clustername" placeholder="鎵嬪姩杈撳叆, 濡傗�滈泦缇鈥�" size="small"></el-input> + </el-form-item> + <el-form-item label="闆嗙兢ID"> + <el-input v-model="clusterid" placeholder="涓嶅厑璁歌緭鍏�,淇濆瓨鍚庡洖鏄�" disabled size="small"></el-input> + </el-form-item> + <el-form-item label="闆嗙兢瀵嗙爜" prop="clusterpwd" style="width:440px"> + <el-input v-model="ruleForm.clusterpwd" placeholder="璇疯緭鍏�6-12浣嶅瘑鐮�,鎴栫偣鍑荤敓鎴�" size="small"> + <el-button type="text" slot="suffix" @click="generatePassword">鐢熸垚瀵嗙爜</el-button> + </el-input> + </el-form-item> + + <el-form-item label="铏氭嫙IP" prop="virtualip"> + <ip-input :ip="ruleForm.virtualip" :on-blur="onIpBlur"></ip-input> + </el-form-item> + <el-form-item style="width:440px"> + <el-button type="primary" size="small" @click="submitForm('ruleForm')">淇濆瓨</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + + <!-- 鍔犲叆宸叉湁闆嗙兢 --> + <el-tab-pane label="鍔犲叆宸叉湁闆嗙兢" name="2" :disabled="isHasColony"> + <el-form label-width="80px" :model="joinForm" :rules="joinRules" ref="joinForm"> + <el-form-item label="IP鍦板潃" style="width:440px"> + <el-input v-model="joinForm.clusterip" placeholder="璇疯緭鍏ラ泦缇ゅ唴浠绘剰IP鍦板潃" size="small"> + <el-button + type="text" + slot="suffix" + v-show="!searchDis" + @click="searchColony" + >鎼滅储闆嗙兢</el-button> + <el-button type="text" slot="suffix" v-show="searchDis" @click="stopSearch"> + <i class="el-icon-loading"></i>鍋滄鎼滅储 + </el-button> + </el-input> + + <!-- <el-button size="mini" :disabled="searchDis" @click="searchColony">鎼滅储闆嗙兢</el-button> + <el-button size="mini" @click="stopSearch">鍋滄鎼滅储</el-button>--> + </el-form-item> + <el-form-item label="闆嗙兢瀵嗙爜" prop="clusterpwd" style="width:440px"> + <el-input + v-model="joinForm.clusterpwd" + placeholder="璇疯緭鍏ラ泦缇ゅ瘑鐮�" + show-password + size="small" + ></el-input> + </el-form-item> + <el-form-item style="width:440px"> + <el-button type="primary" @click="join('joinForm')" size="small">鍔犲叆闆嗙兢</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + </el-tabs> + <!-- 鏈夐泦缇ょ殑鎯呭喌 --> + <div v-if="isHasColony" id="h-alaycluster"> + <el-form :model="ruleForm" ref="ruleForm" label-width="80px"> + <el-form-item label="闆嗙兢鍚嶇О" prop="clustername"> + <el-input v-model="ruleForm.clustername" placeholder="鎵嬪姩杈撳叆, 濡傗�滈泦缇鈥�" size="small"></el-input> + </el-form-item> + <el-form-item label="闆嗙兢ID"> + <el-input v-model="clusterid" placeholder="涓嶅厑璁歌緭鍏�,淇濆瓨鍚庡洖鏄�" disabled size="small"></el-input> + </el-form-item> + <el-form-item label="闆嗙兢瀵嗙爜" prop="clusterpwd" style="width:440px"> + <el-input + v-model="ruleForm.clusterpwd" + disabled + placeholder="璇疯緭鍏�6-12浣嶅瘑鐮�,鎴栫偣鍑荤敓鎴�" + size="small" + ></el-input> + </el-form-item> + + <el-form-item label="铏氭嫙IP" prop="virtualip"> + <ip-input :ip="ruleForm.virtualip" :on-blur="onIpBlur"></ip-input> + </el-form-item> + <el-form-item style="width:440px;text-align: right;"> + <el-button size="small" type="danger" @click="leave">閫�鍑洪泦缇�</el-button> + <el-button + style="margin-right:10px;" + type="primary" + size="small" + @click="submitForm('manageForm')" + >淇濆瓨</el-button> + </el-form-item> + </el-form> + </div> + </el-col> + <el-col :span="14" style="height: 100%;" v-if="members.length !== 0"> + <serfDiagram + ref="diagram" + :members="members" + :agent="agentName" + v-loading="loading" + @selected-node="joinNode" + ></serfDiagram> + </el-col> + </el-row> + <div class="ui-top-view"> + <div class="ui-top-title">瀛樺偍闆嗙兢绠$悊</div> + </div> + <el-row> + <el-col :span="12"> + <el-tabs id="e-dbcluster" v-model="sActiveName"> + <el-tab-pane label="鍒涘缓闆嗙兢" name="s-first"> + <el-button type="primary" style="float: none;margin: 20px 0px;" size="small">鍒涘缓瀛樺偍闆嗙兢</el-button> + <p>鐐瑰嚮灏嗘湰鏈哄垱寤轰负瀛樺偍闆嗙兢</p> + </el-tab-pane> + <el-tab-pane label="鍔犲叆宸叉湁闆嗙兢" name="s-second"> + <el-form label-width="80px"> + <el-form-item label="IP鍦板潃" style="text-align: left;"> + <el-input v-model="clusterip2" placeholder="璇疯緭鍏ラ泦缇ゅ唴浠绘剰IP鍦板潃" size="small"> + <el-button + type="text" + slot="suffix" + v-show="!searchDis" + @click="searchColony" + >鎼滅储闆嗙兢</el-button> + </el-input> + </el-form-item> + <el-form-item> + <el-button type="primary" @click="join('joinForm')" size="small">鍔犲叆闆嗙兢</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + <el-tab-pane label="绠$悊闆嗙兢" name="s-third"> + <h3 style="text-align: left;margin: 10px 0px;"> + <b>闆嗙兢鍚嶇О</b> + <span>xxx</span> + </h3> + <el-table :data="tableData" style="width: 100%"> + <el-table-column prop="nodeType" label="鑺傜偣绫诲瀷"></el-table-column> + <el-table-column prop="nodeName" label="鑺傜偣鍚嶇О"></el-table-column> + <el-table-column prop="nodeIp" label="鑺傜偣IP鍦板潃"></el-table-column> + <el-table-column prop="registerTime" label="娉ㄥ唽鏃堕棿"></el-table-column> + </el-table> + </el-tab-pane> + </el-tabs> + </el-col> + </el-row> + </div> +</template> + +<script> +import { + createColony, + randomPwd, + search, + getSearchNodes, + stopSearching, + findCluster, + updateClusterName, + joinCluster, + leave +} from "@/api/clusterManage"; +import serfDiagram from "@/components/serfDiagram"; +import ipInput from "@/components/subComponents/IPInput"; + +export default { + components: { + serfDiagram, + ipInput + }, + data() { + const checkPwd = (rule, value, callback) => { + if (!value) { + return callback(new Error("瀵嗙爜涓嶈兘涓虹┖")); + } + setTimeout(() => { + if (value.length > 16 || value.length < 6) { + callback(new Error("瀵嗙爜搴斾负6-16浣�!")); + } else { + callback(); + } + }, 1000); + }; + return { + activeName: "1", + sActiveName: "s-first", + clusterid: "", + clusterip2: "", + clusterpwd2: "", + sClusterip: "", + ruleForm: { + clustername: "", + clusterpwd: "", + virtualip: "" + }, + manageForm: { + clustername: "娴嬭瘯闆嗙兢1", + clusterpwd: "123456", + virtualip: "192.168.1.188" + }, + joinForm: { + clusterip: "", + clusterpwd: "" + }, + rules: { + clustername: [ + { required: true, message: "璇疯緭鍏ラ泦缇ゅ悕绉�", trigger: "change" } + ], + clusterpwd: [{ validator: checkPwd, trigger: "change" }], + virtualip: [ + { required: true, message: "璇疯緭鍏ヨ櫄鎷烮P", trigger: "change" } + ] + }, + joinRules: { + clusterpwd: [ + { required: true, message: "璇疯緭鍏ラ泦缇ゅ瘑鐮�", trigger: "change" }, + { validator: checkPwd, trigger: "change" } + ] + }, + tableData: [ + { + nodeType: "涓昏妭鐐�", + nodeName: "xxxx", + nodeIp: "192.168.12.102", + registerTime: "2016-04-04" + }, + { + nodeType: "涓昏妭鐐�", + nodeName: "xxxx", + nodeIp: "192.168.14.122", + registerTime: "2016-05-04" + }, + { + nodeType: "涓昏妭鐐�", + nodeName: "xxxx", + nodeIp: "192.168.10.132", + registerTime: "2016-02-12" + } + ], + scheduleId: "", + isHasColony: false, + currentCluster: {}, + searchNum: "", + loading: false, + searchDis: false, + agentName: "", + members: [] + }; + }, + watch: {}, + methods: { + cleanValue() { + this.members = []; + }, + sHandleClick(tab, event) { + console.log(tab, event); + }, + submitForm(formName) { + this.$refs[formName].validate(valid => { + if (valid) { + alert("submit!"); + let json = { + clusterId: this.clusterid, + clusterName: this.ruleForm.clustername, + password: this.ruleForm.clusterpwd, + virtualip: this.ruleForm.virtualip + }; + this.createColony(json).then(() => { + this.findCluster(); + }); + } else { + console.log("error submit!!"); + return false; + } + }); + }, + join(formName) { + this.$refs[formName].validate(valid => { + if (valid) { + if (Object.keys(this.currentCluster).length === 0) { + this.$notify({ + type: "info", + duration: 1000, + message: "璇峰厛閫夋嫨涓�涓泦缇よ妭鐐�" + }); + return true; + } + let nodeIps = this.members.map(i => { + return i.Address; + }); + let json = { + clusterId: this.currentCluster.cluster_id, + password: this.joinForm.clusterpwd, + nodeIps: nodeIps + }; + this.joinCluster(json).then(() => { + this.findCluster(); + }); + } else { + console.log("error submit!!"); + return false; + } + }); + }, + async createColony(json) { + let res = await createColony(json); + console.log(res, "鍒涘缓闆嗙兢"); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + }, + async randomPwd() { + let res = await randomPwd(); + if (res && res.success) { + this.ruleForm.clusterpwd = res.data; + } + }, + async searchColony() { + this.$refs["joinForm"].validate(valid => { + if (valid) { + let json = { + password: this.joinForm.clusterpwd, + ip: this.joinForm.clusterip + }; + + this.search(json) + .then(() => { + this.setSchedule(); + // this.searchDis = false; + // this.loading = false; + }) + .catch(() => { + this.searchDis = false; + this.loading = false; + }); + } else { + this.searchDis = false; + this.loading = false; + return false; + } + }); + }, + async search(json) { + let res = await search(json); + if (res && res.success) { + console.log(res, "鎼滅储闆嗙兢"); + this.searchNum = res.data; + } + this.searchDis = true; + this.loading = true; + window.setTimeout(() => { + this.stopSearch(); + }, 10 * 1000); + }, + async getSearchNodes() { + let res = await getSearchNodes(); + if (res && res.success) { + let list = res.data.map(i => { + let obj = {}; + obj.cluster_id = i.clusterID ? i.clusterID : ""; + obj.create_time = i.create_time ? i.create_time : ""; + obj.id = i.nodeID ? i.nodeID : ""; + obj.node_id = i.nodeID ? i.nodeID : ""; + obj.Address = i.nodeAddress ? i.nodeAddress : ""; + obj.nodeName = i.nodeAddress ? i.nodeAddress : ""; + obj.role = i.role ? i.role : "pc"; + return obj; + }); + list.map(i => { + let found = this.members.find(element => { + return element.node_id === i.node_id; + }); + if (found === undefined) { + this.members.push(i); + } + }); + } + }, + setSchedule() { + this.scheduleId = window.setInterval(() => { + this.getSearchNodes(); + }, 1000); + }, + async stopSearch() { + if (!this.loading) { + return true; + } + stopSearching({ + searchNum: this.searchNum + }).then((res) => { + console.log(res, '姝e父缁撴潫') + this.loading = false; + this.searchDis = false; + window.clearInterval(this.scheduleId); + }).catch((err) => { + console.log(err, '鎶ラ敊缁撴潫') + this.$notify({ + type: 'error', + duration: 1000, + message: '鍋滄鎼滅储鎶ラ敊锛�' + }) + // window.setTimeout(()=>{ + // this.loading = false; + // this.searchDis = false; + // window.clearInterval(this.scheduleId); + // },2000) + }) + }, + async findCluster() { + let res = await findCluster(); + if (res && res.success) { + if (res.data && res.data.clusterId) { + this.isHasColony = true; + this.activeName = "3"; + this.clusterid = res.data.clusterId; + this.ruleForm.clustername = res.data.clusterName; + this.ruleForm.clusterpwd = res.data.clusterpwd + this.ruleForm.virtualip = res.data.virtualip + let list = res.data.nodes.map(i => { + let obj = {}; + obj.cluster_id = i.cluster_id; + obj.clusterName = res.data.clusterName; + obj.create_time = i.create_time; + obj.id = i.id; + obj.node_id = i.node_id; + obj.node_ip = i.node_ip; + obj.nodeName = i.node_name; + obj.Address = i.node_ip; + obj.role = i.role ? i.role : "pc"; + return obj; + }); + this.members = this.members.concat(list); + } else { + this.isHasColony = false; + // this.activeName = '1' + } + } + }, + async updateClusterName() { + let res = await updateClusterName({ + clusterName: this.mangeForm.colonyName + }); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + }, + async joinCluster(json) { + let res = await joinCluster(json); + if (res.success) { + this.members = [] + } + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + }, + leave() { + this.$confirm(`纭畾閫�鍑洪泦缇ゅ悧?`, { + center: true, + cancelButtonClass: "comfirm-class-cancle", + confirmButtonClass: "comfirm-class-sure" + }).then(async () => { + let res = await leave(); + this.$notify({ + title: res.success ? "鎴愬姛" : "澶辫触", + message: res.msg, + type: res.success ? "success" : "error" + }); + if (res && res.success) { + this.ruleForm.clustername = ""; + this.ruleForm.clusterpwd = "" + this.clusterid = ""; + this.isHasColony = false; + this.activeName = "1" + } + }).catch(() => { }); + + }, + joinNode(event, node) { + this.currentCluster.cluster_id = node.cluster_id; + if (this.activeName === "3") { + this.manageForm.clustername = node.clusterName; + this.clusterid = node.cluster_id; + return; + } + if (this.activeName === "2") { + this.$refs["joinForm"].validate(valid => { + if (valid) { + this.$confirm("鏄惁瑕佸姞鍏ヨ妭鐐� " + node.nodeName + "?", "鍔犲叆闆嗙兢", { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "success" + }) + .then(() => { + // this.agentName = 'node' + this.members.length + // this.members.push({ + // nodeName: this.agentName, + // Address: '172.10.10.26', + // role: 'pc' + // }) + // this.$notify({ + // type: 'success', + // duration: 1000, + // message: '鍔犲叆鎴愬姛!' + // }) + console.log(this.currentCluster, '閫夋嫨鐨勯泦缇よ妭鐐�') + this.join("joinForm"); + }) + .catch(() => { + this.$notify({ + type: "info", + duration: 1000, + message: "宸插彇娑�" + }); + }); + } else { + console.log("error submit!!"); + return false; + } + }); + } + }, + generatePassword() { + var chars = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + var uuid = []; + + for (let i = 0; i < 16; i++) { + uuid[i] = chars[0 | (Math.random() * 50)]; + } + + this.ruleForm.clusterpwd = uuid.join(""); + }, + onIpBlur(ip) { + this.ruleForm.virtualip = ip; + } + }, + mounted() { + this.findCluster(); + }, + created() { } +}; +</script> +<style lang="scss"> +.s-cluster-management { + width: 100%; + height: 100%; + overflow: auto; + + .el-button { + float: right; + } + .el-form-item__content { + text-align: left; + input { + max-width: 360px; + } + } + + #e-alaycluster, + #e-dbcluster { + .el-tabs__header { + border: 0px solid #dcdfe6; + .el-tabs__item { + padding: 5px 50px; + height: 50px; + font-family: PingFangSC-Regular; + font-size: 14px; + color: #222222; + text-align: center; + border: 0px solid transparent; + } + .el-tabs__item:nth-child(2) { + padding-left: 50px; + } + .el-tabs__item:last-child { + padding-right: 50px; + } + .el-tabs__item.is-active { + color: #ff7733; + font-weight: bold; + // border-right-color: #fff; + // border-left-color: #fff; + } + .el-tabs__item:not(.is-disabled):hover { + color: #ff7733; + } + } + .el-tabs__active-bar { + background-color: #ff7733; + } + .el-form-item__content { + text-align: left; + input { + max-width: 420px; + } + } + } + + #h-alaycluster { + .el-form-item__content { + text-align: left; + input { + max-width: 360px; + } + } + } +} +.ui-top-view { + height: 30px; + line-height: 30px; +} +</style> diff --git a/src/pages/settings/components/LogManagement.vue b/src/pages/settings/components/LogManagement.vue new file mode 100644 index 0000000..2b2d37e --- /dev/null +++ b/src/pages/settings/components/LogManagement.vue @@ -0,0 +1,190 @@ +<template> + <div class="s-log-management"> + <div class="top"> + <b>鏃ュ織绫诲瀷:</b> + <el-select v-model="logValue" placeholder="璇烽�夋嫨" size="small"> + <el-option + v-for="item in logOptions" + :key="item.value" + :label="item.label" + :value="item.value" + ></el-option> + </el-select> + <b>鏃堕棿:</b> + <el-date-picker + v-model="timeValue" + type="datetimerange" + size="small" + range-separator="鑷�" + start-placeholder="寮�濮嬫棩鏈�" + end-placeholder="缁撴潫鏃ユ湡" + ></el-date-picker> + <el-input + v-model="searchValue" + placeholder="璇疯緭鍏ュ唴瀹�" + clearable + style="width: 150px;margin: 0px 10px;" + size="small" + ></el-input> + <el-button type="primary" size="small">鎼滅储</el-button> + <el-button type="danger" size="small" @click="delSelected">鎵归噺鍒犻櫎</el-button> + <el-button type="text" size="small" style="font-size: 13px;font-weight: 600;">瀵煎嚭</el-button> + </div> + <div class="foot-table s-table"> + <el-table + ref="multipleTable" + highlight-current-row + :data="tableData" + style="width: 100%" + :header-cell-style="{background:'#f8f8f8',color:'#222222'}" + @selection-change="handleSelectionChange" + > + <el-table-column type="selection" width="55"></el-table-column> + <el-table-column :align="'center'" sortable prop="index" label="搴忓彿"></el-table-column> + <el-table-column :align="'center'" sortable prop="logtype" label="鏃ュ織绫诲瀷"></el-table-column> + <el-table-column :align="'center'" sortable prop="username" label="鐢ㄦ埛鍚�"></el-table-column> + <el-table-column :align="'center'" sortable prop="ipaddress" label="IP鍦板潃"></el-table-column> + <el-table-column :align="'center'" sortable prop="operation" label="鎿嶄綔鍔熻兘"></el-table-column> + <el-table-column :align="'center'" sortable prop="operatetime" label="鎿嶄綔鏃堕棿"></el-table-column> + <el-table-column :align="'center'" sortable prop="operateinfo" label="鎿嶄綔淇℃伅"></el-table-column> + <el-table-column label="鎿嶄綔" :align="'center'"> + <template slot-scope="scope"> + <el-button + type="text" + style="color: red;font-size:16px" + @click="handleDelete(scope.$index, scope.row)" + icon="el-icon-delete" + ></el-button> + </template> + </el-table-column> + </el-table> + </div> + </div> +</template> + +<script> +export default { + data() { + return { + tableData: [ + { + index: "1", + logtype: "寮傚父", + username: "admin", + ipaddress: "192.168.10.110", + operation: "娣诲姞鎽勫儚鏈�", + operatetime: "2019-5-31 16:38:21", + operateinfo: "娣诲姞鎿嶄綔" + }, + { + index: "2", + logtype: "淇℃伅", + username: "admin", + ipaddress: "192.168.10.108", + operation: "鍒犻櫎鎽勫儚鏈�", + operatetime: "2019-5-31 16:38:21", + operateinfo: "娣诲姞鎿嶄綔" + }, + { + index: "3", + logtype: "鎿嶄綔", + username: "admin", + ipaddress: "192.168.10.110", + operation: "娣诲姞鎽勫儚鏈�", + operatetime: "2019-5-31 16:38:21", + operateinfo: "娣诲姞鎿嶄綔" + }, + { + index: "4", + logtype: "寮傚父", + username: "admin", + ipaddress: "192.168.10.110", + operation: "娣诲姞鎽勫儚鏈�", + operatetime: "2019-5-31 16:38:21", + operateinfo: "娣诲姞鎿嶄綔" + }, + { + index: "5", + logtype: "寮傚父", + username: "admin", + ipaddress: "192.168.10.110", + operation: "鍒犻櫎鎽勫儚鏈�", + operatetime: "2019-5-31 16:38:21", + operateinfo: "娣诲姞鎿嶄綔" + }, + { + index: "6", + logtype: "寮傚父", + username: "admin", + ipaddress: "192.168.10.110", + operation: "娣诲姞鎽勫儚鏈�", + operatetime: "2019-5-31 16:38:21", + operateinfo: "娣诲姞鎿嶄綔" + } + ], + multipleSelection: [], + logOptions: [ + { + value: "鍏ㄩ儴绫诲瀷", + label: "鍏ㄩ儴绫诲瀷" + }, + { + value: "鍏朵粬绫诲瀷", + label: "鍏朵粬绫诲瀷" + } + ], + logValue: "鍏ㄩ儴绫诲瀷", + timeValue: [ + new Date(2000, 10, 10, 10, 10), + new Date(2000, 10, 11, 10, 10) + ], + searchValue: "" + }; + }, + methods: { + handleDelete(index, row) { + console.log(index, row); + }, + handleSelectionChange(val) { + this.multipleSelection = val; + }, + delSelected() { + console.log(this.multipleSelection); + } + } +}; +</script> +<style lang="scss"> +.s-log-management { + height: 100%; + width: 100%; + .top { + width: 100%; + margin-top: 10px; + margin-bottom: 20px; + overflow-y: auto; + min-width: 1156px; + height: 40px; + text-align: left; + b { + padding: 0px 10px; + } + } + .export { + display: inline-block; + padding-right: 10px; + box-sizing: border-box; + margin-top: 20px; + b:hover { + color: #2249b4; + } + } + .clear-searching { + cursor: pointer; + text-decoration: underline; + width: 40px; + font-size: 13px; + color: #3d68e1; + } +} +</style> diff --git a/src/pages/settings/components/RadioSet.vue b/src/pages/settings/components/RadioSet.vue new file mode 100644 index 0000000..89cac81 --- /dev/null +++ b/src/pages/settings/components/RadioSet.vue @@ -0,0 +1,189 @@ +<template> + <div class="s-radio-set"> + <div class="add-btn"> + <el-button size="mini" type="primary" @click="handleAdd()">娣诲姞</el-button> + </div> + <el-table + border + highlight-current-row + :data="tableData" + style="width: 100%; margin-top:40px; color:#000" + :header-cell-style="{background:'#f8f8f8',color:'#222222'}" + > + <el-table-column align="center" type="index" label="搴忓彿" width="100px"></el-table-column> + + <el-table-column :align="'center'" label="骞挎挱鍚嶇О"> + <template slot-scope="{row}"> + <el-input v-if="row.edit" :autofocus="row.edit" v-model="row.radiosName" size="small" /> + <span v-else>{{ row.radiosName }}</span> + </template> + </el-table-column> + + <el-table-column :align="'center'" label="IP鍦板潃"> + <template slot-scope="{row}"> + <el-input v-if="row.edit" v-model="row.ipAddress" size="small" /> + <span v-else>{{ row.ipAddress }}</span> + </template> + </el-table-column> + + <el-table-column :align="'center'" label="杩炴帴娴嬭瘯"> + <template slot-scope="{row}"> + <i v-show="row.isCon" class="el-icon-success" style="color:green; font-size:18px"></i> + + <el-button type="text" @click="handleTest(row)">杩炴帴娴嬭瘯</el-button> + </template> + </el-table-column> + + <el-table-column label="鎿嶄綔" :align="'center'"> + <template slot-scope="scope"> + <template v-if="scope.row.edit"> + <el-button size="mini" type="info" @click="handleCancel(scope.row)">鍙栨秷</el-button> + <el-button size="mini" type="primary" @click="handleSave(scope.row)">淇濆瓨</el-button> + </template> + <template v-else> + <el-button + type="text" + style="color: black;font-size:16px" + @click="handleEdit(scope.row)" + icon="el-icon-edit" + ></el-button> + <el-button + type="text" + style="color: red;font-size:16px" + @click="handleDelete(scope.$index)" + icon="el-icon-delete" + ></el-button> + </template> + </template> + </el-table-column> + </el-table> + </div> +</template> + +<script> +export default { + filters: { + isCon(r) { + return r.isCon ? r.isCon : false + } + }, + data() { + return { + radioName: "", + ipAddress: "", + tableData: [ + { + index: "1", + radiosName: "鎿嶅満", + ipAddress: "192.168.1.101", + edit: false, + isCon: false + }, + { + edit: false, + index: "2", + radiosName: "鏁欏", + ipAddress: "192.168.12.61", + isCon: false + }, + { + edit: false, + index: "3", + radiosName: "淇濆畨瀹�", + ipAddress: "192.168.13.121", + isCon: false + } + ] + }; + }, + mounted() { + this.testAll() + }, + methods: { + testAll() { + this.tableData.forEach(l => { + this.$set(l, "isCon", false) + }) + }, + handleEdit(row) { + console.log(row); + row.edit = true; + }, + handleCancel(row) { + row.edit = false; + console.log(row); + }, + handleDelete(index) { + this.$confirm("纭鍒犻櫎璇ュ箍鎾悧?", { + center: true, + cancelButtonClass: "comfirm-class-cancle", + confirmButtonClass: "comfirm-class-sure" + }) + .then(() => { + this.tableData.splice(index, 1) + this.$notify({ + type: "success", + message: "鍒犻櫎鎴愬姛!" + }); + }) + .catch(() => { }); + }, + handleSave(row) { + console.log(row); + row.edit = false; + this.$notify({ + message: "淇濆瓨鎴愬姛", + type: "success" + }); + }, + handleTest(row) { + this.$set(row, 'isCon', true) + }, + handleAdd() { + this.tableData.push({ + radiosName: "", + ipAddress: "", + edit: true, + isCon: false + }) + } + } +}; +</script> +<style lang="scss"> +.s-radio-set { + width: 100%; + height: 100%; + .el-dialog { + border-radius: 8px; + border: 1px solid #ccc; + .el-dialog__header { + border-bottom: 1px solid #ccc; + } + } + + .add-btn { + float: right; + margin-bottom: 7px; + } +} +.e-message { + width: 331px; +} +.e-confirm { + border-color: #ff0000 !important; + background-color: #ff0000 !important; +} +.e-confirm:hover { + border-color: #f83131d6 !important; + background-color: #f83131d6 !important; +} +.e-cancel { + border-color: #eaeaea !important; + background-color: #eaeaea !important; +} +.e-cancel:hover { + border-color: #e9e9e9 !important; + background-color: #e9e9e9 !important; +} +</style> diff --git a/src/pages/settings/components/SystemMaintenance.vue b/src/pages/settings/components/SystemMaintenance.vue new file mode 100644 index 0000000..bf40d81 --- /dev/null +++ b/src/pages/settings/components/SystemMaintenance.vue @@ -0,0 +1,514 @@ +<template> + <el-tabs + id="systemMaintenance" + v-model="activeName" + v-loading="loading" + :element-loading-text="loadingText" + > + <el-tab-pane label="璁惧缁存姢" name="first" v-if="isShow('videoSystem:sysManage:sysfix')"> + <div class="s-system-maintenance"> + <div class="box-card"> + <div class="ui-top-view"> + <div class="ui-top-title">閲嶅惎</div> + </div> + <el-divider></el-divider> + + <div class="box-card-content"> + <el-row> + <el-col :span="1"> + <el-button type="primary" size="small" style="width:80px" @click="reboot">閲嶅惎</el-button> + </el-col> + <el-col :span="23"> + <b class="card-text">閲嶅惎鑺傜偣</b> + </el-col> + </el-row> + <el-row style="margin-top:20px"> + <el-col> + <vue-cron :expression="rebootCron" @update="setRebootCron" /> + </el-col> + </el-row> + </div> + </div> + <!-- + <div class="box-card"> + <div class="ui-top-view"> + <div class="ui-top-title">鎭㈠榛樿鍊�</div> + </div> + <el-divider></el-divider> + + <div class="box-card-content"> + <el-row> + <el-col :span="1"> + <el-button type="primary" size="small">绠�鍗曟仮澶�</el-button> + </el-col> + <el-col :span="23"> + <b class="card-text">绠�鍗曟仮澶嶈澶囧弬鏁�</b> + </el-col> + </el-row> + <el-row style="margin-top:20px"> + <el-col :span="1"> + <el-button type="primary" size="small">瀹屽叏鎭㈠</el-button> + </el-col> + <el-col :span="23"> + <b class="card-text">瀹屽叏鎭㈠璁惧鍙傛暟鍒板嚭鍘傝缃�</b> + </el-col> + </el-row> + </div> + </div> + + <div class="box-card"> + <div class="ui-top-view"> + <div class="ui-top-title">鍙傛暟瀵煎叆瀵煎嚭</div> + </div> + <el-divider></el-divider> + + <div class="box-card-content"> + <el-row :gutter="4"> + <el-col :span="1"> + <el-button type="info" size="small" style="width:80px">瀵煎叆</el-button> + </el-col> + <el-col :span="3" style="padding-left:30px"> + <el-input placeholder="涓婁紶鍙傛暟鏂囦欢" size="small" :readonly="true"> + <el-upload slot="suffix" action="https://jsonplaceholder.typicode.com/posts/"> + <el-button + type="text" + icon="el-icon-upload2" + size="small" + style="font-size:18px; color:#0088ff" + ></el-button> + </el-upload> + </el-input> + </el-col> + </el-row> + <el-row style="margin-top:20px"> + <el-col :span="1"> + <el-button type="primary" size="small">璁惧鍙傛暟</el-button> + </el-col> + <el-col :span="23"> + <b class="card-text">鍙傛暟瀵煎嚭</b> + </el-col> + </el-row> + </div> + </div> + --> + <div class="box-card"> + <div class="ui-top-view"> + <div class="ui-top-title">鍗囩骇</div> + </div> + </div> + <el-divider></el-divider> + <div class="box-card-content"> + <el-row :gutter="4"> + <el-col :span="6"> + <file-uploader + single + uploadPlaceholder="涓婁紶鍗囩骇鏂囦欢" + url="/data/api-v/sysset/patchUpdate" + @complete="onFileUpload" + @file-added="onFileAdded" + /> + </el-col> + <el-col :span="2"> + <el-button + type="primary" + size="small" + style="width:80px" + @click="upgrade" + :disabled="!fileAdded" + :loading="upgrading" + >鍗囩骇</el-button> + </el-col> + <el-col :span="16" class="upload-msg"> + <span v-html="patchUpdateStatus"></span> + </el-col> + </el-row> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="鏁版嵁搴撶淮鎶�" name="second" v-if="isShow('videoSystem:sysManage:dbfix')"> + <div class="box"> + <p class="title"> + <label>鏁版嵁娓呯悊</label> + </p> + <div class="range"> + <div class="left"> + <p>閫夋嫨鏁版嵁鑼冨洿锛�</p> + </div> + <div class="middle"> + <el-date-picker + v-model="dataRange" + type="daterange" + range-separator="鑷�" + start-placeholder="寮�濮嬫棩鏈�" + end-placeholder="缁撴潫鏃ユ湡" + style="height:38px" + :picker-options="pickerOptions" + ></el-date-picker> + </div> + <div class="right"> + <el-button @click="deleteData" style="height:38px;background:#ff0000;color:white">鍒犻櫎鏁版嵁</el-button> + </div> + </div> + <div class="tip"> + <i class="iconfont icontishi-zhuyi"></i> + <p class="zhuyi">璇锋敞鎰忥紝鎸変互涓婃棩鏈熻寖鍥村垹闄ょ殑鏁版嵁涓嶅彲鎭㈠锛岀珛鍗崇敓鏁堬紝璇疯皑鎱庢搷浣�</p> + </div> + </div> + </el-tab-pane> + </el-tabs> + +</template> + +<script> +import { rebootServer, getDevInfo, getRebootTask, setRebootTask, fileUpload, doUpgrade,deleteDate } from "@/api/system" +import VueCron from "@/components/subComponents/VueCron" +import FileUploader from "@/components/subComponents/FileUpload/index" + +export default { + components: { + VueCron, + FileUploader + }, + data() { + return { + timer: null, + buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [], + rebootCron: "", + activeName: "first", + restartValue: "涓嶉噸鍚�", + restartTimeValue: new Date(2019, 9, 10, 18, 40), + loading: false, + loadingText: '', + probeSum: 0, + patchUpdateStatus: "", + dataRange: [ + this.$moment().format("YYYY-MM-DD HH:mm:ss"), + this.$moment().format("YYYY-MM-DD HH:mm:ss") + ], + fileUploadUrl: fileUpload, + patchFile: {}, + pickerOptions: { + disabledDate(time) { + var day = new Date() + day.setTime(day.getTime() - 24 * 60 * 60 * 1000) + return time.getTime() > day; + }, + }, + upgrading: false, + fileAdded: false + }; + }, + mounted() { + this.getRebootCron() + if (!this.isShow('videoSystem:sysManage:sysfix')) { + console.log("榛樿鏄剧ず鏁版嵁搴撶淮鎶�") + this.activeName = "second" + } + }, + computed: { + isAdmin() { + if ( + sessionStorage.getItem('userInfo') && + sessionStorage.getItem('userInfo') !== '' + ) { + let loginName = JSON.parse(sessionStorage.getItem('userInfo')).username + return ( + loginName === 'superadmin' || loginName === 'basic' + ) + } + return false; + } + }, + methods: { + isShow (authority) { + if (this.isAdmin) { + return true + } else if ( + this.buttonAuthority.indexOf(',' + authority + ',') > -1 + ) { + return true + } else { + return false + } + }, + format(array) { + return [ + this.$moment(array[0]).format("YYYY-MM-DD"), + this.$moment(array[1]).format("YYYY-MM-DD") + ]; + }, + getRebootCron() { + getRebootTask().then(rsp => { + this.rebootCron = rsp.data + }) + }, + setRebootCron(value) { + this.rebootCron = value + setRebootTask({ task: value }).then(rsp => { + if (rsp && rsp.success) { + this.$notify({ + type: "success", + message: "閰嶇疆鎴愬姛" + }) + } + }).catch(err => { + this.$notify({ + type: "error", + message: "閰嶇疆澶辫触" + }) + }) + }, + reboot() { + this.$confirm('纭畾瑕侀噸鍚鑺傜偣鍚�?', { + center: true, + cancelButtonClass: 'comfirm-class-cancle', + confirmButtonClass: 'comfirm-class-sure' + }).then(() => { + this.loading = true; + this.loadingText = "鏅鸿兘璁$畻鑺傜偣姝e湪閲嶅惎锛岃鑰愬績绛夊緟..." + rebootServer().then(rsp => { + this.probeServer(this.reLogin) + }).catch(err => { + if (err.status == 400) { + this.loading = false; + this.$notify({ + type: "error", + message: "閲嶅惎璁$畻鑺傜偣澶辫触" + }) + } else { + this.probeServer(this.reLogin) + } + }) + }) + }, + deleteData() { + var timeRange = this.format(this.dataRange); + var showStartTime = timeRange[0] + var showEndTime = timeRange[1] + console.log("鏃堕棿锛�",showStartTime,showEndTime) + this.$confirm("鎻愮ず锛�"+showStartTime+" 鑷� "+showEndTime+" 浜х敓鐨勫叏閮ㄦ暟鎹皢琚垹闄わ紝姝ゆ搷浣滅珛鍗崇敓鏁堬紝涓嶅彲鎭㈠锛屾槸鍚﹀垹闄わ紵", { + center: true, + cancelButtonClass: "comfirm-class-cancle", + confirmButtonClass: "comfirm-class-sure" + }).then(() => { + this.loading = true + this.loadingText = "姝e湪鍒犻櫎鏁版嵁锛岃绋嶅�欙紒" + var param = { + startTime: showStartTime, + endTime: showEndTime + } + deleteDate(param).then(resp => { + if (resp.success) { + this.$message({ + type: "success", + message: "鍒犻櫎鏁版嵁鎴愬姛" + }) + this.loading = false + } + }).catch(err => { + this.$message({ + type: "error", + message: "鍒犻櫎鏁版嵁澶辫触锛�" + }) + this.loading = false + }) + + }).catch(() => { + console.log("鍙栨秷浜嗭紒") + }) + }, + reLogin() { + this.$router.push("/") + }, + probeServer(callback) { + this.probeSum++; + let _this = this + if (this.probeSum > 60) { + this.$confirm('杩炴帴鏈嶅姟鍣ㄥけ璐�, 璇峰埛鏂伴〉闈㈡垨鑱旂郴绠$悊鍛�', '澶辫触', { + type: 'error', + cancelButtonClass: 'comfirm-class-cancle', + confirmButtonClass: 'comfirm-class-sure' + }).then(() => { + // _this.$router.push("/") + callback() + }) + return + } + + this.timer = setTimeout(() => { + getDevInfo().then(() => { + // _this.$router.push("/") + callback() + }).catch(err => { + _this.probeServer(callback) + }) + }, 10000) + }, + onFileUpload(file) { + this.patchUpdateStatus = `<span style="color:green">涓婁紶鎴愬姛, 鐐瑰嚮鍗囩骇鎸夐挳寮�濮嬪崌绾�</span>` + this.patchFile = { ...file } + this.fileAdded = true + }, + onFileAdded() { + this.patchUpdateStatus = "" + }, + upgrade() { + this.upgrading = true + this.patchUpdateStatus = `<span style="color:red">姝e湪鍗囩骇...</span>` + doUpgrade(this.patchFile).then(rsp => { + this.upgrading = false + + if (rsp && rsp.success) { + clearTimeout(this.timer) + this.doneUpgrade() + } + }).catch(err => { + if (err.code) { + this.upgrading = false + this.patchUpdateStatus = `<span style="color:red">${err.data}</span>` + clearTimeout(this.timer) + } else { + this.probeServer(this.doneUpgrade) + } + }) + }, + doneUpgrade() { + this.upgrading = false + this.patchUpdateStatus = `<span style="color:green">鍗囩骇鎴愬姛</span>` + let _this = this + this.$confirm('鍗囩骇鎴愬姛, 璇烽噸鏂扮櫥褰曠郴缁�', '鎴愬姛', { + type: 'success', + cancelButtonClass: 'comfirm-class-cancle', + confirmButtonClass: 'comfirm-class-sure' + }).then(() => { + _this.reLogin() + }) + } + } +}; +</script> +<style lang="scss"> +.s-system-maintenance { + width: 100%; + height: 100%; + .box-card { + text-align: left; + height: auto; + margin: 10px 0px; + .box-card-content { + padding-bottom: 40px; + .card-text { + padding: 0 30px; + line-height: 32px; + } + } + } + + .upload-icon { + font-size: 18px; + color: #0088ff; + } + .upload-msg { + padding-left: 10px; + text-align: left; + span { + line-height: 32px; + font-size: 13px; + } + } +} +.box{ + width: 50%; + min-width: 700px; + height: 270px; + border: 1px solid #eee; + .title { + font-size:20px; + font-weight: bold; + text-align: left; + padding: 20px; + border-bottom: 1px solid #eee; + } + .range { + width: 100%; + padding-top: 30px; + height: 38px; + .left { + width: 120px; + float: left; + text-align: right; + font-size: 14px; + p { + height: 38px; + line-height: 38px; + } + } + .middle { + width: 50%; + min-width: 400px; + height: 38px; + float: left; + } + .right { + width: 20%; + height: 38px; + float: left; + } + } + .tip { + width: 100%; + padding: 30px 0px 0px 30px; + height: 34px; + + .zhuyi { + font-size: 14px; + height: 34px; + line-height: 34px; + margin-left: 20px; + float: left; + } + i { + font-size: 32px; + color: #e99038; + float: left; + } + } +} +#systemMaintenance{ + + .el-tabs__header { + border: 0px solid #dcdfe6; + .el-tabs__item { + padding: 5px 50px; + height: 50px; + font-family: PingFangSC-Regular; + font-size: 14px; + color: #222222; + text-align: center; + border: 0px solid transparent; + } + .el-tabs__item:nth-child(2) { + padding-left: 50px; + } + .el-tabs__item:last-child { + padding-right: 50px; + } + .el-tabs__item.is-active { + color: #ff7733; + font-weight: bold; + // border-right-color: #fff; + // border-left-color: #fff; + } + .el-tabs__item:not(.is-disabled):hover { + color: #ff7733; + } + + } + .el-tabs__active-bar { + background-color: #ff7733; + } + .el-tabs__content { + padding-left: 15px !important; + } +} +</style> diff --git a/src/pages/settings/index/App.vue b/src/pages/settings/index/App.vue new file mode 100644 index 0000000..84c1bb0 --- /dev/null +++ b/src/pages/settings/index/App.vue @@ -0,0 +1,166 @@ +<template> + <div class="s-system-manage"> + <basic-setting v-show="activeName === 'basic'"></basic-setting> + </div> +</template> + +<script> +import AuthorityManagement from "../components/AuthorityManagement"; +import BasicSetting from "../components/BasicSetting"; +import ClusterManagement from "../components/ClusterManagement"; +import LogManagement from "../components/LogManagement"; +import RadioSet from "../components/RadioSet"; +import SystemMaintenance from "../components/SystemMaintenance"; +//import EventPush from "../components/systemManage/EventPush/index"; + +export default { + name: 'settings', + components: { + AuthorityManagement, + BasicSetting, + LogManagement, + RadioSet, + SystemMaintenance + }, + data() { + return { + activeName: "basic", + buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [], + loginName: JSON.parse(sessionStorage.getItem("userInfo")).username || "鐢ㄦ埛鍚�" + } + }, + computed: { + isAdmin() { + if ( + sessionStorage.getItem("userInfo") && + sessionStorage.getItem("userInfo") !== "" + ) { + let loginName = JSON.parse(sessionStorage.getItem("userInfo")).username; + return loginName === "superadmin" || loginName === "basic"; + } + return false; + } + }, + methods: { + isShow(authority) { + if (this.isAdmin) { + return true; + } else if (this.buttonAuthority.indexOf("," + authority + ",") > -1) { + return true; + } else { + return false; + } + }, + }, + created() { + if(this.isShow('videoSystem:base')){ + this.activeName = "basic" + }else if(this.isShow('videoSystem:permission')){ + this.activeName = "user" + }else if(this.isShow('videoSystem:broadcast')){ + this.activeName = "radio" + }else if(this.isShow('videoSystem:eventPush')){ + this.activeName = "event" + }else if(this.isShow('videoSystem:logManage')){ + this.activeName = "log" + }else if(this.isShow('videoSystem:sysManage')){ + this.activeName = "system" + } + }, +}; +</script> +<style lang="scss"> +.s-system-manage { + width: 100% !important; + box-sizing: border-box; + padding: 10px; + background-color: #e9ebf2; + .s-system-manage-breadcrumb { + height: 5%; + box-sizing: border-box; + border: 1px solid #e4e7ed; + box-shadow: #e4e7ed 0px 0px 9px inset; + box-shadow: #e4e7ed 0px 0px 9px inset; + border-radius: 5px; + } + + .el-tabs--border-card { + border: 0px solid #dcdfe6; + -webkit-box-shadow: none; + box-shadow: none; + .el-tabs__header { + border: 0px solid #dcdfe6; + .el-tabs__item { + padding: 5px 50px; + height: 50px; + font-family: PingFangSC-Regular; + font-size: 15px; + color: #222222; + text-align: center; + border: 0px solid transparent; + } + .el-tabs__item:nth-child(2) { + padding-left: 50px !important; + } + .el-tabs__item:last-child { + padding-right: 50px !important; + } + .el-tabs__item.is-active { + color: #3d68e1; + font-weight: bold; + // border-right-color: #fff; + // border-left-color: #fff; + } + .el-tabs__item:not(.is-disabled):hover { + color: #3d68e1; + } + } + } + .el-tabs__content { + height: calc(100% - 64px); + width: calc(100% - 20px); + box-sizing: border-box; + overflow-y: auto; + padding: 10px 40px !important; + .el-tab-pane { + width: 100%; + .s-title { + text-align: left; + padding: 15px 0px; + font-size: 16px; + } + } + } + + .s-table { + border: 1px solid #e8e8e9; + margin-top: 40px; + } + + .ui-top-title { + padding-bottom: 10px; + /* border-bottom: 1px solid #ebebeb; */ + position: relative; + text-align: left; + padding-left: 15px; + font-size: 16px; + font-weight: bold; + } + + .ui-top-title:before { + content: " "; + border-left: 4px solid #f53d3d; + display: inline-block; + height: 16px; + position: absolute; + top: 50%; + left: 0; + margin-top: -13px; + } + + .el-button--text { + color: #3d68e1; + text-decoration: underline; + } +} +</style> diff --git a/src/pages/settings/index/main.ts b/src/pages/settings/index/main.ts new file mode 100644 index 0000000..80f18a4 --- /dev/null +++ b/src/pages/settings/index/main.ts @@ -0,0 +1,11 @@ +import Vue from 'vue' +import ElementUI from 'element-ui' +import 'element-ui/lib/theme-chalk/index.css' +import App from './App.vue' + +Vue.use(ElementUI) + +new Vue({ + el: '#app', + render: h => h(App) +}) -- Gitblit v1.8.0