Browse Source

Merge branch 'feature_ide_20221214' of https://git.pcl.ac.cn/wangwei10061/aiforge into feature_ide_20221214

pull/3374/head
linlu 3 years ago
parent
commit
54a8f35f8f
4 changed files with 2038 additions and 0 deletions
  1. +1412
    -0
      web_src/js/components/IdeProject.vue
  2. +156
    -0
      web_src/js/components/VueTreeList.vue
  3. +214
    -0
      web_src/js/components/monacoeditor.vue
  4. +256
    -0
      web_src/js/components/vueTree.vue

+ 1412
- 0
web_src/js/components/IdeProject.vue
File diff suppressed because it is too large
View File


+ 156
- 0
web_src/js/components/VueTreeList.vue View File

@@ -0,0 +1,156 @@
<template>
<div class="treeNode">
<span @click="addNode">添加节点</span>
<vue-tree-list
:model="data"
default-tree-node-name="new file"
default-leaf-node-name="new folder"
:default-expanded="false"
@click="onClick"
@change-name="onChangeName"
@delete-node="onDel"
@add-node="onAddNode"
/>
</div>
</template>

<script>
import {VueTreeList, Tree, TreeNode} from 'vue-tree-list';

export default {
components: {
VueTreeList
},
props: {
treeData: {
type: Array,
default: () => []
},
fileInfoParams: {
type: Object,
default: () => {}
}
},
data() {
return {
newTree: {},
fileParams: {}, // 文件相关的信息
data: new Tree([
{
name: 'Node 1',
id: 1,
pid: 0,
children: [
{
name: 'Node 1-2',
id: 2,
isLeaf: true,
pid: 0
}
]
},
{
name: 'Node 2',
id: 3,
pid: 0,
},
{
name: 'Node 3',
id: 4,
pid: 0
}
])
};
},
watch: {
treeData(val) {
this.data = new Tree(val);
},
fileInfoParams(val) {
this.fileParams = val;
}
},
mounted() {
console.log('treeData', this.data);
},
methods: {
onDel(node) {
const paramsInfo = [];
if (!node.children?.length > 0) { // 文件还是文件夹
paramsInfo[0] = {...node};
} else { // 文件夹
node.children.filter((item) => item.sha).map((items) => { // 过滤是新增的元素进行删除
paramsInfo.push({
filePath: items.path,
content: '',
name: items.name,
operation: 'delete'
});
});
}
this.$emit('deleteNode', paramsInfo);
node.remove();
},

onChangeName(params) {
console.log(params);
},

onAddNode(params) {
console.log(params, '节点还是树');
},

// 点击每个文件/夹事件
onClick(params) {
if (!params.isLeaf) return;
if (this.fileParams?.sha === params.sha) return;
this.$emit('handleChangFile', params);
},

addNode() {
console.log('我是子节点');
const node = new TreeNode({name: 'new node', isLeaf: false});

if (!this.data.children) this.data.children = [];
this.data.addChildren(node);
},
}
};
</script>

<style lang="less" rel="stylesheet/less">
.vtl {
.vtl-drag-disabled {
background-color: #d0cfcf;
&:hover {
background-color: #d0cfcf;
}
}
.vtl-disabled {
background-color: #d0cfcf;
}
}
</style>

<style lang="less" rel="stylesheet/less" scoped>
.icon {
&:hover {
cursor: pointer;
}
}

.muted {
color: gray;
font-size: 80%;
}
</style>

<style scoped>
.treeNode{
padding:20px 20px 0;
overflow-y: auto;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

+ 214
- 0
web_src/js/components/monacoeditor.vue View File

@@ -0,0 +1,214 @@

<template>
<div ref="container" class="monaco-editor" style="height: calc(100vh - 42px)" />
</template>

<script>
// import * as monaco from "monaco-editor";

import "monaco-editor/min/vs/loader.js";
import "monaco-editor/min/vs/editor/editor.main.nls.js";
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
// import "monaco-editor/esm/vs/basic-languages/mysql/mysql.contribution";
// import "monaco-editor/esm/vs/editor/contrib/suggest/suggestController.js";
// import "monaco-editor/esm/vs/editor/contrib/bracketMatching/bracketMatching.js";
// import "monaco-editor/esm/vs/editor/contrib/hover/hover.js";
import { isBase64 } from "../utils.js";
export default {
name: "AcMonaco",
inject: ["reload"],
props: {
opts: {
type: Object,
default() {
return {};
},
},
height: {
type: Number,
default: 300,
},

monacaValue: {
type: String,
default: "false",
},
onChange: {
type: Function,
default: new Function
}
},
data() {
return {
isDiff: false,
// 主要配置
defaultOpts: {
lineNumbersMinChars: 0,
lineDecorationsWidth: 0,
glyphMargin: false,
value: "", // 编辑器的值
wordWrap: "on",
theme: "vs-dark", // 编辑器主题:vs, hc-black, or vs-dark,更多选择详见官网
roundedSelection: false, // 右侧不显示编辑器预览框
autoIndent: true, // 自动缩进
quickSuggestions: true, // 快速搜索

enableSplitViewResizing: false,
scrollBeyondLastLine: false,
quickSuggestions: false, //智能提示
renderLineHighlight: false, //选中行外部边框
lineHeight: 22

},

// 编辑器对象
monacoEditor: {},
oldValue: "123123/n\n",
newValue: "123121311111111",
};
},
watch: {
opts: {

},
monacaValue: {
handler(value) {
if(this.isDiff) return ;
const editor = this.monacoEditor
const output = isBase64(value)
? Buffer.from(value, "base64").toString("utf8")
: value;
const positions = this.monacoEditor.getPosition()
this.monacoEditor.setValue(output);
this.monacoEditor.setPosition({
lineNumber: positions.lineNumber,
column: positions.column
})
},
deep: true
},
// monacaValue(value) {
// alert(value)
// console.log(isBase64);
// const output = isBase64(value)
// ? Buffer.from(value, "base64").toString("utf8")
// : value;
// this.monacoEditor.setValue(output);
// },
},
beforeDestroy() {
document.removeEventListener("keyup", this.onSaveHandler);
},
mounted() {
document.addEventListener("keyup", this.onSaveHandler, false);

this.init();
},
methods: {
init() {

// 初始化container的内容,销毁之前生成的编辑器
this.$refs.container.innerHTML = "";
// 生成编辑器配置
const editorOptions = Object.assign(this.defaultOpts, this.opts);
if (!this.isDiff) {
// 初始化编辑器实例
this.monacoEditor = monaco.editor.create(
this.$refs.container,
editorOptions
);
this.monacoEditor.onDidChangeModelContent(
event => {
this.$emit("onChange", this.monacoEditor.getValue())
},
);

// 编辑器内容发生改变时触发
} else {
editorOptions.readOnly = true;
editorOptions.language = "javascript";
// editorOptions.inlineHints = true;
// 初始化编辑器实例
this.monacoDiffInstance = monaco.editor.createDiffEditor(
this.$refs.container,
editorOptions
);
this.monacoDiffInstance.setModel({
original: monaco.editor.createModel(
this.oldValue,
editorOptions.language
),
modified: monaco.editor.createModel(
this.newValue,
editorOptions.language
),
});
}

if (this.monacaValue) {
const output = isBase64(this.monacaValue)
? Buffer.from(value, "base64").toString("utf8")
: this.monacaValue;
this.monacoEditor.setValue(output);
}
},
upDateDiff(val) {
this.monacoDiffInstance.updateOptions({
renderSideBySide: !val,
});
},
onSaveHandler(e) {
if(this.isDiff) return;
if (
(window.navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) &&
e.keyCode === 83
) {
e.preventDefault();
this.$emit("handleSave", this.monacoEditor.getValue());
}
this.$emit("handleSave", this.monacoEditor.getValue());
},
// 供父组件调用手动获取值
getVal() {
return this.monacoEditor.getValue();
},
setLanguage(lang) {
setTimeout(() => {
if (monaco.editor.setModelLanguage) {
monaco.editor.setModelLanguage(this.monacoEditor.getModel(), lang)
}
}), 300;
// alert(JSON.stringify(this.monacoEditor.getModel()))
},
updateOptions(opts) {
const editorOptions = Object.assign(this.defaultOpts, opts);
this.monacoEditor.updateOptions(editorOptions);
},
setTheme(theme) {
monaco.editor.setTheme(theme);
},
setDiff(oldContent, newContent) {
this.oldValue = isBase64(oldContent) ? Buffer.from(oldContent, "base64").toString("utf8") : oldContent;
this.newValue = newContent;
this.isDiff = true;
this.init();
},
setCloseDiff() {
if (this.isDiff) {
this.isDiff = false;
this.init();
}
},
},
};
</script>

<style>
.margin-view-overlays {
background: #f5f5f5;
}

/* .view-lines {
padding-left: 10px;
} */
</style>

+ 256
- 0
web_src/js/components/vueTree.vue View File

@@ -0,0 +1,256 @@
<template>
<div class="myTrees">
<el-tree
ref="tree"
:data="treeData"
node-key="filePath"
empty-text="暂无数据"
highlight-current
@node-click="handleLeftclick"
>
<div slot-scope="{ node , data }" class="custom-tree-node">
<span>
<i :class="getIcon(node.data)" />
{{ node.label }}
</span>
<span>
<el-dropdown trigger="click" class="el-dropdown"
v-show="!isLeaf && data.type == 'tree'"
>
<span class="el-dropdown-link">
<svg class="icon el-dropdown-svg" aria-hidden="true">
<use xlink:href="#icon-a-bianzu31"></use>
</svg>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
@click.native="addChildNode('leaf')"
>新建文件</el-dropdown-item
>
<el-dropdown-item
@click.native="addChildNode('')"
>新建文件夹</el-dropdown-item
>
<!-- <el-dropdown-item @click.native="deleteNode">删除</el-dropdown-item> -->
</el-dropdown-menu>
</el-dropdown>
</span>
</div>
</el-tree>
</div>
</template>
<!-- file-icon ide-icon word-icon dark-blue -->
<link rel="stylesheet" href="/web_src/js/components/treeIcon.css" />
<script>
import {icons} from "./icons";
console.log("icons:",icons)
export default {
name: "List",
props: {
treeListData: {
type: Array,
default: () => [],
},
fileInfoParams: {
type: Object,
default: () => {},
},
},
data() {
return {
fileParams: {},
treeData: [],
isShow: false,
currentData: "",
currentNode: "",
menuVisible: false,
firstLevel: false,
lastLevel: false,
filterText: "",
isLeaf: false,
};
},
watch: {
treeListData(val) {
this.treeData = val;
},
fileInfoParams(val) {
this.fileParams = val;
},
},

methods: {
// 鼠标左击事件
handleLeftclick(data, node) {
this.currentData = data;
this.currentNode = node;
this.firstLevel = false;
this.isLeaf = data.isLeaf;
this.lastLevel = false;
if (data.type === 'tree') return;
// if (data.sha) {
this.$emit("handleChangFile", data, this.treeData);
// }
},
getIcon(data){
console.log("data:",data.name.split("."))
let icon = '';
if(data.type === 'tree'){
return 'fa fa-folder ide-icon ide-icon-folder'
}
try {
let suffix = data.name.split(".").pop();
if(data.name.indexOf(".") > -1){
suffix = "." + suffix
}
icons.forEach(element => {
if(element[2].test(suffix)){
icon = element[0] + ' ' + element[1].join(' ');
throw('')
}
})
} catch (error) {

}
return "file-icon ide-icon " + icon;
},

// 增加子级节点事件
addChildNode(shape) {
const id = Math.ceil(Math.random() * 100);
this.$prompt("请输入名称", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
})
.then(({ value }) => {
if (value.trim().indexOf("") === -1)
return this.$message.warning("名称不能包含空格!");
const treeD = {
id,
label: value,
operation: "add",
isEdit: true,
type: shape === "leaf" ? "blob" : "tree",
filePath: `${this.currentData.filePath}/${value}`,
isLeaf: shape === "leaf",
name: value,
fileType:"txt",
children: [],
};
if(shape === "leaf"){
treeD.content = "";
treeD.oldContent = "";
treeD.newContent = "";
treeD.fileType = 'txt'
}
treeD.path = treeD.filePath;
this.$refs.tree.append(treeD, this.currentData.filePath);
this.$emit("handleAddNode", treeD, this.currentData.filePath); // 触发父组件更改提交界面的数据变化
})
.catch(() => {});
},
// 删除节点
deleteNode() {
this.$confirm(`确定删除当前文件,是否继续?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
if (this.currentData.isLeaf) {
// isLeaf为true 代表文件类型
if (this.currentData.operation === "add") {
// 新增的节点删去
this.$emit("handleDeleteAddNode", this.currentData);
} else if (this.currentData.sha) {
// 原本存在的数据 触发父组件更新已存在数据的状态
this.$emit("handleDeleteOldNode", this.currentData);
}
}
this.$refs.tree.remove(this.currentNode);
})
.catch(() => {});
},
},
};
</script>
<style lang="less" scoped>
@import "./treeIcon.css";
.myTrees {
/*background: transparent;*/
height: 100%;
overflow: auto;
background: #FFFFFF;
}
.el-tree {
/* padding: 20px; */
/*background: transparent;*/
background: #FFFFFF;
color: black;
}
.el-tree .is-current{
background: #f5f7fa;
}

.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding-right: 8px;
font-size: 14px;
height: 34px;
line-height: 34px;
.el-dropdown-svg{
height: 16px;
width: 16px;
color: #979797;
}
.el-dropdown-svg:hover{
color: #007aff;
}
}
/deep/ .el-tree-node__content{
height: 34px;
line-height: 34px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
}
/deep/ .el-tree-node.is-current > .el-tree-node__content{
background: #F5F7FA;
color: #2285D0 !important;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #2285D0;
}
.el-dropdown-menu{
padding: 0px !important;
}
.el-popper[x-placement^=bottom] .popper__arrow {
display: none !important;
}
.el-dropdown-menu__item{
color: #333333 !important;
height: 34px !important;
}
li.el-dropdown-menu__item:hover {
background: #f2f2f2 !important;
}
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<style>
.myTrees .el-tree-node__expand-icon{
visibility: hidden;
}
.monaco-editor .line-numbers{
color: #999;
}
</style>

Loading…
Cancel
Save