Jelajahi Sumber

feat[wwf]:添加微认证模块

StackWwf 3 tahun lalu
induk
melakukan
cb5d49da1f

+ 150 - 0
package-lock.json

@@ -1220,6 +1220,86 @@
         "to-fast-properties": "^2.0.0"
       }
     },
+    "@codemirror/autocomplete": {
+      "version": "6.5.1",
+      "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.5.1.tgz",
+      "integrity": "sha512-/Sv9yJmqyILbZ26U4LBHnAtbikuVxWUp+rQ8BXuRGtxZfbfKOY/WPbsUtvSP2h0ZUZMlkxV/hqbKRFzowlA6xw==",
+      "requires": {
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.6.0",
+        "@lezer/common": "^1.0.0"
+      }
+    },
+    "@codemirror/commands": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.2.3.tgz",
+      "integrity": "sha512-9uf0g9m2wZyrIim1SavcxMdwsu8wc/y5uSw6JRUBYIGWrN+RY4vSru/BqB+MyNWqx4C2uRhQ/Kh7Pw8lAyT3qQ==",
+      "requires": {
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.2.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0"
+      }
+    },
+    "@codemirror/lang-python": {
+      "version": "6.1.2",
+      "resolved": "https://registry.npmmirror.com/@codemirror/lang-python/-/lang-python-6.1.2.tgz",
+      "integrity": "sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.3.2",
+        "@codemirror/language": "^6.0.0",
+        "@lezer/python": "^1.0.0"
+      }
+    },
+    "@codemirror/language": {
+      "version": "6.6.0",
+      "resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.6.0.tgz",
+      "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==",
+      "requires": {
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0",
+        "style-mod": "^4.0.0"
+      }
+    },
+    "@codemirror/lint": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.2.1.tgz",
+      "integrity": "sha512-y1muai5U/uUPAGRyHMx9mHuHLypPcHWxzlZGknp/U5Mdb5Ol8Q5ZLp67UqyTbNFJJ3unVxZ8iX3g1fMN79S1JQ==",
+      "requires": {
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "crelt": "^1.0.5"
+      }
+    },
+    "@codemirror/search": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmmirror.com/@codemirror/search/-/search-6.3.0.tgz",
+      "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==",
+      "requires": {
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "crelt": "^1.0.5"
+      }
+    },
+    "@codemirror/state": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.2.0.tgz",
+      "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA=="
+    },
+    "@codemirror/view": {
+      "version": "6.9.5",
+      "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.9.5.tgz",
+      "integrity": "sha512-IZwGdkn8PDyMkGms7bCMpFuTCg6+6eCZNgLOe9xQL4RYvMw1yYLviH+qoAqsNoYGpDt4HhHoW9v3FmalobFoKw==",
+      "requires": {
+        "@codemirror/state": "^6.1.4",
+        "style-mod": "^4.0.0",
+        "w3c-keyname": "^2.2.4"
+      }
+    },
     "@element-plus/icons": {
       "version": "0.0.11",
       "resolved": "https://registry.npmjs.org/@element-plus/icons/-/icons-0.0.11.tgz",
@@ -1385,6 +1465,36 @@
         "@jridgewell/sourcemap-codec": "1.4.14"
       }
     },
+    "@lezer/common": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.0.2.tgz",
+      "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng=="
+    },
+    "@lezer/highlight": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.1.4.tgz",
+      "integrity": "sha512-IECkFmw2l7sFcYXrV8iT9GeY4W0fU4CxX0WMwhmhMIVjoDdD1Hr6q3G2NqVtLg/yVe5n7i4menG3tJ2r4eCrPQ==",
+      "requires": {
+        "@lezer/common": "^1.0.0"
+      }
+    },
+    "@lezer/lr": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.3.3.tgz",
+      "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==",
+      "requires": {
+        "@lezer/common": "^1.0.0"
+      }
+    },
+    "@lezer/python": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/@lezer/python/-/python-1.1.4.tgz",
+      "integrity": "sha512-x82XgYxqqX0Yiw7uIemQJ3z2QyQme5BYpectkPfNg99OQrakqfwqVolqEVIrsj4QO9rVDLFZZ49J0Vbne7UbAA==",
+      "requires": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "@mrmlnc/readdir-enhanced": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@@ -4647,6 +4757,20 @@
         "q": "^1.1.2"
       }
     },
+    "codemirror": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmmirror.com/codemirror/-/codemirror-6.0.1.tgz",
+      "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/commands": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/lint": "^6.0.0",
+        "@codemirror/search": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0"
+      }
+    },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -5065,6 +5189,11 @@
         "sha.js": "^2.4.8"
       }
     },
+    "crelt": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/crelt/-/crelt-1.0.5.tgz",
+      "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA=="
+    },
     "cross-spawn": {
       "version": "6.0.5",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -12080,6 +12209,11 @@
       "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
       "dev": true
     },
+    "style-mod": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.0.3.tgz",
+      "integrity": "sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw=="
+    },
     "stylehacks": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
@@ -13159,6 +13293,17 @@
         "@vue/shared": "3.2.45"
       }
     },
+    "vue-codemirror": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmmirror.com/vue-codemirror/-/vue-codemirror-6.1.1.tgz",
+      "integrity": "sha512-rTAYo44owd282yVxKtJtnOi7ERAcXTeviwoPXjIc6K/IQYUsoDkzPvw/JDFtSP6T7Cz/2g3EHaEyeyaQCKoDMg==",
+      "requires": {
+        "@codemirror/commands": "6.x",
+        "@codemirror/language": "6.x",
+        "@codemirror/state": "6.x",
+        "@codemirror/view": "6.x"
+      }
+    },
     "vue-eslint-parser": {
       "version": "7.11.0",
       "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
@@ -13406,6 +13551,11 @@
         "@vue/devtools-api": "^6.0.0-beta.11"
       }
     },
+    "w3c-keyname": {
+      "version": "2.2.6",
+      "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
+      "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg=="
+    },
     "watchpack": {
       "version": "1.7.5",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",

+ 3 - 0
package.json

@@ -7,11 +7,13 @@
     "build": "vue-cli-service build --mode production"
   },
   "dependencies": {
+    "@codemirror/lang-python": "^6.1.2",
     "@element-plus/icons-vue": "0.2.4",
     "ali-oss": "^6.17.1",
     "axios": "^0.25.0",
     "babel-plugin-import": "^1.13.3",
     "clipboard": "^2.0.11",
+    "codemirror": "^6.0.1",
     "core-js": "^3.6.5",
     "dayjs": "^1.11.7",
     "echarts": "^4.8.0",
@@ -23,6 +25,7 @@
     "react": "^18.2.0",
     "resize-detector": "^0.3.0",
     "vue": "^3.1.0",
+    "vue-codemirror": "^6.1.1",
     "vue-pdf": "^4.3.0",
     "vue-pdf-embed": "^1.1.5",
     "vue-pdf-preview": "^0.0.3",

+ 15 - 0
src/router/index.js

@@ -54,6 +54,21 @@ const routes = [
     name: "Course",
     component: () => import("../views/CoursePage/CoursePage.vue"),
   },
+  {
+    path: "/microauth",
+    name: "microAuth",
+    component: () => import("../views/MicroAuthPage/auth.vue"),
+  },
+  {
+    path: "/microauth/detail",
+    name: "microAuthDetail",
+    component: () => import("../views/MicroAuthPage/detail.vue"),
+  },
+  {
+    path: "/microauth/detail/practice",
+    name: "microAuthPractice",
+    component: () => import("../views/MicroAuthPage/practiceDetail.vue"),
+  },
   {
     path: "/course/:id",
     name: "CourseDetail",

+ 14 - 2
src/views/CoursePage/CoursePage.vue

@@ -21,6 +21,12 @@
             </el-icon>
             <span style="padding-left: 20px">我的课程</span>
           </el-menu-item>
+          <el-menu-item index="3">
+            <el-icon>
+              <FolderChecked/>
+            </el-icon>
+            <span style="padding-left: 20px">微认证</span>
+          </el-menu-item>
         </el-menu>
       </el-card>
     </el-col>
@@ -38,6 +44,9 @@
         <div v-if="this.activeIndex === '2' && isStudent" class="course-page-main">
           <CourseCard v-for="course in courses_my" :key="course.id" :courseVO="course"/>
         </div>
+        <div v-if="this.activeIndex === '3'" >
+          <MicroAuth></MicroAuth>
+        </div>
         <div v-if="this.activeIndex === '2' && isTeacher">
           教师请前往
           <span style="cursor: pointer;color: #409eff"
@@ -57,10 +66,11 @@
 <script>
 import {Back, Folder, FolderChecked} from "@element-plus/icons-vue";
 import CourseCard from "@/components/CourseCard";
+import MicroAuth from "../MicroAuthPage/auth.vue";
 
 export default {
   name: "CoursePage",
-  components: {FolderChecked, Folder, Back, CourseCard},
+  components: {FolderChecked, Folder, Back, CourseCard,MicroAuth},
   data() {
     return {
       activeIndex: "1",
@@ -72,7 +82,9 @@ export default {
     activeName() {
       if (this.activeIndex === "1") {
         return this.isLogin ? "全部课程" : "公开课程";
-      } else {
+      } else if(this.activeIndex==="3"){
+        return "微认证";
+      }else {
         return "我的课程";
       }
     },

+ 13 - 4
src/views/ManagePage/ManagePage.vue

@@ -393,7 +393,7 @@
       />
     </el-dialog>
 
-    <el-dialog v-model="uploadFileDialog" :width="1000">
+    <el-dialog destroy-on-close v-model="uploadFileDialog" :width="1000">
       <el-form
           ref="form"
           :model="uploadFileForm"
@@ -997,9 +997,18 @@ export default {
       body.append("data", this.uploadFiles[0].raw);
       this.$apis.createCoderProblem(body)
           .then((data) => {
-            ElMessage.success("创建Coder代码题成功");
-            this.loading = false;
-            this.uploadFileDialog = false;
+            console.log("uploadFileDataRes",data.data);
+            if(data.data.err===0){
+              ElMessage.success("创建Coder代码题成功");
+              this.loading = false;
+              this.uploadFileDialog = false;
+              this.fetchProblemData();
+            }else{
+              ElMessage.error("创建Coder代码题失败:"+data.data.msg);
+              this.loading = false;
+            }
+
+
             // this.problemList.push()
             // this.$nuxt.$router.push("/problem/" + data.res?.id);
           })

+ 278 - 0
src/views/MicroAuthPage/assessDetail.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="bg">
+    <div class="bigContainer">
+      <p class="bigTitle">安卓开发实践</p>
+
+      <div class="totalInfo">
+        <div class="totalInfoLeft">
+          <div class="totalInfoLeft1">
+            <span>所属微认证:安卓开发微认证</span>
+            <span style="margin-left: 50px">完成度:20%</span>
+          </div>
+          <div class="totalInfoLeft2">
+            <span>源代码地址:</span>
+            <span style="color: dodgerblue">https://p.seec.seecoder.cn/exam/9511</span>
+            <el-button class="miniButton">复制</el-button>
+          </div>
+        </div>
+        <div class="totalInfoRight">
+          <el-button class="buildButton">触发构建</el-button>
+        </div>
+      </div>
+
+      <div class="record" >
+        <el-collapse>
+          <el-collapse-item class="collapse">
+            <template #title>
+              <p class="subTitle">
+                构建记录
+              </p>
+            </template>
+            <el-table :data="buildData" style="width: 100%">
+              <el-table-column prop="id" label="id"  />
+              <el-table-column prop="buildTime" label="构建时间"  />
+              <el-table-column prop="status" label="状态" />
+              <el-table-column prop="pkg" label="产物包">
+                <template #default="scope">
+                  <a class="pkgUrl" :src=scope.row.pkg >{{scope.row.pkg}}</a>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-collapse-item>
+        </el-collapse>
+      </div>
+
+      <div class="record" >
+        <div class="recordHeader">
+          <div class="recordHeaderLeft">
+            <p class="subTitle" style="margin-top: 0px">
+              自动化测试
+            </p>
+            <div class="autoTestRecord" style="margin-top: -20px">
+              选择产物包:
+              <el-radio-group v-model="radio" style="color:#000;">
+                <el-radio :label="1" style="color:#000;">2-package.apk</el-radio>
+                <el-radio :label="2" style="color:#000;">3-package.apk</el-radio>
+              </el-radio-group>
+
+            </div>
+          </div>
+          <div class="recordHeaderRight">
+            <el-button class="buildButton">触发测试</el-button>
+          </div>
+        </div>
+
+        <el-collapse>
+          <el-collapse-item class="collapse">
+            <template #title>
+              <p class="subsubTitle">
+                测试脚本
+              </p>
+            </template>
+            <codemirror
+                placeholder="Code gose here..."
+                :mode="lang-python"
+            />
+          </el-collapse-item>
+        </el-collapse>
+      </div>
+
+      <div class="record" >
+        <el-collapse>
+          <el-collapse-item class="collapse">
+            <template #title>
+              <p class="subTitle">
+                测试记录
+              </p>
+            </template>
+            <el-table :data="testData" style="width: 100%">
+              <el-table-column prop="id" label="id"  />
+              <el-table-column prop="testTime" label="测试时间"  />
+              <el-table-column prop="status" label="状态" />
+              <el-table-column prop="testRes" label="测试结果" />
+            </el-table>
+          </el-collapse-item>
+        </el-collapse>
+      </div>
+    </div>
+    <div style="height: 150px">
+
+    </div>
+  </div>
+</template>
+
+<script>
+import {ref} from "vue";
+import { Codemirror } from "vue-codemirror";
+import { python} from "@codemirror/lang-python";
+import {Back, Folder, FolderChecked} from "@element-plus/icons-vue";
+import CourseCard from "@/components/CourseCard";
+import MicroAuth from "@/views/MicroAuthPage/auth";
+
+export default {
+  components: {Codemirror},
+  data(){
+    return {
+      buildData:[
+        {
+          id:1,
+          buildTime:"2023-4-20 15:20",
+          status:"正在构建",
+          pkg:"-"
+        },
+        {
+          id:2,
+          buildTime:"2023-4-20 15:20",
+          status:"构建成功",
+          pkg:"2-package.apk"
+        }
+      ],
+      testData :[
+        {
+          id:1,
+          testTime:"2023-4-20 15:20",
+          status:"正在测试",
+          testRes:"-"
+        },
+        {
+          id:2,
+          testTime:"2023-4-20 15:20",
+          status:"测试成功",
+          testRes:"80"
+        }
+      ],
+      radio:1
+    };
+  },
+};
+
+</script>
+
+<style scoped>
+.bg{
+  background-image: linear-gradient(to bottom right, #C3D7DF, #FFFFFF);
+  overflow: hidden;
+  width: 100%;
+}
+
+.bigContainer{
+  padding: 80px 150px 0 150px;
+}
+
+.bigTitle{
+  font-size: xxx-large;
+  font-weight: bold;
+}
+
+.subTitle{
+  font-size: x-large;
+}
+
+.subsubTitle{
+  font-size: large;
+  font-size: medium;
+}
+
+autoTestCard{
+  overflow: hidden;
+}
+
+.pkgUrl{
+  color: dodgerblue;
+  text-decoration: underline;
+}
+
+.totalInfo{
+  padding: 20px;
+  border: #93B5CF solid 1px;
+  display: flex;
+}
+
+.totalInfoLeft{
+  width: 100%;
+}
+
+.totalInfoLeft span{
+  font-size:large;
+}
+
+.totalInfoLeft2{
+  margin-top: 20px;
+}
+
+.miniButton{
+  margin-left: 5px;
+  vertical-align:middle;
+  text-align: center;
+
+}
+
+.totalInfoRight{
+  float:right;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.buildButton{
+  border-color: #93B5CF;
+  background-color: white;
+  color: #93B5CF;
+  font-size: large;
+  width: 150px;
+  height: 50px;
+}
+
+.buildButton:hover{
+  border-color: white;
+  background-color: #93B5CF;
+  color: white;
+  font-size: large;
+  width: 150px;
+  height: 50px;
+}
+
+.record{
+  margin-top: 50px;
+  padding: 20px;
+  border: #93B5CF solid 1px;
+}
+
+.recordHeader{
+  display: flex;
+}
+
+.recordHeaderLeft{
+  width: 100%;
+}
+.recordHeaderRight{
+  float: right;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+:deep(.el-collapse){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+:deep(.el-collapse-item__header is-active){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+:deep(.el-collapse-item__header){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+:deep(.el-collapse-item__content){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+
+
+
+</style>

+ 193 - 0
src/views/MicroAuthPage/auth.vue

@@ -0,0 +1,193 @@
+<template>
+  <div class="bg">
+    <h1>SeeCoder微认证学堂</h1>
+    <div class="mainWrapper">
+      <div class="listGrid">
+        <el-card class="cardMore" v-for="item of list" :key="item.id" @click="jumpToDetail(item.id)">
+          <template #header>
+            <el-tag>
+              {{ item.type }}
+            </el-tag>
+            {{item.name}}
+          </template>
+          <p class="cardP">{{item.desc}}</p>
+          <el-tag type="info">{{item.zone}}</el-tag>
+        </el-card>
+      </div>
+    </div>
+  </div>
+
+</template>
+
+<script>
+
+export default {
+  data() {
+    return {
+      list : [
+        {
+          id:1,
+          name:"HarmonyOS分布式协同办公应用开发",
+          type:"New",
+          zone:"HarmonyOS",
+          desc:"HarmonyOS打造全场景分布式操作系统,助力万物互联,轻松实现跨设备共享服务及应用,灵活定制系统,适配更多设备。"
+        },
+        {
+          id:2,
+          name:"name2",
+          type:"type2",
+          zone:"zone2",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:3,
+          name:"name3",
+          type:"type3",
+          zone:"zone3",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:4,
+          name:"name4",
+          type:"type4",
+          zone:"zone4",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:5,
+          name:"name1",
+          type:"type1",
+          zone:"zone1",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:6,
+          name:"name2",
+          type:"type2",
+          zone:"zone2",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:7,
+          name:"name3",
+          type:"type3",
+          zone:"zone3",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:8,
+          name:"name4",
+          type:"type4",
+          zone:"zone4",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:9,
+          name:"name1",
+          type:"type1",
+          zone:"zone1",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:10,
+          name:"name2",
+          type:"type2",
+          zone:"zone2",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:11,
+          name:"name3",
+          type:"type3",
+          zone:"zone3",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:12,
+          name:"name4",
+          type:"type4",
+          zone:"zone4",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:13,
+          name:"name1",
+          type:"type1",
+          zone:"zone1",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:14,
+          name:"name2",
+          type:"type2",
+          zone:"zone2",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:15,
+          name:"name3",
+          type:"type3",
+          zone:"zone3",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+        {
+          id:16,
+          name:"name4",
+          type:"type4",
+          zone:"zone4",
+          desc:"descdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescdescv"
+        },
+      ],
+    };
+  },
+  methods:{
+    jumpToDetail(){
+      this.$router.push("/microauth/detail");
+    }
+  }
+};
+</script>
+
+<style scoped>
+.bg{
+  background-image: linear-gradient(to bottom right, #C3D7DF, #FFFFFF);
+  overflow: hidden;
+  width: 100%;
+  height: 1200px
+}
+.mainWrapper{
+  margin-top: 50px;
+  margin-left: 10%;
+  /*border: #747bff dashed 5px;*/
+  width: 80%;
+  height: 830px  ;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.listGrid{
+  width: 100%;
+  /*background-color: #747bff;*/
+  height: 100%;
+  display: grid;
+  grid-template-columns: repeat(4,1fr);
+  grid-gap: 10px;
+  grid-template-rows: repeat(4,200px);
+}
+
+.cardP{
+  /*height: 250px;*/
+  margin-top: 5px;
+  width: 100%;
+  word-break: break-all;
+  word-wrap:  break-word;
+}
+
+.cardMore:hover{
+  background-color: aliceblue;
+  cursor:pointer;
+}
+
+
+</style>

+ 269 - 0
src/views/MicroAuthPage/detail.vue

@@ -0,0 +1,269 @@
+<template>
+  <div class="bg">
+    <div class="bigContainer">
+      <p class="bigTitle">HarmonyOS分布式协同办公应用开发</p>
+      <p class="subTitle">HarmonyOS打造全场景分布式操作系统,助力万物互联,轻松实现跨设备共享服务及应用,灵活定制系统,适配更多设备。</p>
+      <div class="characteristicWrap">
+        <div class="characteristic" v-for="item of charas" :key="item.id">
+          <span>{{item.title}}</span>
+          <el-divider />
+          <p>{{ item.desc }}</p>
+        </div>
+      </div>
+      <p class="authProTitle">认证流程-轻松5步:</p>
+      <div class="authProWrap">
+        <div class="onePro">
+          <div class="oneProLeft">
+            <p class="bigTitle">01.</p> <br />
+            <p class="subTitle" style="margin-top: -75px">购买认证</p>
+          </div>
+          <div class="oneProMiddle">
+            <p>1、请使用华为云个人账号或企业主账号购买微认证,不支持企业子账号购买/兑换认证,不支持企业子账号考试;</p>
+            <p>2、如使用兑换码兑换微认证,请点击微认证兑换完成操作,仅支持华为云个人账号兑换认证;</p>
+            <p>3、成功购买微认证后方可进行后续步骤,可在个人主页-我的认证中查看购买/兑换记录;</p>
+          </div>
+          <div class="oneProRight">
+            <el-button class="proButton">
+              购买认证 ¥29.98
+            </el-button>
+          </div>
+        </div>
+        <el-divider/>
+        <div class="onePro">
+          <div class="oneProLeft">
+            <p class="bigTitle">02.</p> <br />
+            <p class="subTitle" style="margin-top: -75px">在线学习</p>
+          </div>
+          <div class="oneProMiddle">
+            <p>通过在线课程学习,掌握理论基础知识</p>
+            <el-table :data="tableData" stripe style="width: 100%" :header-cell-style="{background:'#93B5CF'}">
+              <el-table-column prop="chap" label="章节" width="180" />
+              <el-table-column prop="time" label="时长" width="180" />
+              <el-table-column prop="target" label="学习目标" />
+            </el-table>
+          </div>
+          <div class="oneProRight">
+            <el-button class="proButton">
+              开始学习
+            </el-button>
+          </div>
+        </div>
+        <el-divider/>
+        <div class="onePro">
+          <div class="oneProLeft">
+            <p class="bigTitle">03.</p> <br />
+            <p class="subTitle" style="margin-top: -75px">实验练习</p>
+          </div>
+          <div class="oneProMiddle">
+            <p>每个实验都与课程相匹配,通过实验操作,加深对课程学习内容的理解,获得场景化的技能</p>
+            <p>实验前:  1、购买认证后,如动手实验需要使用付费资源,用户费用中心将获得一张“实验资源代金券”,用于购买实验所需资源;</p>
+            <p style="margin-left: 60px">       2、开始实验前,请下载实验手册,查看手册使用注意事项,并按照手册指引开展实验。</p>
+            <p style="margin-top: 20px">实验中: 1、购买资源时,请按照实验指引选择资源规格和计费模式,华为云将优先使用代金券进行扣费;</p>
+            <p style="margin-left: 60px">       2、为避免实验资源浪费,请一次性完成实验;若无法连续完成,请先删除已购买的资源,避免因资源持续使用而产生扣费;</p>
+            <p style="margin-left: 60px">       3、如遇到问题,可以联系华为云人工客服或拨打4000 955988热线进行求助;您反馈的实验问题,将由客服转接课程老师为您进行答疑;</p>
+            <p style="margin-left: 60px">       4、“实验资源代金券”自认证购买之日起30天内有效,请在有效期内使用。</p>
+            <p style="margin-top: 20px">实验后: 实验结束,请务必按照实验指引手动完成资源释放,避免因资源未及时得到释放而产生持续扣费。</p>
+          </div>
+          <div class="oneProRight">
+            <el-button class="proButton">
+              下载手册
+            </el-button>
+          </div>
+        </div>
+        <div class="onePro">
+          <div class="oneProLeft">
+            <p class="bigTitle">04.</p> <br />
+            <p class="subTitle" style="margin-top: -75px">在线考试</p>
+          </div>
+          <div class="oneProMiddle">
+            <p>1、在线考试需验证考生身份,请提前准备好身份证电子件;</p>
+            <p>2、请使用Google、火狐或360浏览器完成在线考试,不支持IE浏览器</p>
+            <p>3、正式考试前请仔细阅读在线考试注意事项,提前完成邮箱绑定;</p>
+            <p>4、每次购买后将获得5次考试机会,为避免考试次数浪费,再次购买前请确认考试机会已用完。</p>
+          </div>
+          <div class="oneProRight">
+            <el-button class="proButton" @click="jumpToPracticeDetail()">
+              在线考试
+            </el-button>
+          </div>
+        </div>
+        <div class="onePro">
+          <div class="oneProLeft">
+            <p class="bigTitle">05.</p> <br />
+            <p class="subTitle" style="margin-top: -75px">获取证书</p>
+          </div>
+          <div class="oneProMiddle">
+            <p>1、通过考试后24小时,可前往个人主页-我的认证查看证书编号和下载电子证书;</p>
+            <p>2、证书自颁布之日起2年内有效。</p>
+          </div>
+          <div class="oneProRight">
+            <el-button class="proButton">
+              获取证书
+            </el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+
+  </div>
+
+</template>
+
+<script>
+export default {
+  data(){
+    return{
+      charas:[
+        {
+          id:1,
+          title:"适合人群",
+          desc:"HarmonyOS应用开发工程师,以及对鸿蒙生态感兴趣的个人开发者,高校师生"
+        },
+        {
+          id:2,
+          title:"培训方案",
+          desc:"通过为一款备忘录应用添加跨设备流转功能,快速实现“分布式协同办公”应用体验"
+        },
+        {
+          id:3,
+          title:"技术能力",
+          desc:"通过本微认证的理论学习与动手实践操作,掌握HarmonyOS分布式应用开发能力"
+        },
+        {
+          id:4,
+          title:"认证价值",
+          desc:"了解HarmonyOS系统架构与技术特点,掌握HarmonyOS应用开发流程"
+        }
+      ],
+      tableData:[
+        {
+          chap: "HarmonyOS技术优势",
+          time: "29分钟",
+          target: "了解HarmonyOS系统架构、定位与技术特性",
+        },
+        {
+          chap: "HarmonyOS超级终端场景化体验创新",
+          time: "6分钟",
+          target: "了解HarmonyOS行业应用场景与创新体验",
+        },
+        {
+          chap: "分布式协同办公实践",
+          time: "35分钟",
+          target: "掌握HarmonyOS应用程序框架结构与开发流程",
+        }
+      ]
+    };
+  },
+  methods:{
+    jumpToPracticeDetail(){
+      this.$router.push("/microauth/detail/practice");
+    }
+  }
+};
+
+</script>
+
+<style scoped>
+
+.bg{
+  background-image: linear-gradient(to bottom right, #C3D7DF, #FFFFFF);
+  overflow: hidden;
+  width: 100%;
+}
+.bigContainer{
+  padding: 80px 150px 0 150px;
+}
+
+
+.bigTitle{
+  font-size: xxx-large;
+  font-weight: bold;
+}
+
+.subTitle{
+  margin-top: -15px;
+  font-size: x-large;
+}
+
+.authProTitle {
+  font-size: xx-large;
+}
+
+.characteristicWrap{
+  margin-top: 50px;
+  display: flex;
+  background-image: linear-gradient(to bottom right,  #0F59A4,#93B5CF);
+  overflow: hidden;
+}
+
+.characteristic{
+  flex:1;
+  padding: 35px;
+}
+
+.characteristic span{
+  color: #FFFFFF;
+  font-size: x-large;
+}
+
+.characteristic p{
+  color: #FFFFFF;
+  width: 100%;
+  word-break: break-all;
+  word-wrap:  break-word;
+}
+
+.authProWrap{
+  background-color: white;
+}
+
+.proButton{
+  border-color: #93B5CF;
+  background-color: white;
+  color: #93B5CF;
+  font-size: large;
+  width: 150px;
+  height: 50px;
+}
+
+.proButton:hover{
+  border-color: white;
+  background-color: #93B5CF;
+  color: white;
+  font-size: large;
+  width: 150px;
+  height: 50px;
+}
+
+.onePro{
+  display: flex;
+}
+
+.oneProLeft{
+  width: 300px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+
+.oneProMiddle{
+  padding-top:35px;
+  width: 100%;
+}
+
+.oneProRight p{
+  width: 100%;
+  word-break: break-all;
+  word-wrap:  break-word;
+}
+
+.oneProRight{
+  width: 300px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+</style>

+ 278 - 0
src/views/MicroAuthPage/practiceDetail.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="bg">
+    <div class="bigContainer">
+      <p class="bigTitle">安卓开发实践</p>
+
+      <div class="totalInfo">
+        <div class="totalInfoLeft">
+          <div class="totalInfoLeft1">
+            <span>所属微认证:安卓开发微认证</span>
+            <span style="margin-left: 50px">完成度:20%</span>
+          </div>
+          <div class="totalInfoLeft2">
+            <span>源代码地址:</span>
+            <span style="color: dodgerblue">https://p.seec.seecoder.cn/exam/9511</span>
+            <el-button class="miniButton">复制</el-button>
+          </div>
+        </div>
+        <div class="totalInfoRight">
+          <el-button class="buildButton">触发构建</el-button>
+        </div>
+      </div>
+
+      <div class="record" >
+        <el-collapse>
+          <el-collapse-item class="collapse">
+            <template #title>
+              <p class="subTitle">
+                构建记录
+              </p>
+            </template>
+            <el-table :data="buildData" style="width: 100%">
+              <el-table-column prop="id" label="id"  />
+              <el-table-column prop="buildTime" label="构建时间"  />
+              <el-table-column prop="status" label="状态" />
+              <el-table-column prop="pkg" label="产物包">
+                <template #default="scope">
+                  <a class="pkgUrl" :src=scope.row.pkg >{{scope.row.pkg}}</a>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-collapse-item>
+        </el-collapse>
+      </div>
+
+      <div class="record" >
+        <div class="recordHeader">
+          <div class="recordHeaderLeft">
+            <p class="subTitle" style="margin-top: 0px">
+              自动化测试
+            </p>
+            <div class="autoTestRecord" style="margin-top: -20px">
+              选择产物包:
+              <el-radio-group v-model="radio" style="color:#000;">
+                <el-radio :label="1" style="color:#000;">2-package.apk</el-radio>
+                <el-radio :label="2" style="color:#000;">3-package.apk</el-radio>
+              </el-radio-group>
+
+            </div>
+          </div>
+          <div class="recordHeaderRight">
+            <el-button class="buildButton">触发测试</el-button>
+          </div>
+        </div>
+
+        <el-collapse>
+          <el-collapse-item class="collapse">
+            <template #title>
+                <p class="subsubTitle">
+                  测试脚本
+                </p>
+            </template>
+            <codemirror
+                placeholder="Code gose here..."
+                :mode="lang-python"
+            />
+          </el-collapse-item>
+        </el-collapse>
+      </div>
+
+      <div class="record" >
+        <el-collapse>
+          <el-collapse-item class="collapse">
+            <template #title>
+              <p class="subTitle">
+                测试记录
+              </p>
+            </template>
+            <el-table :data="testData" style="width: 100%">
+              <el-table-column prop="id" label="id"  />
+              <el-table-column prop="testTime" label="测试时间"  />
+              <el-table-column prop="status" label="状态" />
+              <el-table-column prop="testRes" label="测试结果" />
+            </el-table>
+          </el-collapse-item>
+        </el-collapse>
+      </div>
+    </div>
+    <div style="height: 150px">
+
+    </div>
+  </div>
+</template>
+
+<script>
+import {ref} from "vue";
+import { Codemirror } from "vue-codemirror";
+import { python} from "@codemirror/lang-python";
+import {Back, Folder, FolderChecked} from "@element-plus/icons-vue";
+import CourseCard from "@/components/CourseCard";
+import MicroAuth from "@/views/MicroAuthPage/auth";
+
+export default {
+  components: {Codemirror},
+  data(){
+    return {
+      buildData:[
+        {
+          id:1,
+          buildTime:"2023-4-20 15:20",
+          status:"正在构建",
+          pkg:"-"
+        },
+        {
+          id:2,
+          buildTime:"2023-4-20 15:20",
+          status:"构建成功",
+          pkg:"2-package.apk"
+        }
+      ],
+      testData :[
+        {
+          id:1,
+          testTime:"2023-4-20 15:20",
+          status:"正在测试",
+          testRes:"-"
+        },
+        {
+          id:2,
+          testTime:"2023-4-20 15:20",
+          status:"测试成功",
+          testRes:"80"
+        }
+      ],
+      radio:1
+    };
+  },
+};
+
+</script>
+
+<style scoped>
+.bg{
+  background-image: linear-gradient(to bottom right, #C3D7DF, #FFFFFF);
+  overflow: hidden;
+  width: 100%;
+}
+
+.bigContainer{
+  padding: 80px 150px 0 150px;
+}
+
+.bigTitle{
+  font-size: xxx-large;
+  font-weight: bold;
+}
+
+.subTitle{
+  font-size: x-large;
+}
+
+.subsubTitle{
+  font-size: large;
+  font-size: medium;
+}
+
+autoTestCard{
+  overflow: hidden;
+}
+
+.pkgUrl{
+  color: dodgerblue;
+  text-decoration: underline;
+}
+
+.totalInfo{
+  padding: 20px;
+  border: #93B5CF solid 1px;
+  display: flex;
+}
+
+.totalInfoLeft{
+  width: 100%;
+}
+
+.totalInfoLeft span{
+  font-size:large;
+}
+
+.totalInfoLeft2{
+  margin-top: 20px;
+}
+
+.miniButton{
+  margin-left: 5px;
+  vertical-align:middle;
+  text-align: center;
+
+}
+
+.totalInfoRight{
+  float:right;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.buildButton{
+  border-color: #93B5CF;
+  background-color: white;
+  color: #93B5CF;
+  font-size: large;
+  width: 150px;
+  height: 50px;
+}
+
+.buildButton:hover{
+  border-color: white;
+  background-color: #93B5CF;
+  color: white;
+  font-size: large;
+  width: 150px;
+  height: 50px;
+}
+
+.record{
+  margin-top: 50px;
+  padding: 20px;
+  border: #93B5CF solid 1px;
+}
+
+.recordHeader{
+  display: flex;
+}
+
+.recordHeaderLeft{
+  width: 100%;
+}
+.recordHeaderRight{
+  float: right;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+:deep(.el-collapse){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+:deep(.el-collapse-item__header is-active){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+:deep(.el-collapse-item__header){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+:deep(.el-collapse-item__content){
+  background-color:  rgba(0, 0, 0, 0);
+  border: none;
+}
+
+
+
+
+</style>

+ 1 - 0
src/views/ProblemPage/ProblemUpload.vue

@@ -120,6 +120,7 @@ export default {
       body.append("data", this.files[0].raw);
       this.$apis.createCoderProblem(body)
         .then((data) => {
+          console.log("data",data);
           this.$router.push("/problem/" + data.res?.id);
         })
         .catch((err) => {