靳炳淑 6 лет назад
Родитель
Сommit
fa0afe2361

+ 7 - 0
src/components/CodeInterpreter/Editor/index.vue

@@ -43,6 +43,7 @@ export default {
       }
     }
   },
+  watch: {},
   data() {
     return {
       themeOption: [
@@ -83,6 +84,10 @@ export default {
     },
     RunResult() {
       console.log(this.monacoEditor.getValue());
+    },
+    resetCode(code) {
+      this.codesCopy = code;
+      this.initEditor();
     }
     // themeChange(val) {
     //   this.initEditor();
@@ -94,6 +99,8 @@ export default {
     window.addEventListener("resize", function() {
       self.initEditor();
     });
+    this.codesCopy = this.codes;
+    console.log("editor mount", this.codes);
     this.initEditor();
   }
 };

+ 76 - 23
src/components/CodeInterpreter/index.vue

@@ -1,25 +1,46 @@
 <template>
-  <div class="code-itp">
-    <div id="editor-container">
-      <div class="editor-title">
-        <b-tag type="is-primary">源代码</b-tag>
-        <b-button @click="handleSubmit" type="is-success" size="is-small"
-          >运行</b-button
-        >
+  <div class="question-board">
+    <div class="instruction">
+      <b-tag>题目要求</b-tag>
+      <p>{{ instruction }}</p>
+    </div>
+    <div class="code-itp">
+      <div id="editor-container">
+        <div class="editor-title">
+          <div>
+            <b-tag type="is-primary">源代码</b-tag>
+            <b-button
+              id="resetButton"
+              @click="handleReset"
+              type="is-success"
+              size="is-small"
+              icon-right="reload"
+              rounded
+              outlined
+              >reset</b-button
+            >
+          </div>
+          <b-button @click="handleSubmit" type="is-success" size="is-small"
+            >运行</b-button
+          >
+        </div>
+        <div class="editor-wrapper">
+          <editor
+            ref="editor"
+            :language="'html'"
+            :codes="htmlCodes"
+            @onMounted="htmlOnMounted"
+            @onCodeChange="htmlOnCodeChange"
+          />
+        </div>
       </div>
-      <div class="editor-wrapper">
-        <editor
-          :language="'html'"
-          :codes="htmlCodes"
-          @onMounted="htmlOnMounted"
-          @onCodeChange="htmlOnCodeChange"
-        />
+      <div id="iframe-container">
+        <div class="iframe-title">
+          <b-tag type="is-primary">运行结果</b-tag>
+        </div>
+        <div id="iframe-wrapper"></div>
       </div>
     </div>
-    <div id="iframe-container">
-      <div class="iframe-title"><b-tag type="is-primary">运行结果</b-tag></div>
-      <div id="iframe-wrapper"></div>
-    </div>
   </div>
 </template>
 
@@ -30,11 +51,21 @@ export default {
   components: {
     Editor
   },
-  props: {},
+  watch: {
+    initialCode: {
+      handler: function(newVal) {
+        this.htmlCodes = newVal;
+      },
+      immediate: true
+    }
+  },
+  props: {
+    instruction: String,
+    initialCode: String
+  },
   data() {
     return {
-      htmlCodes:
-        '<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<meta charset="utf-8">\r\n<title>SEEC WEB</title>\r\n<style>\r\nbody\r\n{\r\n\tbackground-color:#d0e4fe;\r\n}\r\nh1\r\n{\r\n\tcolor:orange;\r\n\ttext-align:center;\r\n}\r\np\r\n{\r\n\tfont-family:"Times New Roman";\r\n\tfont-size:20px;\r\n}\r\n</style>\r\n</head>\r\n\r\n<body>\r\n\r\n<h1>CSS \u5b9e\u4f8b!</h1>\r\n<p>Hello, World</p>\r\n\r\n</body>\r\n</html>\r\n',
+      htmlCodes: "",
       htmlEditor: null
     };
   },
@@ -88,6 +119,10 @@ export default {
     },
     htmlOnCodeChange(value) {
       this.htmlCodes = value;
+    },
+    handleReset() {
+      this.htmlCodes = this.initialCode;
+      this.$refs["editor"].resetCode(this.htmlCodes);
     }
   }
 };
@@ -96,12 +131,26 @@ export default {
 <style lang="scss" scoped>
 @import "../../assets/scss/app";
 
+.question-board {
+  border: $default-border;
+  padding: 10px 10px 10px 10px;
+}
+
+.instruction {
+  display: flex;
+  align-items: center;
+  p {
+    font-size: $size-small;
+    color: $text;
+    margin-left: 12px;
+  }
+}
+
 .code-itp {
   display: flex;
-  padding: 0px 10px 10px 10px;
   background-color: $default-background;
-  border: $default-border;
 }
+
 #editor-container {
   width: 50%;
   margin: 10px;
@@ -115,6 +164,10 @@ export default {
   margin: 10px 0;
   display: flex;
   justify-content: space-between;
+
+  #resetButton {
+    margin-left: 10px;
+  }
 }
 .editor-wrapper {
   box-shadow: $default-shadow-darker;

+ 275 - 0
src/components/GitGraph/index.vue

@@ -0,0 +1,275 @@
+<template>
+  <div class="git-graph-body">
+    <div class="command-container">
+      <div class="command-box" ref="command-box">
+        <b-field
+          v-for="c in commandHistory"
+          v-bind:key="c.id"
+          :type="c.result"
+          :message="c.info"
+        >
+          <b-input v-model="c.value" size="is-small" readOnly></b-input>
+        </b-field>
+      </div>
+      <b-field>
+        <!-- keypress事件 屏蔽中文输入法的enter -->
+        <b-input
+          id="command-input"
+          placeholder="git"
+          v-model="commandInput"
+          @keypress.enter.native="handleCommand"
+        ></b-input>
+      </b-field>
+    </div>
+    <!--分支图-->
+    <div class="gitgraph-container"><div id="gitgraph"></div></div>
+  </div>
+</template>
+
+<script>
+import { createGitgraph, templateExtend, TemplateName } from "@gitgraph/js";
+export default {
+  name: "GitGraph",
+  components: {},
+  props: {},
+  watch: {},
+  data() {
+    return {
+      commandInput: "",
+      commandHistory: [],
+      fastCommandPointer: 0, // 上下按键访问历史命令
+      branchList: [],
+      currentBranchName: ""
+    };
+  },
+  methods: {
+    /** 解析命令相关方法 */
+    handleCommand(event) {
+      //1 分词
+      let command = event.target.value;
+      command = command.trim();
+      let array = command.split(" ");
+      array = array.filter(i => i.length > 0);
+      console.log("array:", array);
+
+      //2 检测开头的 ‘git’
+      if (array.length < 1) {
+        this.commandWrong(command);
+        return;
+      }
+      if (array[0] !== "git") {
+        console.log("invalid command");
+        this.commandWrong(command);
+        return;
+      }
+
+      //3 检测第一个词
+      if (array.length < 2) {
+        this.commandWrong(command);
+        return;
+      }
+      //-*- git branch
+      if (array[1] === "branch") {
+        if (array.length === 3) {
+          // git branch master
+          this.makeBranch(array[2], command);
+          return;
+        } else {
+          this.commandWrong(command);
+          return;
+        }
+      }
+      //-*- git commit
+      else if (array[1] === "commit") {
+        if (array.length === 2) {
+          this.makeCommit(this.currentBranchName, "", command);
+          return;
+        } else if (array.length === 4 && array[2] === "-m") {
+          this.makeCommit(this.currentBranchName, array[3], command);
+          return;
+        } else {
+          this.commandWrong(command);
+          return;
+        }
+      }
+      //-*- git checkout
+      else if (array[1] === "checkout") {
+        if (array.length === 3) {
+          // git checkout master
+          this.makeCheckout(array[2], command);
+        } else if (array.length === 4 && array[2] === "-b") {
+          // git checkout -b dev
+          let step1 = this.makeBranch(array[3], command, true); // selfUse = true
+          if (step1) {
+            this.makeCheckout(array[3], command);
+          }
+        } else {
+          this.commandWrong(command);
+          return;
+        }
+      }
+      //-*- git merge
+      else if (array[1] === "merge") {
+        if (array.length === 3) {
+          // git merge dev
+          this.makeMerge(array[2], command);
+        } else {
+          this.commandWrong(command);
+          return;
+        }
+      }
+      //-*- 不存在或暂时不支持的command
+      else {
+        this.commandWrong(command, "不存在或暂不支持的命令");
+        return;
+      }
+    },
+
+    commandCorrect(command) {
+      let cmd = {
+        id: this.commandHistory.length,
+        value: command,
+        result: "is-success"
+      };
+      this.recordCommand(cmd);
+      this.clearInput();
+    },
+    commandWrong(command, info = "invalid command") {
+      let cmd = {
+        id: this.commandHistory.length,
+        value: command,
+        result: "is-danger",
+        info: info
+      };
+      this.recordCommand(cmd);
+      this.clearInput();
+    },
+    clearInput() {
+      this.commandInput = "";
+    },
+    recordCommand(command) {
+      this.commandHistory.push(command);
+      this.fastCommandPointer = this.commandHistory.length - 1;
+      console.log(
+        this.$refs["command-box"].scrollTop,
+        this.$refs["command-box"].scrollHeight
+      );
+      this.$nextTick(() => {
+        this.$refs["command-box"].scrollTop = this.$refs[
+          "command-box"
+        ].scrollHeight;
+      });
+    },
+    /** 画图相关方法 */
+    makeBranch(branchName, command, selfUse) {
+      console.log("makeBranch", branchName);
+      let branchExist = this.branchList.find(item => item.name === branchName);
+      if (branchExist) {
+        this.commandWrong(command, "branch exist");
+        return false;
+      } else {
+        let newBranch = this.gitGraph.branch(branchName);
+        this.branchList.push(newBranch);
+        this.currentBranchName = branchName;
+        if (!selfUse) {
+          this.commandCorrect(command);
+        }
+        return true;
+      }
+    },
+    makeCommit(branchName, message, command) {
+      let branchExist = this.branchList.find(item => item.name === branchName);
+      if (branchExist) {
+        branchExist.commit(message);
+        this.commandCorrect(command);
+      } else {
+        this.commandWrong(command, "no branch name" + branchName);
+      }
+    },
+    makeCheckout(branchName, command) {
+      let branchExist = this.branchList.find(item => item.name === branchName);
+      if (branchExist) {
+        this.currentBranchName = branchName;
+        this.commandCorrect(command);
+      } else {
+        this.commandWrong(command, "no branch name" + branchName);
+      }
+    },
+    makePush() {},
+    makeMerge(branchName, command) {
+      let branchExist = this.branchList.find(item => item.name === branchName);
+      if (branchExist) {
+        let currentBranch = this.branchList.find(
+          item => item.name === this.currentBranchName
+        );
+        if (currentBranch) {
+          currentBranch.merge(branchExist);
+          this.commandCorrect(command);
+        } else {
+          this.commandWrong(command, "not on a branch ---should not happen");
+        }
+      } else {
+        this.commandWrong(command, "no branch name" + branchName);
+      }
+    }
+  },
+  mounted() {
+    console.log("GitGraph mounted");
+    let self = this;
+    const myTemplate = templateExtend(TemplateName.BlackArrow, {
+      commit: {
+        message: {
+          displayHash: false,
+          displayAuthor: false
+        }
+      },
+      mode: "compact"
+    });
+    this.gitGraphContainer = document.getElementById("gitgraph");
+    this.gitGraph = createGitgraph(this.gitGraphContainer, {
+      template: myTemplate
+    });
+
+    // ⬆快捷键
+    document.onkeyup = function(e) {
+      if (e.key === "ArrowUp") {
+        self.fastCommandPointer = Math.max(self.fastCommandPointer - 1, 0);
+        self.commandInput = self.commandHistory[self.fastCommandPointer].value;
+      }
+      if (e.key === "ArrowDown") {
+        self.fastCommandPointer = Math.min(
+          self.fastCommandPointer + 1,
+          self.commandHistory.length - 1
+        );
+        self.commandInput = self.commandHistory[self.fastCommandPointer].value;
+      }
+    };
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../assets/scss/app";
+.git-graph-body {
+  display: flex;
+  justify-content: space-between;
+  padding: 10px 20px;
+}
+.command-container {
+  width: 50%;
+  padding: 20px 20px 10px 20px;
+  border: $default-border;
+
+  .command-box {
+    margin: 0 0 50px 0;
+    max-height: 400px;
+    overflow: scroll;
+    padding: 0 10px;
+  }
+}
+.gitgraph-container {
+  width: 50%;
+  margin: 0 0 0 20px;
+  border: $default-border;
+}
+</style>

+ 5 - 3
src/router/routes.js

@@ -111,12 +111,14 @@ export default [
         ]
       },
       {
-        path: "code/:homeworkId/:projectId/test/unit/:unitTestId",
+        path:
+          "code/:homeworkId/:projectId/group/:groupId/test/unit/:unitTestId",
         component: () =>
           import("@/views/student/Code/ProjectDetail/Test/UnitTestDetail")
       },
       {
-        path: "code/:homeworkId/:projectId/test/functional/:functionalTestId",
+        path:
+          "code/:homeworkId/:projectId/group/groupId/test/functional/:functionalTestId",
         component: () =>
           import("@/views/student/Code/ProjectDetail/Test/FunctionalTestDetail")
       },
@@ -265,7 +267,7 @@ export default [
       },
       {
         path: "study/git",
-        component: () => import("@/views/student/StudyWeb")
+        component: () => import("@/views/student/StudyGit")
       }
     ]
   },

+ 21 - 0
src/views/student/StudyGit/index.vue

@@ -0,0 +1,21 @@
+<template>
+  <div>
+    <h2>Study Git</h2>
+    <git-graph></git-graph>
+  </div>
+</template>
+
+<script>
+import GitGraph from "@/components/GitGraph/index";
+export default {
+  components: {
+    GitGraph
+  },
+  data() {
+    return {};
+  },
+  methods: {}
+};
+</script>
+
+<style></style>

+ 14 - 2
src/views/student/StudyWeb/index.vue

@@ -1,5 +1,10 @@
 <template>
-  <div><code-interpreter></code-interpreter></div>
+  <div>
+    <code-interpreter
+      :instruction="question.instruction"
+      :initial-code="question.initialCode"
+    ></code-interpreter>
+  </div>
 </template>
 
 <script>
@@ -14,7 +19,14 @@ export default {
     CodeInterpreter
   },
   data() {
-    return {};
+    return {
+      question: {
+        instruction:
+          "调整<p>的CSS样式,使文字“CSS Exercise字号为18px, 颜色为红色",
+        initialCode:
+          '<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<meta charset="utf-8">\r\n<title>SEEC WEB</title>\r\n<style>\r\nbody\r\n{\r\n\tbackground-color:#d0e4fe;\r\n}\r\nh1\r\n{\r\n\tcolor:orange;\r\n\ttext-align:center;\r\n}\r\np\r\n{\r\n}\r\n</style>\r\n</head>\r\n\r\n<body>\r\n\r\n<h1>SEEC Learing</h1>\r\n<p>CSS Exercise</p>\r\n\r\n</body>\r\n</html>\r\n'
+      }
+    };
   },
   methods: {}
 };