山东大学软件学院项目实训weblab-9

前言

本项目是为开发一套容器化的开发、运行、测试环境,用以支持Web开发、程序设计等课程的实验教学。

完善文件压缩类

import JSZip from 'jszip';
import { saveAs } from 'file-saver';

enum FileType {
    root,
    folder,
    ts,
    js,
    html,
    css,
    md,
    txt,
}
const fileTypes = function (type: string): FileType | undefined {
    switch (type) {
        case "folder":
            return FileType.folder;
        case "ts":
            return FileType.ts;
        case "js":
            return FileType.js;
        case "html":
            return FileType.html;
        case "css":
            return FileType.css;
        case "md":
            return FileType.md;
        case "txt":
            return FileType.txt;
        default:
            return undefined
    }
}
class Ziper {
    projName: string = 'web';
    zip: any;
    constructor() {
        this.zip = new JSZip();
    }
    setProjectName(name: string) {
        this.projName = name;
    }
    updateProject(data: any, parent = this.zip) {
        for (var item in data) {
            if (data[item].type == FileType.folder) {
                let pa = this._addFolder(parent, data[item].name)
                this.updateProject(data[item].children, pa);
            } else {
                this._addFile(parent, data[item].name, data[item].value);
            }
        }
    }
    _addFile(parent: any, name: string, value: string) {
        parent.file(name, value);
    }
    _addFolder(parent: any, name: string) {
        return parent.folder(name);
    }
    _saveZIP() {
        let projName = this.projName;
        this.zip.generateAsync({ type: "blob" })
            .then(function (blob: any) {
                saveAs(blob, projName);
            });
    }
}
const ziper = new Ziper();


export { ziper, FileType, fileTypes };

实现代码编辑器与文件管理器的通信

编辑器里:

const setCode=(new_code:string,type:FileType)=>{
  code.value=new_code;
  switch(type){
    case FileType.js:
      cmOptions.value.mode="text/javascript";
      break;
    case FileType.ts:
      cmOptions.value.mode="text/typescript";
      break;
    case FileType.md:
      cmOptions.value.mode="text/x-markdown";
      break;
    case FileType.css:
      cmOptions.value.mode="text/css";
      break;
    case FileType.html:
      cmOptions.value.mode="text/html"
      break;
  }
}
defineExpose({setCode});
const emit = defineEmits(['onChange']);

文件管理器:

const LeftClick = function (data: Tree) {
  visible.value = false;
  if (data.type != FileType.folder && data.type != FileType.root) {
    selectedData.value = data;
    emit("setFileContext", selectedData.value.value, selectedData.value.type);
  }
}


const emit = defineEmits(['setFileContext']);
const setCode = (value: string) => {
  if (selectedData.value != null) {
    console.log(selectedData.value.name);
    selectedData.value.value = value;
  }
}
defineExpose({ setCode })

coding页面:

const setFileContext = (code: string, type: FileType) => {
  cmRef.value.setCode(code, type);
}
const onCodeChange = (value: string) => {
  sideRef.value.setCode(value);
}

目前的效果

在这里插入图片描述

进一步完善

在一开始没有选择文件时显示选择文件来打开编辑器

<code-editor-vue ref="cmRef" @on-change="onCodeChange" v-show="selected"></code-editor-vue>
        <el-result title="open file to edit" v-show="!selected">
          <template #icon>
            <el-icon :size="250">
              <files />
            </el-icon>
          </template>
        </el-result>
const store = useFileStore();
const sideRef = ref();
const cmRef = ref();
const selected = computed({
  get: () => store.getSelected,
  set: (val) => {
    selected.value = val;
  },

})

pinia中

const useFileStore = defineStore({
  id: "file",
  state: () => ({
    selected: false,
  }),
  getters: {
    getSelected(state) {
      return state.selected;
    },
  },
  actions: {
    setSelected(s: boolean) {
      this.selected = s;
    }
  },
});

文件管理器栏

const LeftClick = function (data: Tree) {
  visible.value = false;

  if (data.type != FileType.folder && data.type != FileType.root) {
    selectedData.value = data;
    store.setSelected(true);
    emit("setFileContext", selectedData.value.value, selectedData.value.type);
  }
}
const Delete = function () {
  ElMessageBox.confirm('You will delete the file,continue?', 'Warning',
    {
      confirmButtonText: 'OK',
      cancelButtonText: 'Cancel',
      type: 'warning',
    })
    .then(() => {
      const parent = targetNode.value?.parent
      const children: Tree[] = parent?.data.children || parent?.data
      const index = children.findIndex((d) => d.id === targetData.value?.id)
      children.splice(index, 1)
      dataSource.value = [...dataSource.value]
      selectedData.value=undefined;
      store.setSelected(false);
    })
    .catch(() => {
    })
}

将所有文件保存为zip

点击按钮

const Submit = function () {
  emit('SaveZIP')
}
const emit = defineEmits(['SaveZIP']);

文件管理栏

const getData = () => {
  return dataSource.value[0].children;
}
const getProjectName = () => {
  return dataSource.value[0].name;
}

coding页面

const saveZIP = () => {
  ziper.setProjectName(sideRef.value.getProjectName());
  ziper.updateProject(sideRef.value.getData());
  ziper._saveZIP();
}

最终效果

在这里插入图片描述

完整代码

CodeEditor.vue

<template>
  <CodeMirror ref="cmRef" class="code-mirror" :value="code" :options="cmOptions" :border="true" :height="400"
    @change="onChange" @input="onInput" @ready="onReady" autofocus KeepCursorInEnd />
</template>


<script setup lang="ts">
import CodeMirror from "codemirror-editor-vue3"
// language
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/vue/vue.js";
import "codemirror/mode/markdown/markdown.js";
import "codemirror/mode/css/css.js";
import "codemirror/mode/htmlmixed/htmlmixed.js"

import type { Editor, EditorConfiguration } from "codemirror";
// theme css
import "codemirror/theme/rubyblue.css";
import "codemirror/theme/panda-syntax.css";
import "codemirror/theme/darcula.css";
import "codemirror/theme/idea.css";
import "codemirror/theme/eclipse.css";
// require active-line.js
import "codemirror/addon/selection/active-line.js";
// styleSelectedText
import "codemirror/addon/selection/mark-selection.js";
import "codemirror/addon/search/searchcursor.js";
// hint
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/javascript-hint.js";
import "codemirror/addon/selection/active-line.js";
// highlightSelectionMatches
import "codemirror/addon/scroll/annotatescrollbar.js";
import "codemirror/addon/search/matchesonscrollbar.js";
import "codemirror/addon/search/searchcursor.js";
import "codemirror/addon/search/match-highlighter.js";
// keyMap
import "codemirror/mode/clike/clike.js";
import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/addon/comment/comment.js";
import "codemirror/addon/dialog/dialog.js";
import "codemirror/addon/dialog/dialog.css";
import "codemirror/addon/search/searchcursor.js";
import "codemirror/addon/search/search.js";
import "codemirror/keymap/sublime.js";
// foldGutter
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/fold/comment-fold.js";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/foldgutter.js";
import "codemirror/addon/fold/indent-fold.js";
import "codemirror/addon/fold/markdown-fold.js";
import "codemirror/addon/fold/xml-fold.js";

import { onMounted, ref, type Ref } from "vue";
import { FileType } from "@/fileziper";
const cminstance = ref<Editor>();
const cmOptions = ref<EditorConfiguration>({
  mode: "text/javascript", // 语言模式  java:text/x-java js:text/javascript ts:text/typescript css:text/css html:text/html md:text/x-markdown
  tabSize: 4,
  theme: "darcula", // 主题
  lineNumbers: true, // 显示行号
  styleSelectedText: true,
  smartIndent: true, // 智能缩进
  indentUnit: 4, // 智能缩进单位为4个空格长度
  foldGutter: true, // 启用行槽中的代码折叠
  styleActiveLine: true, // 显示选中行的样式
  gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
  highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: true },
  matchBrackets: true,
  showCursorWhenSelecting: true,
  extraKeys: { Ctrl: "autocomplete" },
  autofocus: true,
  lineWrapping: true,
});
var code = ref();

function onChange(value: string) {

}
function onInput(value: string) {
  emit('onChange', value);
}
function onReady(cm: Editor) {
  cminstance.value = cm;
}
onMounted(() => {
  // code.value = "let b=20;";
})
const setCode = (new_code: string, type: FileType) => {
  // code.value = new_code;

  cminstance.value!.setValue(new_code);
  
  switch (type) {
    case FileType.js:
      cmOptions.value.mode = "text/javascript";
      break;
    case FileType.ts:
      cmOptions.value.mode = "text/typescript";
      break;
    case FileType.md:
      cmOptions.value.mode = "text/x-markdown";
      break;
    case FileType.css:
      cmOptions.value.mode = "text/css";
      break;
    case FileType.html:
      cmOptions.value.mode = "text/html"
      break;
    case FileType.txt:
      cmOptions.value.mode = "text";
      break;
  }
  cminstance.value!.refresh();

}
defineExpose({ setCode });
const emit = defineEmits(['onChange']);
</script>



<style>
.code-mirror {
  font-size: 16px !important;
  line-height: 150%;
  text-align: left !important;
}
</style>

coding-view.vue

import { FileType } from "../fileziper";
<!--login-coding-page-->
<template>
  <el-header>
    <topmenu :activeIndex="'2'"></topmenu>
  </el-header>

  <el-main>
    <el-row class="tac">
      <el-col :span="5">
        <side ref="sideRef" @set-file-context="setFileContext" />
      </el-col>
      <el-col :span="1"></el-col>
      <el-col :span="18">
        <code-editor-vue ref="cmRef" @on-change="onCodeChange" v-show="selected"></code-editor-vue>
        <el-result title="open file to edit" v-show="!selected">
          <template #icon>
            <el-icon :size="250">
              <files />
            </el-icon>
          </template>
        </el-result>
        <div class="grid-content"></div>
        <el-divider content-position="center">
          <btns @save-z-i-p="saveZIP"></btns>
        </el-divider>
        <div class="grid-content"></div>
        <ResultsDisplay></ResultsDisplay>
      </el-col>
    </el-row>
  </el-main>
</template>

<script lang="ts" setup>
import { ref, computed } from "vue";
import { RouterLink, RouterView } from "vue-router";
import CodeEditorVue from "../components/CodeEditor.vue";
import ResultsDisplay from "../components/ResultsDisplay.vue"
import btns from "../layout/btns.vue"
import topmenu from "../layout/topmenu.vue";
import side from "../layout/sidecolumn.vue"
import { ziper } from "../fileziper"
import type { FileType } from "../fileziper";
import { useFileStore } from '@/stores/store';
import { Files } from '@element-plus/icons-vue';
const store = useFileStore();
const sideRef = ref();
const cmRef = ref();
const selected = computed({
  get: () => store.getSelected,
  set: (val) => {
    selected.value = val;
  },

})

const setFileContext = (code: string | undefined, type: FileType) => {
  cmRef.value.setCode(code, type);

}
const onCodeChange = (value: string) => {
  sideRef.value.setCode(value);

}
const saveZIP = () => {
  ziper.setProjectName(sideRef.value.getProjectName());
  ziper.updateProject(sideRef.value.getData());
  ziper._saveZIP();
}
</script>

<style>
.grid-content {
  border-radius: 4px;
  min-height: 10px;
}
</style>

store.ts

import { defineStore } from "pinia";

const useLoginStore = defineStore({
  id: "login",
  state: () => ({
    isLogin: Number(localStorage.getItem('isLogin') || '0'),
    userId: localStorage.getItem('userId') || '',
    userPassword: localStorage.getItem('userPassword') || '',
    token: localStorage.getItem('token') || '',
  }),
  getters: {
    getIsLogin(state) {
      return (state.isLogin == 1) ? true : false;
    },
    getUserId(state) {
      return state.userId;
    },
    getUserPassword(state) {
      return state.userPassword;
    },
    getToken(state) {
      return state.token;
    },


  },
  actions: {
    userLogin(id: string, pwd: string, token: string) {
      this.isLogin = 1;
      this.userId = id;
      this.userPassword = pwd;
      this.token = token;
      localStorage.setItem('isLogin', '1');
      localStorage.setItem('userId', id);
      localStorage.setItem('userPassword', pwd);
      localStorage.setItem('token', token);
    },
    userLogout() {
      this.isLogin = 0;
      this.userId = '';
      this.userPassword = '';
      this.token = '';
      localStorage.removeItem('isLogin');
      localStorage.removeItem('userId');
      localStorage.removeItem('userPassword');
      localStorage.removeItem('token');

    },
    // userRegister(id: string, pwd: string) {
    //   localStorage.setItem('userId', id);
    //   localStorage.setItem('userPassword', pwd);
    //   this.userId = id;
    //   this.userPassword = pwd;
    // },
    updateUserPassword(newPass: string) {
      this.userPassword = newPass;
      localStorage.setItem('userPassword', newPass);
    },

  },
});

const useFileStore = defineStore({
  id: "file",
  state: () => ({
    selected: false,
  }),
  getters: {
    getSelected(state) {
      return state.selected;
    },
  },
  actions: {
    setSelected(s: boolean) {
      this.selected = s;
    }
  },
});

export { useLoginStore, useFileStore };

sidecolumn.vue

<template>
  <div class="custom-tree-container">
    <el-menu default-active="2" class="el-menu-vertical-demo">
      <el-input v-model="query" placeholder="Please enter keyword" style="width: 220px" />

      <el-tree ref="treeRef" :data="dataSource" :props="props" :filter-node-method="filterMethod" :height="720"
        node-key="id" default-expand-all @node-contextmenu="RightClick" @node-click="LeftClick" highlight-current>
        <template #default="{ node, data }">
          <el-icon>
            <folder v-if="data.type == FileType.folder || data.type == FileType.root"></folder>
            <document v-else></document>
          </el-icon>
          <span>{{ node.label }}</span>
        </template>
      </el-tree>

      <el-card v-show="visible" id="menu" shadow="always"
        :style="{ position: 'fixed', left: mouseX + 'px', top: mouseY + 'px', zIndex: '999', cursor: 'pointer' }">
        <div>
          <el-button type="text" @click="AddFoloder()"
            v-show="targetData?.type === FileType.folder || targetData?.type === FileType.root">add new folder
          </el-button>
        </div>
        <div>
          <el-button type="text" @click="AddFile()"
            v-show="targetData?.type === FileType.folder || targetData?.type === FileType.root">add new file
          </el-button>
        </div>
        <div>
          <el-button type="text" @click="Delete()" v-show="targetData?.type != FileType.root">delete</el-button>
        </div>
        <div>
          <el-button type="text" @click="Rename()">rename</el-button>
        </div>
      </el-card>
    </el-menu>
  </div>
</template>

<script lang="ts" setup>
import { ref, watch } from 'vue'
import type { ElTree } from 'element-plus'
import type Node from 'element-plus/es/components/tree/src/model/node'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fileTypes, FileType } from '../fileziper';
import { Folder, Document } from '@element-plus/icons-vue';
import { useFileStore } from '@/stores/store';

const store = useFileStore();
interface Tree {
  id: string
  name: string
  type: FileType
  children: Tree[]
  value?: string
}

const visible = ref(false)

const query = ref('')
const treeRef = ref<InstanceType<typeof ElTree>>()
const targetData = ref<Tree>()
const targetNode = ref<Node>()
const selectedData = ref<Tree>()
const totalId = ref(0);
const mouseX = ref(0)
const mouseY = ref(0)
const props = {
  value: 'id',
  label: 'name',
  children: 'children',
}
const dataSource = ref<Tree[]>
  ([
    {
      id: `${totalId.value++}`, name: 'Web', type: FileType.root, children:
        [
          {
            id: `${totalId.value++}`, name: 'src', type: FileType.folder, children:
              [
                {
                  id: `${totalId.value++}`, name: 'main.js', type: FileType.ts, children: [], value: ''
                },
                {
                  id: `${totalId.value++}`, name: 'main.html', type: FileType.html, children: [], value: ''
                },
                {
                  id: `${totalId.value++}`, name: 'main.css', type: FileType.css, children: [], value: ''
                },
                {
                  id: `${totalId.value++}`, name: 'README.md', type: FileType.md, children: [], value: ''
                }
              ]
          },
          {
            id: `${totalId.value++}`, name: 'public', type: FileType.folder, children:
              [
                {
                  id: `${totalId.value++}`, name: 'README.md', type: FileType.md, children: [], value: ''
                }
              ]
          }
        ]
    }

  ])


watch(query, (val) => {
  treeRef.value!.filter(val)
})
const filterMethod = (query: string, data: Tree) => {
  if (!query) return true;
  return data.name!.includes(query)
}
const RightClick = function (e: PointerEvent, data: Tree, node: Node) {
  visible.value = true;
  targetData.value = data;
  targetNode.value = node;
  mouseX.value = e.clientX;
  mouseY.value = e.clientY;
  document.addEventListener('click', cancelRightClick)
}

const LeftClick = function (data: Tree) {
  visible.value = false;

  if (data.type != FileType.folder && data.type != FileType.root) {
    selectedData.value = data;
    store.setSelected(true);
    emit("setFileContext", selectedData.value.value, selectedData.value.type);
  }
}

const cancelRightClick = function () {
  visible.value = false;
  document.removeEventListener('click', cancelRightClick);
}

const AddFile = () => {
  ElMessageBox.prompt('Please input folder of file(name.type)', 'Add new file', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputPattern:
      /[\w!#$%&'*+/=?^_`{|}~-]+(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
    inputErrorMessage: 'Please input file(name.type)',
  })
    .then(({ value }) => {
      const val = value.split(".");
      let type = val[val.length - 1];
      let fileType = fileTypes(type);
      if (fileType != undefined) {
        targetData.value!.children.push({
          id: `${totalId.value++}`,
          name: value,
          type: fileType,
          children: [],
          value: ''
        })
        dataSource.value = [...dataSource.value]
      } else {
        ElMessage({
          type: 'error',
          message: `not support this type`,
        })
      }
      // ElMessage({
      //   type: 'success',
      //   message: `Your file is:${value}`,
      // })
    })
    .catch(() => {

    })
}
const AddFoloder = () => {
  ElMessageBox.prompt('Please input folder', 'Add new folder', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputPattern:
      /[\w!#$%&'*+/=?^_`{|}~-]?/,
    inputErrorMessage: 'Please input folder',
  })
    .then(({ value }) => {
      targetData.value!.children.push({
        id: `${totalId.value++}`,
        name: value,
        type: FileType.folder,
        children: []
      })
      dataSource.value = [...dataSource.value]
      // ElMessage({
      //   type: 'success',
      //   message: `Your folder is:${value}`,
      // })
    })
    .catch(() => {
    })
}
const Delete = function () {
  ElMessageBox.confirm('You will delete the file,continue?', 'Warning',
    {
      confirmButtonText: 'OK',
      cancelButtonText: 'Cancel',
      type: 'warning',
    })
    .then(() => {
      const parent = targetNode.value?.parent
      const children: Tree[] = parent?.data.children || parent?.data
      const index = children.findIndex((d) => d.id === targetData.value?.id)
      children.splice(index, 1)
      dataSource.value = [...dataSource.value]
      selectedData.value = undefined;
      store.setSelected(false);
    })
    .catch(() => {
    })
}
const Rename = function () {
  const isFolder = targetData.value?.type === FileType.folder || targetData.value?.type === FileType.root;
  ElMessageBox.prompt('Please input new name', 'Rename', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputPattern: isFolder
      ? /[\w!#$%&'*+/=?^_`{|}~-]?/ : /[\w!#$%&'*+/=?^_`{|}~-]+(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
    inputErrorMessage: 'Please input correct name',
  })
    .then(({ value }) => {
      let fileType;
      if (!isFolder) {
        const val = value.split(".");
        let type = val[val.length - 1];
        fileType = fileTypes(type);
      } else
        fileType = FileType.folder;
      if (fileType != undefined) {
        targetData.value!.name = value;
        dataSource.value = [...dataSource.value]
      } else {
        ElMessage({
          type: 'error',
          message: `not support this type`,
        })
      }
      // ElMessage({
      //   type: 'success',
      //   message: `Your folder is:${value}`,
      // })
    })
    .catch(() => {
    })
}
const emit = defineEmits(['setFileContext']);
const setCode = (value: string) => {
  if (selectedData.value != null) {
    selectedData.value.value = value;
  }
}
const getData = () => {
  return dataSource.value[0].children;
}
const getProjectName = () => {
  return dataSource.value[0].name;
}
defineExpose({ setCode, getData, getProjectName })
</script>

<style>
.dialog-footer button:first-child {
  margin-right: 10px;
}
</style>

btns.vue

<template>
  <div class="flex">
    <el-space wrap :size="size">
      <el-button size="large" type="primary" @click="Submit">提交</el-button>
      <!--    <el-button type="primary">-->
      <!--      Upload<el-icon class="el-icon&#45;&#45;right"><Upload /></el-icon>-->
      <!--    </el-button>-->
    </el-space>
    <el-button size="large" type="primary">刷新</el-button>
  </div>
</template>

<script setup lang="ts">
import { Edit, Share, Delete, Search, Upload } from '@element-plus/icons-vue'
import { ref } from 'vue'


const size = ref(20)
const Submit = function () {
  emit('SaveZIP')
}
const emit = defineEmits(['SaveZIP']);
</script>

<style scoped>
</style>

fileziper.ts

import JSZip from 'jszip';
import { saveAs } from 'file-saver';

enum FileType {
    root,
    folder,
    ts,
    js,
    html,
    css,
    md,
    txt,
}
const fileTypes = function (type: string): FileType | undefined {
    switch (type) {
        case "folder":
            return FileType.folder;
        case "ts":
            return FileType.ts;
        case "js":
            return FileType.js;
        case "html":
            return FileType.html;
        case "css":
            return FileType.css;
        case "md":
            return FileType.md;
        case "txt":
            return FileType.txt;
        default:
            return undefined
    }
}
class Ziper {
    projName: string = 'web';
    zip: any;
    constructor() {
        this.zip = new JSZip();
    }
    setProjectName(name: string) {
        this.projName = name;
    }
    updateProject(data: any, parent = this.zip) {
        for (var item in data) {
            if (data[item].type == FileType.folder) {
                let pa = this._addFolder(parent, data[item].name)
                this.updateProject(data[item].children, pa);
            } else {
                this._addFile(parent, data[item].name, data[item].value);
            }
        }
    }
    _addFile(parent: any, name: string, value: string) {
        parent.file(name, value);
    }
    _addFolder(parent: any, name: string) {
        return parent.folder(name);
    }
    _saveZIP() {
        let projName = this.projName;
        this.zip.generateAsync({ type: "blob" })
            .then(function (blob: any) {
                saveAs(blob, projName);
            });
    }
}
const ziper = new Ziper();


export { ziper, FileType, fileTypes };

修改文件命名相同问题

const AddFile = () => {
  ElMessageBox.prompt('Please input folder of file(name.type)', 'Add new file', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputPattern:
      /[\w!#$%&'*+/=?^_`{|}~-]+(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
    inputErrorMessage: 'Please input file(name.type)',
  })
    .then(({ value }) => {
      const val = value.split(".");
      let type = val[val.length - 1];
      let fileType = fileTypes(type);
      if (fileType != undefined) {
        if (targetData.value != null) {
          for (let i = 0; i < targetData.value.children.length; i++) {
            if (fileType == targetData.value.children[i].type&&value == targetData.value.children[i].name)
              throw false;
          }
        }

        targetData.value!.children.push({
          id: `${totalId.value++}`,
          name: value,
          type: fileType,
          children: [],
          value: ''
        })
        dataSource.value = [...dataSource.value]
      } else {
        ElMessage({
          type: 'error',
          message: `not support this type`,
        })
      }
      // ElMessage({
      //   type: 'success',
      //   message: `Your file is:${value}`,
      // })
    })
    .catch(() => {
      ElMessage({
        type: 'error',
        message: "file already exist",
      })
    })
}
const AddFoloder = () => {
  ElMessageBox.prompt('Please input folder', 'Add new folder', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputPattern:
      /[\w!#$%&'*+/=?^_`{|}~-]?/,
    inputErrorMessage: 'Please input folder',
  })
    .then(({ value }) => {
      if (targetData.value != null) {
        for (let i = 0; i < targetData.value.children.length; i++) {
          if (targetData.value.children[i].type == FileType.folder && value == targetData.value.children[i].name)
            throw false;
        }
      }
      targetData.value!.children.push({
        id: `${totalId.value++}`,
        name: value,
        type: FileType.folder,
        children: []
      })
      dataSource.value = [...dataSource.value]
      // ElMessage({
      //   type: 'success',
      //   message: `Your folder is:${value}`,
      // })
    })
    .catch(() => {
      ElMessage({
        type: 'error',
        message: "folder already exist",
      })
    })
}
const Rename = function () {
  const isFolder = targetData.value?.type === FileType.folder || targetData.value?.type === FileType.root;
  ElMessageBox.prompt('Please input new name', 'Rename', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputPattern: isFolder
      ? /[\w!#$%&'*+/=?^_`{|}~-]?/ : /[\w!#$%&'*+/=?^_`{|}~-]+(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
    inputErrorMessage: 'Please input correct name',
  })
    .then(({ value }) => {
      let fileType;
      const pa = targetNode.value?.parent.data.children;
      if (!isFolder) {
        const val = value.split(".");
        let type = val[val.length - 1];
        fileType = fileTypes(type);

        for (let i = 0; i < pa.length; i++) {
          if (value == pa[i].name && fileType == pa[i].type)
            throw false;
        }
      } else {
        for (let i = 0; i < pa.length; i++) {
          if (pa[i].type == FileType.folder && value == pa[i].name)
            throw false;
        }
        fileType = FileType.folder;
      }

      if (fileType != undefined) {
        targetData.value!.name = value;
        dataSource.value = [...dataSource.value]
      } else {
        ElMessage({
          type: 'error',
          message: `not support this type`,
        })
      }
      // ElMessage({
      //   type: 'success',
      //   message: `Your folder is:${value}`,
      // })
    })
    .catch(() => {
    })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值