1 Star 0 Fork 0

oldlie / exp-2-tree

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
index.html 21.55 KB
一键复制 编辑 原始数据 按行查看 历史
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/theme-chalk/index.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/index.js"></script>
</head>
<body>
<div id="app">
<div>
<p>
<el-input type="textarea" :rows="8" placeholder="请输入内容" v-model="exp">
</el-input>
</p>
<p>
<el-button @click="exp2Tree">将表达式输出成树</el-button>
</p>
<el-row style="white-space:pre-wrap">
<el-col :span="24">
<el-tree :data="data" :props="defaultProps" default-expand-all @node-drag-start="handleDragStart"
:indent="32" @node-drag-enter="handleDragEnter" @node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver" @node-drag-end="handleDragEnd" @node-drop="handleDrop"
draggable :allow-drop="allowDrop" :allow-drag="allowDrag" @node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>
<el-button-group>
<el-button v-if="node.label[0] !== '('" type="text" size="mini"
@click="handleNodeClick($event, node, data)">
<i class="el-icon-edit-outline"></i>
</el-button>
<el-button v-else type="text" size="mini"
@click="handleNodeClick($event, node, data)">
<i class="el-icon-plus"></i>
</el-button>
<el-button type="text" size="mini" @click="() => remove(node, data)">
<i class="el-icon-delete"></i>
</el-button>
</el-button-group>
</span>
<span style="font-size:12px;">{{ node.label }}</span>
</span>
</el-tree>
</el-col>
</el-row>
<p>
<el-button @click="tree2Exp">将树输出成表达式</el-button>
</p>
<p>
<el-input type="textarea" :rows="8" placeholder="请输入内容" v-model="exp2">
</el-input>
</p>
<el-dialog title="编辑" :visible.sync="dialogVisible" width="80%" :close-on-click-modal="false">
<p>
<el-input type="textarea" :rows="8" placeholder="请输入内容" v-model="exp3">
</el-input>
</p>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="updateExp">确 定</el-button>
</span>
</el-dialog>
<el-dialog title="追加" :visible.sync="dialog1Visible" width="80%" :close-on-click-modal="false">
<p>
<el-input type="textarea" :rows="8" placeholder="请输入内容" v-model="exp4">
</el-input>
</p>
<span slot="footer" class="dialog-footer">
<el-button @click="dialog1Visible = false">取 消</el-button>
<el-button type="primary" @click="appendToChildren">追加表达式到子节点</el-button>
<el-button type="primary" @click="appendToGrandson">追加表达式到孙子节点</el-button>
</span>
</el-dialog>
</div>
</div>
<script>
let exp = '(exp1 and 表达式2) or (exp3 and exp4)';
let exp2 = "(分类号=('B23B%' or 'B23C%' or 'B24B%' or 'B27C3/%' or 'B23F%' or 'B23H%') or 名称=(车床 or 铣床 or 钻床 or 镗床 or 磨床 or ((车削 or 车铣 or 车磨 or 车拉 or 铣削 or 车铣 or 磨削 or 珩磨 or 滚齿 or 插齿 or 车齿 or 刨齿 or 铣齿 or 拉齿 or 珩齿 or 剃齿 or 磨齿) and (机 or 设备 or 装置 or 工装 or 生产线 or 中心 or 系统))) or (摘要,主权项+=(车床 or 铣床 or ((车削 or 车铣 or 车磨 or 车拉 or 铣削 or 车铣) and (设备 or 装置 or 工装 or 生产线 or 中心))) and 分类号=('B23%')) or ((名称=(机床 or 加工中心)) and 名称,摘要,主权项+=((车削 not 车削膜) or 铣削)) or (名称,摘要,主权项+=(钻床 or 钻镗床 or 钻头) and 分类号=('B27C%')) or (名称,摘要,主权项+=(磨 and (床 or 设备 or 装置 or 工装)) and 分类号=('B23%')) or 申请(专利权)人=(格里森 or 赫思机器及工具 or 机床) or (摘要,主权项+=((滚齿 or 插齿 or 车齿 or 刨齿 or 铣齿 or 拉齿 or 珩齿 or 剃齿 or 磨齿) and (机 or 床 or 设备 or 装置 or 工装)) and 分类号=('B23%' or 'G%')) or (名称,摘要,主权项+=(线切割 or 走丝 or 电加工 or 电火花) and 分类号=('B23H%' or 'B23Q%' or '15-09%')) or (名称,摘要,主权项+=((线切割 or 电加工 or 电火花) and (导丝 or 丝架 or 线架 or 运丝 or 丝筒 or 走丝 or 电火花 or 钼丝 or 脉冲 or 电极丝 or 断线 or 断丝 or 电源)) and 分类号=('B01D%' or 'B23%' or 'G05%' or 'G06%' or 'H%')) or (分类号=('B26D7%') or 名称=(电加工 or 电火花 or 电腐蚀 or 电蚀 or 夹具))) and (分类号=('B23Q15%' or 'G05B19/18%' or 'G05B19/19%' or 'G05B19/2%' or 'G05B19/3%' or 'G05B19/40%' or 'G05B19/41%' or 'G05B13%') or 名称,摘要,主权项+=(数控 or 闭环控制 or 数值控制 or 数字控制 or NC or CNC or 插补 or 运动控制 or 自适应))"
function TreeNode() {
this.left = null;
this.right = null;
this.value = null;
}
function isLogicOpt(str, str1) {
return str === 'and' ||
str === 'or' ||
str === 'not' ||
str === 'xor' ||
str === 'adj' ||
str === 'equ/10' ||
str === 'xor/10' ||
str === 'pre/10';
}
function getWords(exp) {
exp = exp.replace(/\s+/ig, ' ');
let bracket = 0;
let bracketStr = '';
let quotation = false;
let chars = [];
let words = [];
let word = '';
for (let i = 0; i < exp.length; i++) {
let char = exp[i];
if (char === '(') {
bracketStr += char;
bracket++;
}
if (char === ')') {
bracketStr += char;
bracket--;
}
if (char === "'") {
quotation = true;
word += char;
i++;
for (; i < exp.length; i++) {
char = exp[i];
word += char;
if (char === "'") {
quotation = false;
break;
}
}
continue;
}
if (quotation) {
console.error('单引号不匹配--->', exp);
throw "单引号不匹配:" + exp;
}
if (char === '\\') {
word += char;
i++;
char = exp[i];
word += char;
continue;
}
if (char === ' ' && bracket === 0) {
words.push(word);
word = '';
continue;
}
word += char;
}
if (word != '') {
words.push(word);
}
if (bracket !== 0) {
console.error('括号不匹配 ---->', exp, bracket, bracketStr);
throw "括号不匹配:" + exp;
}
return words;
}
function copy(obj) {
return JSON.parse(JSON.stringify(obj));
}
function analysisExp(exp) {
let words = getWords(exp);
if (!words || words.length <= 1) {
return null;
}
// root的right总是null
let root = new TreeNode();
root.value = { text: '()', type: 'root' }
let length = words.length;
for (let i = 0; i < length; i++) {
let word = words[i];
if (word[0] === '(' && word[word.length - 1] === ')') {
word = word.replace(/(^\(|\)$)/ig, '');
}
let child = analysisExp(word);
if (child === null) {
// 说明就是一个表达式,这个表达式里面不含有表达式了
let leaf = new TreeNode();
if (isLogicOpt(word)) {
leaf.value = { text: word, type: 'opt' };
if (root.left === null) {
let errLeft = new TreeNode();
errLeft.value = { text: 'Left_error', type: '逻辑运算符左边没有表达式' }
leaf.left = copy(errLeft);
root.left = copy(leaf);
} else {
let preLeft = copy(root.left);
leaf.left = copy(preLeft);
root.left = copy(leaf);
}
} else {
if (root.left === null) {
leaf.value = { text: word, type: 'left' }
root.left = JSON.parse(JSON.stringify(leaf));
} else {
let preOpt = root.left;
if (preOpt.leaf === null) {
// 正常情况下左节点不可能为空
let errLeft = new TreeNode();
errLeft.value = { text: 'Left_error', type: '逻辑运算符左边没有表达式' }
preOpt.left = copy(errLeft);
}
if (preOpt.right !== null) {
// 如果右叶子不为空,则说明遇到了两个连续的表达式使用空格分隔的情况,这里补一个or运算符节点
let plusRoot = new TreeNode();
plusRoot.value = { text: '()', type: 'root' };
let preRight = copy(preOpt.right);
plusRoot.left = preRight;
leaf.value = { text: word, type: 'right' }
plusRoot.right = copy(leaf);
preOpt.right = plusRoot;
} else {
leaf.value = { text: word, type: 'right' }
preOpt.right = copy(leaf);
}
}
}
} else {
// 说明底下是一个表达式,那么该word不可能是逻辑运算符
if (root.left === null) {
root.left = child;
} else {
let preOpt = root.left;
if (preOpt.leaf === null) {
// 正常情况下左节点不可能为空
let errLeft = new TreeNode();
errLeft.value = { text: 'Left_error', type: '逻辑运算符左边没有表达式' }
preOpt.left = copy(errLeft);
}
if (preOpt.right === null) {
preOpt.right = child;
} else {
// 如果右叶子不为空,则说明遇到了两个连续的表达式使用空格分隔的情况,这里补一个or运算符节点
let plusRoot = new TreeNode();
plusRoot.value = { text: '()', type: 'root' };
let preRight = copy(preOpt.right);
plusRoot.left = preRight;
plusRoot.right = child;
preOpt.right = plusRoot;
}
}
}
}
return root;
}
// let simpleTree = analysisExp(exp2);
// console.log('st --->', simpleTree);
/**
* 先序遍历
*/
function dlr(tree, queue) {
queue.push(tree.value.text);
if (tree.left !== null) {
dlr(tree.left, queue);
}
if (tree.right !== null) {
dlr(tree.right, queue)
}
}
function dlr2(tree, queue) {
if (tree.left !== null) {
if (tree.left.value && tree.left.value.type === 'root') {
let lt = tree2List(tree.left);
queue.push(lt)
} else {
dlr2(tree.left, queue);
}
}
// queue.push(tree.value.text);
queue.push({ label: tree.value.text });
if (tree.right !== null) {
if (tree.right.value && tree.right.value.type === 'root') {
let lt = tree2List(tree.right);
queue.push(lt)
} else {
dlr2(tree.right, queue)
}
}
}
// let queue = [];
// dlr(simpleTree, queue);
// console.log('queue', queue);
function tree2List(tree) {
if (tree === null) {
return null;
}
let vt = {
label: tree.value.text,
children: []
}
let left = copy(tree.left);
let right = copy(tree.right);
if (left === null && right === null) {
return list;
}
let queue = [];
if (left != null) {
dlr2(left, queue);
}
if (right != null) {
dlr2(right, queue);
}
vt.children = queue;
return vt;
}
// let data = tree2List(simpleTree);
// console.log('tree 2 list --->', data);
function tree2Exp(data) {
let exp = '';
for (let i = 0; i < data.length; i++) {
let item = data[i];
if (item.children) {
let temp = tree2Exp(item.children);
exp += `(${temp})`;
} else {
if (isLogicOpt(item.label)) {
exp += ' ' + item.label + ' ';
} else {
exp += item.label;
}
}
}
return exp;
}
var app = new Vue({
el: '#app',
data() {
return {
exp: exp2,
exp2: '',
data: [],
defaultProps: {
children: 'children',
label: 'label'
},
dialogVisible: false,
exp3: '',
tempNode: {},
tempData: {},
dialog1Visible: false,
exp4: '',
}
},
methods: {
handleNodeClick(event, node, data) {
console.log('event --->', event);
this.tempNode = node;
this.tempData = data;
this.exp3 = this.tempNode.label;
if (this.exp3[0] === '(') {
event.stopPropagation();
this.dialog1Visible = true;
} else {
this.dialogVisible = true;
}
return false;
},
exp2Tree() {
let simpleTree;
try {
simpleTree = analysisExp(this.exp);
} catch (e) {
this.$message.error(e);
}
if (!simpleTree) {
this.$message.error('表达式不足以构成树结构');
return;
}
let data = [];
data.push(tree2List(simpleTree));
this.data = data;
},
handleNodeExpand(node) {
node.label = '(...)';
},
handleNodeCollapse(node) {
let children = [];
node.children.forEach(x => {
children.push(x.label);
});
node.label = `(${children.join(" ")})`;
},
tree2Exp() {
this.exp2 = tree2Exp(this.data[0]['children']);
},
handleClose() {
this.dialogVisible = false;
},
handle1Close() {
this.dialog1Visible = false;
},
updateExp() {
console.log('update exp');
this.tempData.label = this.exp3;
console.log('node--->', this.tempNode, this.tempData);
this.dialogVisible = false;
},
remove(node, data) {
console.log('node', node.id);
console.log('data', data.id);
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => {
let id = d.$treeNodeId;
console.log('children id --->', id, node.id, id === node.id);
return d.$treeNodeId === node.id
});
children.splice(index, 1);
}).catch(() => {
});
},
appendToChildren() {
this.tempData.children.push({ label: this.exp4 });
this.exp4 = '';
this.dialog1Visible = false;
},
appendToGrandson() {
let node = { label: '()', children: [] };
node.children.push({ label: this.exp4 });
this.tempData.children.push(node);
this.exp4 = '';
this.dialog1Visible = false;
},
// region 拖拽
handleDragStart(node, ev) {
console.log('drag start', node);
},
handleDragEnter(draggingNode, dropNode, ev) {
console.log('tree drag enter: ', dropNode.label);
},
handleDragLeave(draggingNode, dropNode, ev) {
console.log('tree drag leave: ', dropNode.label);
},
handleDragOver(draggingNode, dropNode, ev) {
console.log('tree drag over: ', dropNode.label);
},
handleDragEnd(draggingNode, dropNode, dropType, ev) {
console.log('tree drag end: ', dropNode && dropNode.label, dropType);
this.data = JSON.parse(JSON.stringify(this.data));
},
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log('tree drop: ', dropNode.label, dropType);
},
allowDrop(draggingNode, dropNode, type) {
if (dropNode.data.label === '二级 3-1') {
return type !== 'inner';
} else {
return true;
}
},
allowDrag(draggingNode) {
// return draggingNode.data.label[0] !== "(";
return true;
}
// endregion
},
});
</script>
</body>
</html>
1
https://gitee.com/oldlie/exp-2-tree.git
git@gitee.com:oldlie/exp-2-tree.git
oldlie
exp-2-tree
exp-2-tree
master

搜索帮助