Kaynağa Gözat

feat: 增加操作指引的部分

shanshan 3 yıl önce
ebeveyn
işleme
ec8c790193

+ 6 - 6
src/components/BugAddDrawer.vue

@@ -13,18 +13,18 @@
       style="width: 80%;margin-left: 20px"
       size="small">
       <el-form-item label="标题" prop="title">
-        <el-input v-model="param.title"></el-input>
+        <el-input id="bugAddTitle" v-model="param.title"></el-input>
       </el-form-item>
       <el-form-item label="描述">
-        <el-input type="textarea"
+        <el-input id="bugAddDescription" type="textarea"
                   maxlength="120"
                   show-word-limit v-model="param.description"></el-input>
       </el-form-item>
       <el-form-item label="工作量">
-        <el-input-number  v-model="param.timeToTake" :min="1" :max="200"/> 人日
+        <el-input-number id="bugAddTime" v-model="param.timeToTake" :min="1" :max="200"/> 人日
       </el-form-item>
       <el-form-item label="优先级">
-        <el-select placeholder="选择优先级" v-model="param.priority">
+        <el-select id="bugAddPriority" placeholder="选择优先级" v-model="param.priority">
           <el-option
             v-for="item in  priorityOptions"
             :key="item.value"
@@ -33,7 +33,7 @@
         </el-select>
       </el-form-item>
       <el-form-item label="经办人">
-        <el-select placeholder="选择经办人" v-model="param.processorId">
+        <el-select id="bugAddProcessor" placeholder="选择经办人" v-model="param.processorId">
           <el-option
             v-for="item in  userOptions"
             :key="item.value"
@@ -42,7 +42,7 @@
         </el-select>
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" v-loading="confirmLoading" @click="submitAdd">创建</el-button>
+        <el-button id="bugAddConfirm" type="primary" v-loading="confirmLoading" @click="submitAdd">创建</el-button>
         <el-button @click="showDrawer = false">取消</el-button>
       </el-form-item>
     </el-form>

+ 2 - 1
src/components/BugEditDrawer.vue

@@ -24,8 +24,9 @@
         </el-col>
         <el-col :span="6" :offset="2">
           <el-switch
+            id="bugEditSwitch"
             v-if="activeTab ==='basic_info'"
-            style="float: right;"
+            style="float: right; padding: 5px"
             v-model="isEditing"
             active-text="编辑"
             @change="(isEditing) => {

+ 14 - 14
src/components/CodeReviewAddDrawer.vue

@@ -4,14 +4,14 @@
       <h3 v-if="showSelectBranch">选择分支</h3>
       <h3 v-if="showCreateCodeReview">创建代码评审任务</h3>
     </template>
-    <div class="drawer-content" v-if="showSelectBranch">
+    <div id="branchSelectDrawer" class="drawer-content" v-show="showSelectBranch">
       <div class="branch-table">
         <div class="branch-row" style="background-color: #F5F5F5;">Source Branch</div>
         <div class="branch-row" >
           <el-select v-model="sourceProject" placeholder="请选择源项目" class="inline-selector left" style="margin-right:1%">
             <el-option v-for="item in projectOptions" :key="item" :value="item" :label="item"/>
           </el-select>
-          <el-select v-model="sourceBranch" placeholder="请选择源分支" class="inline-selector right" style="margin-left:1%">
+          <el-select id="selectSourceBranch" v-model="sourceBranch" placeholder="请选择源分支" class="inline-selector right" style="margin-left:1%">
             <el-option v-for="item in branchOptions" :key="item" :value="item" :label="item"/>
           </el-select>
         </div>
@@ -34,7 +34,7 @@
           <el-select v-model="targetProject" placeholder="请选择目标项目" class="inline-selector left" style="margin-right:1%">
             <el-option v-for="item in projectOptions" :key="item" :value="item" :label="item"/>
           </el-select>
-          <el-select v-model="targetBranch" placeholder="请选择目标分支" class="inline-selector right" style="margin-left:1%">
+          <el-select id="selectTargetBranch" v-model="targetBranch" placeholder="请选择目标分支" class="inline-selector right" style="margin-left:1%">
             <el-option v-for="item in branchOptions" :key="item" :value="item" :label="item"/>
           </el-select>
         </div>
@@ -51,32 +51,29 @@
             </div>
         </div>
       </div>
-      <el-button type="success" style="margin-top: 7px" @click="compareBranch()" size="medium">继续</el-button>
+      <el-button id="confirmSelectBranch" type="success" style="margin-top: 7px" @click="compareBranch()" size="medium">继续</el-button>
     </div>
-    <div class="drawer-content" v-if="showCreateCodeReview">
+    <div id="branchReviewDrawer" class="drawer-content" v-show="showCreateCodeReview">
       <el-form ref="createForm" label-position="right" label-width="80px" :model="codeReviewCreateForm" :rules="formRules">
         <el-form-item label="标题" prop="title">
-          <el-input v-model="codeReviewCreateForm.title"/>
+          <el-input id="branchReviewTitle" v-model="codeReviewCreateForm.title"/>
         </el-form-item>
         <el-form-item label="详细描述" prop="description">
           <el-input type="textarea" v-model="codeReviewCreateForm.description"/>
         </el-form-item>
         <el-form-item label="评审人" prop="reviewerId">
-          <el-select v-model="codeReviewCreateForm.reviewerId" placeholder="请选择评审人">
+          <el-select id="branchReviewer" v-model="codeReviewCreateForm.reviewerId" placeholder="请选择评审人">
             <el-option v-for=" member in projectMemberList" :label="member.label" :key="member.id" :value="member.value"/>
           </el-select>
         </el-form-item>
-        <!-- <el-form-item prop="deleteSourceBranch">
-          <el-switch v-model="codeReviewCreateForm.deleteSourceBranch"
-            active-text="合并后删除源分支"
-            active-color="#13ce66"/>
-        </el-form-item> -->
         <el-form-item>
-          <el-button type="success" v-loading="submitLoading" size="medium" @click="submitForm">立即创建</el-button>
+          <el-button id="confirmCreateBranchReview" type="success" v-loading="submitLoading" size="medium" @click="submitForm">立即创建</el-button>
           <el-button type="text" size="medium" @click="backToSelectBranch">重新选择分支</el-button>
         </el-form-item>
       </el-form>
-      <CodeDifferencePlate :data="diffMsg"/>
+      <div id="branchAddCodeDiff" style="padding: 5px">
+        <CodeDifferencePlate :data="diffMsg"/>
+      </div>
     </div>
   </el-drawer>
 </template>
@@ -253,4 +250,7 @@ export default {
 .el-drawer__container ::-webkit-scrollbar{
     display: none;
 }
+.el-overlay {
+  background-color: rgba(0,0,0,0);
+}
 </style>

+ 2 - 1
src/components/GeneralTable.vue

@@ -2,10 +2,11 @@
   <div class="table-prefix">
     <div class="right">
       <ElButton class="prefix-right-button" size="small" type="text" @click="clearFilter">清除过滤器</ElButton>
-      <ElButton class="prefix-right-button" v-if="showAdd" size="small" type="primary" @click="add">新建</ElButton>
+      <ElButton id="generalTableCreateButton" class="prefix-right-button" v-if="showAdd" size="small" type="primary" @click="add">新建</ElButton>
     </div>
   </div>
   <ElTable
+    id="generalTable"
     ref="tableRef"
     :data="data"
     v-loading="loading"

+ 2 - 2
src/components/SideBar.vue

@@ -1,6 +1,6 @@
 <template>
-  <el-menu :default-active="active" class="side-bar" :collapse="true" :router="true">
-    <el-menu-item v-for="tab in sidebar" :index="tab.name" :key="tab.name" v-show="!tab.hide" style="height: 70px;">
+  <el-menu id="sidebar" :default-active="active" class="side-bar" :collapse="true" :router="true">
+    <el-menu-item v-for="tab in sidebar" :id="tab.name" :index="tab.name" :key="tab.name" v-show="!tab.hide" style="height: 70px;">
       <el-tooltip placement="right" :content="tab.description">
         <i class="icon" :target="tab.name">
           <div v-if="calculateLength(tab.description) === 1" class="title" style="margin-left: 2px;">

+ 446 - 0
src/components/Tutorial.vue

@@ -0,0 +1,446 @@
+<template>
+  <div class="tutorial">
+    <el-row style="padding: 5px; font-size: larger">Developer使用指南
+      <el-button size="small" class="closeButton" @click="closeTutorial"></el-button>
+    </el-row>
+    <el-divider style="margin: 4px; height: 2px"/>
+    <div id="taskContainer" class="introduction" v-if="showTask">
+      <div v-for="(task, index) in taskList" :key="index" class="taskLine" @click="beginTask(index)">
+        <el-tag type="info" size="mini" effect="light" round v-if="task.status === 0">未开始</el-tag>
+        <el-tag type="danger" size="mini" effect="light" round v-if="task.status === 1">进行中</el-tag>
+        <el-tag type="success" size="mini" effect="light" round v-if="task.status === 2">已完成</el-tag>
+        {{task.description}}
+      </div>
+    </div>
+    <div id="stepContainer" class="introduction" v-if="showStep">
+      <div style="float: left; padding: 6px; left: 5px">{{stepIndex+1}}.</div>
+      <div style="padding: 4px; margin-left:20px; margin-bottom: 8px">{{ currentSteps[stepIndex].description }}</div>
+      <div style="padding: 4px; margin-left:20px; margin-bottom: 8px">请按照下列指示进行操作:</div>
+      <div class="actionDisplay" v-show="!stepFinish">{{currentSteps[stepIndex].action}}</div>
+      <div class="actionDisplaySuccess" v-show="stepFinish">{{currentSteps[stepIndex].action}}</div>
+      <el-button size="small" type="primary" plain
+                 :disabled="!stepFinish" style="float: right; right: 5px; margin-top: 10px" @click="nextStep">
+        下一步
+      </el-button>
+    </div>
+  </div>
+  <div class="shade" style="height: 60px; width: 100%"></div>
+  <div class="shade" style="top: 60px; height: 100%; width: 100%;"></div>
+</template>
+
+<script>
+export default {
+  name: 'Tutorial',
+  data() {
+    return {
+      showTask: true,
+      showStep: false,
+      // status 表示某一个任务是否被完成,0表示未开始,1表示进行中,2表示已完成
+      taskList: [
+        { name: 'display', description: 'Developer界面介绍', status: 0 },
+        { name: 'taskList', description: '学习使用任务列表模块', status: 0 },
+        { name: 'git', description: '学习使用提交记录模块', status: 0 },
+        { name: 'pipeline', description: '学习使用流水线模块', status: 0 },
+        { name: 'database', description: '学习使用数据库模块', status: 0 },
+        { name: 'apitest', description: '学习使用测试模块', status: 0 },
+        { name: 'bugList', description: '学习使用缺陷模块', status: 0 },
+        { name: 'codereview', description: '学习开展分支评审任务', status: 0 },
+      ],
+      instructions: {
+        display: [],
+        taskList: [
+          {
+            id: 'taskList', popUpId: 'sidebar', description: 'Developer系统提供了任务列表模块,用户可以管理项目开发过程中的所有任务。', action: '点击左边栏中的"任务列表"按钮', type: 'click',
+          },
+          {
+            id: 'taskListTable', popUpId: 'taskListTable', description: '在此模块中可以看到所有存在的任务,以及其预计耗时、优先级等信息', action: '查看表中的任务信息', type: 'display',
+          },
+        ],
+        git: [
+          {
+            id: 'git', popUpId: 'sidebar', description: 'Developer系统的模块选择位于最左侧的选择栏中', action: '点击左边栏中的"提交记录"按钮', type: 'click',
+          },
+          {
+            id: 'gitCommitTree', popUpId: 'gitCommitTree', description: '提交记录模块中展示了项目的所有git commit记录', action: '查看当前分支的commit信息', type: 'display',
+          },
+          {
+            id: 'gitBranchSelect', popUpId: 'gitSelectRow', description: '提交记录模块允许选择分支来单独展示分支上的变更', action: '选择master分支', type: 'select', value: 'master',
+          },
+          {
+            id: 'gitFilterButton', popUpId: 'gitSelectRow', description: '', action: '点击\'过滤\'按钮确认筛选', type: 'click',
+          },
+          {
+            id: 'gitAuthorSelect', popUpId: 'gitSelectRow', description: '提交记录模块允许在分支的基础上通过提交人进行筛选', action: '选择任意的提交者', type: 'select',
+          },
+          {
+            id: 'gitFilterButton', popUpId: 'gitSelectRow', description: '', action: '点击\'过滤\'按钮确认筛选', type: 'click',
+          },
+          {
+            id: 'gitTitleFilter', popUpId: 'gitSelectRow', description: '提交记录模块允许根据commit信息以及哈希码进行过滤', action: '输入需要筛选的message或者哈希码', type: 'input',
+          },
+          {
+            id: 'gitFilterButton', popUpId: 'gitSelectRow', description: '', action: '点击\'过滤\'按钮确认筛选', type: 'click',
+          },
+        ],
+        pipeline: [
+          {
+            id: 'pipeline', popUpId: 'sidebar', description: 'Developer系统提供了流水线模块,用户可以创建并触发部署流水线,查看部署产物。', action: '点击左边栏中的"流水线"按钮', type: 'click',
+          },
+          {
+            id: 'pipelineCreateButton', popUpId: 'pipelineElTable', description: '为了使用流水线模块的功能,我们首先创建一个新的流水线', action: '点击创建按钮', type: 'click',
+          },
+          {
+            id: 'pipelineCreateTitle', popUpId: 'pipelineCreateTitle', description: '', action: '填写流水线标题为"springboot"', type: 'input', input: 'springboot',
+          },
+          {
+            id: 'pipelineCreateTemplate', popUpId: 'pipelineCreateTemplate', description: '', action: '选择流水线模版"SpringBoot"', type: 'select', value: 'SPRINGBOOT_JAVA8',
+          },
+          {
+            id: 'pipelineCreateConfirm', popUpId: 'pipelineCreateConfirm', description: '', action: '点击确认创建流水线', type: 'select',
+          },
+          {
+            id: 'pipelineTable', popUpId: 'pipelineTabs', description: '在此表中可以看到所有的流水线信息', action: '查看流水线列表', type: 'display',
+          },
+          {
+            id: 'pipelineEditButton-springboot', popUpId: 'pipelineElTable', description: '为了使用流水线任务,我们还需要配置一些必要信息,比如代码仓库地址、端口等', action: '点击编辑按钮', type: 'click',
+          },
+          {
+            id: 'pipelineEditInput-branchOrHash', popUpId: 'pipelineEditInput-branchOrHash', description: '代码检查镜像会在构建前检查指定的分支或提交的代码', action: '输入需要生成检查镜像的分支或hash', type: 'input',
+          },
+          {
+            id: 'pipelineEditNextStep', popUpId: 'pipelineEditNextStep', description: '', action: '点击按钮进行后续配置', type: 'click',
+          },
+          {
+            id: 'pipelineEditInput-repoUrl', popUpId: 'pipelineEditInput-repoUrl', description: '在触发流水线任务时,Developer系统会在指定仓库、指定分支拉取代码并进行构建', action: '输入需要构建的代码仓库地址', type: 'input',
+          },
+          {
+            id: 'pipelineEditInput-branchName', popUpId: 'pipelineEditInput-branchName', description: '', action: '输入需要构建的代码分支', type: 'input',
+          },
+          {
+            id: 'pipelineEditNextStep', popUpId: 'pipelineEditNextStep', description: '', action: '点击按钮进行后续配置', type: 'click',
+          },
+          {
+            id: 'pipelineEditInput-port', popUpId: 'pipelineEditInput-port', description: '此处需要填写springboot后端项目将要占用的端口', action: '填写8080', type: 'input', value: '8080',
+          },
+          {
+            id: 'pipelineEditNextStep', popUpId: 'pipelineEditNextStep', description: '', action: '点击按钮进行后续配置', type: 'click',
+          },
+          {
+            id: 'pipelineEditInput-testSelect', popUpId: 'pipelineEditInput-testSelect', description: '此处可以选择需要进行的自动化接口测试,可以在测试模块中创建API测试', action: '选择需要进行的API测试任务,可以不选择', type: 'display',
+          },
+          {
+            id: 'pipelineEditFinish', popUpId: 'pipelineEditFinish', description: '', action: '点击按钮完成配置', type: 'click',
+          },
+          {
+            id: 'pipelineActivateButton-springboot', popUpId: 'pipelineActivateButton-springboot', description: '点击触发按钮后,系统会根据配置拉取代码并进行构建', action: '点击触发按钮', type: 'click',
+          },
+        ],
+        database: [
+          {
+            id: 'pipeline', popUpId: 'sidebar', description: '在使用数据库模块之前需要先通过流水线部署一个数据库实例', action: '点击左边栏中的"流水线"按钮', type: 'click',
+          },
+          {
+            id: 'pipelineCreateButton', popUpId: 'pipelineElTable', description: '', action: '点击按钮新建流水线', type: 'click',
+          },
+          {
+            id: 'pipelineCreateTitle', popUpId: 'pipelineCreateTitle', description: '', action: '填写流水线标题为"mysql"', type: 'input', input: 'mysql',
+          },
+          {
+            id: 'pipelineCreateTemplate', popUpId: 'pipelineCreateTemplate', description: '', action: '选择流水线模版"MYSQL"', type: 'select', value: 'MYSQL',
+          },
+          {
+            id: 'pipelineCreateConfirm', popUpId: 'pipelineCreateConfirm', description: '', action: '点击确认创建流水线', type: 'select',
+          },
+          {
+            id: 'pipelineActivateButton-mysql', popUpId: 'pipelineElTable', description: '默认的数据库占用3306端口,root账户的密码默认为root,可以在编辑中进行修改。', action: '点击确认触发数据库部署', type: 'click',
+          },
+          {
+            id: 'database', popUpId: 'sidebar', description: 'Developer系统提供了数据库模块,用户可以在此模块中执行SQL语句,直观的对数据库进行操作', action: '点击左边栏中的"数据库"按钮', type: 'click',
+          },
+          {
+            id: 'databaseSelect', popUpId: 'projectContainer', description: '用户在此处需要选择要操作的数据库,必须在流水线模块中部署后才可以选择', action: '选择mysql数据库实例', type: 'select', value: 'mysql',
+          },
+          {
+            id: 'databasePassword', popUpId: 'projectContainer', description: '用户在此处需要输入数据库的密码', action: '输入root用户的密码', type: 'input',
+          },
+          {
+            id: 'databaseSQL', popUpId: 'projectContainer', description: '用户在此处输入要执行的SQL语句', action: '输入SQL语句', type: 'input',
+          },
+          {
+            id: 'databaseExec', popUpId: 'projectContainer', description: '', action: '点击按钮执行SQL语句', type: 'click',
+          },
+          {
+            id: 'databaseHistory', popUpId: 'databaseHistory', description: '', action: '在此处可以看到SQL语句执行历史以及结果', type: 'display',
+          },
+        ],
+        apitest: [
+          {
+            id: 'apitest', popUpId: 'sidebar', description: '', action: '点击左边栏中的"测试"', type: 'click',
+          },
+          {
+            id: 'testCreateButton', popUpId: 'testElTable', description: '测试模块包括接口测试与黑盒测试两个部分,首先使用接口测试部分', action: '点击按钮新建接口测试任务', type: 'click',
+          },
+          {
+            id: 'testCreateTitle', popUpId: 'testCreateTitle', description: '此处填写测试的名称,在构建时可以根据此名称选择需要进行的自动化测试', action: '输入"tutorial"', type: 'input', value: 'tutorial',
+          },
+          {
+            // eslint-disable-next-line max-len
+            id: 'testCreateUrl', popUpId: 'testCreateUrl', description: '此处填写接口测试使用的URL, 触发测试时会想此处发送请求', action: '输入"http://backend.todolist-backend-877.devcloud.seec.seecoder.cn/hello"', type: 'input', value: 'http://backend.todolist-backend-877.devcloud.seec.seecoder.cn/hello',
+          },
+          {
+            id: 'testCreateMethod', popUpId: 'testCreateMethod', description: '此处填写接口使用的Http方法类型', action: '选择GET', type: 'select', value: 'GET',
+          },
+          {
+            id: 'testCreateParam', popUpId: 'testCreateParam', description: '此处填写Http需要填写的参数,POST方法中是指RequestBody', action: '在此方法中无需填写', type: 'display',
+          },
+          {
+            id: 'testCreateConfirm', popUpId: 'testCreateConfirm', description: '', action: '点击按钮创建测试', type: 'click',
+          },
+          {
+            id: 'testExec-tutorial', popUpId: 'testElTable', description: '触发测试后,系统会按照配置发送Http请求并返回结果', action: '点击按钮触发测试', type: 'click',
+          },
+          {
+            id: 'testDetail-tutorial', popUpId: 'testElTable', description: '用户可以查看测试的执行历史等信息', action: '点击按钮查看详情', type: 'click',
+          },
+          {
+            id: 'testExecHistory', popUpId: 'testExecHistory', description: '', action: '查看接口测试的执行历史,点击前面的按钮可以查看测试执行返回结果', type: 'display',
+          },
+        ],
+        bugList: [
+          {
+            id: 'bugList', popUpId: 'sidebar', description: 'Developer系统提供了缺陷管理模块用于管理开发过程中发现的各种问题', action: '点击左边栏中的"缺陷列表"', type: 'click',
+          },
+          {
+            id: 'generalTableCreateButton', popUpId: 'projectContainer', description: '', action: '点击按钮创建新的缺陷', type: 'click',
+          },
+          {
+            id: 'bugAddTitle', popUpId: 'bugAddTitle', description: '', action: '填写缺陷的名称', type: 'input',
+          },
+          {
+            id: 'bugAddDescription', popUpId: 'bugAddDescription', description: '此处需要描述缺陷出现的场景,可能出现的原因,方便其余人员进行修复', action: '填写缺陷描述(非必填)', type: 'display',
+          },
+          {
+            id: 'bugAddTime', popUpId: 'bugAddTime', description: '此处填写预计解决缺陷需要花费的事件,以"人月"作为单位', action: '选择需要的时间', type: 'display',
+          },
+          {
+            id: 'bugAddPriority', popUpId: 'bugAddPriority', description: '此处需要选择缺陷需要处理的优先级', action: '选择优先级', type: 'select',
+          },
+          {
+            id: 'bugAddProcessor', popUpId: 'bugAddProcessor', description: '此处可以指定项目中的开发人员负责修复这个缺陷', action: '选择经办人', type: 'select',
+          },
+          {
+            id: 'bugAddConfirm', popUpId: 'bugAddConfirm', description: '', action: '点击按钮创建缺陷', type: 'click',
+          },
+          {
+            id: 'bugTable', popUpId: 'projectContainer', description: '在此处展示了当前项目的缺陷列表,点击其中一列可以查看缺陷的详情', action: '点击任意一列', type: 'click',
+          },
+          {
+            id: 'bugEditSwitch', popUpId: 'bugEditSwitch', description: '在此处展示了某一个缺陷的详情,点击上方的开关按钮可以对缺陷进行编辑', action: '查看缺陷详情,对缺陷进行编辑', type: 'display',
+          },
+        ],
+        codereview: [
+          {
+            id: 'codereview', popUpId: 'sidebar', description: '分支评审任务属于代码评审模块的一部分', action: '点击左边栏中的"代码评审"按钮', type: 'click',
+          },
+          {
+            id: 'addBranchReview', popUpId: 'codeReviewButtonRow', description: '', action: '点击新建分支评审任务', type: 'click',
+          },
+          {
+            id: 'selectSourceBranch', popUpId: 'branchSelectDrawer', description: '分支评审基于项目的不同分支进行,在创建分支评审时需要首先选择分支,目标分支与源分支不能相同', action: '选择master分支', type: 'select', value: 'master',
+          },
+          {
+            id: 'selectTargetBranch', popUpId: 'branchSelectDrawer', description: '当分支评审任务结束时,会将源分支上的改动合并至目标分支中', action: '选择dev分支', type: 'select', value: 'dev',
+          },
+          {
+            id: 'confirmSelectBranch', popUpId: 'branchSelectDrawer', description: '', action: '点击继续按钮', type: 'click',
+          },
+          {
+            id: 'branchAddCodeDiff', popUpId: 'branchReviewDrawer', description: '在此处可以预览分支间的代码差异', action: '查看分支代码差异预览', type: 'display',
+          },
+          {
+            id: 'branchReviewTitle', popUpId: 'branchReviewDrawer', description: '', action: '填写评审任务的的标题', type: 'input',
+          },
+          {
+            id: 'branchReviewer', popUpId: 'branchReviewDrawer', description: '分支评审任务只可以选择项目内部的开发人员作为评审人', action: '选择任意的评审人', type: 'select',
+          },
+          {
+            id: 'confirmCreateBranchReview', popUpId: 'branchReviewDrawer', description: '', action: '点击确认创建新的分支评审任务', type: 'click',
+          },
+        ],
+      },
+      currentSteps: [],
+      eventListeners: [],
+      stepFinish: false,
+      stepIndex: -1,
+      taskIndex: 1,
+    };
+  },
+  methods: {
+    beginTask(index) {
+      this.currentSteps = this.instructions[this.taskList[index].name];
+      this.taskList[index].status = 1;
+      this.taskIndex = index;
+      this.nextStep();
+      this.showTask = false;
+      this.showStep = true;
+    },
+    nextStep() {
+      if (this.stepIndex !== -1) {
+        // 存在前一个步骤,需要先消除之前的闪烁边框以及z-index提前
+        document.getElementById(this.currentSteps[this.stepIndex].id).classList.remove('border-glow');
+        document.getElementById(this.currentSteps[this.stepIndex].popUpId).classList.remove('pop-up');
+        // 去除事件监听器
+        if (this.eventListeners[this.stepIndex] !== null) {
+          document.getElementById(this.currentSteps[this.stepIndex].id).removeEventListener(this.eventListeners[this.stepIndex].type, this.eventListeners[this.stepIndex].func);
+        }
+      }
+      if (this.stepIndex === this.currentSteps.length - 1) {
+        // 所有的步骤都被遍历完,可以直接推出步骤引导,返回任务列表
+        this.stepIndex = -1;
+        this.taskList[this.taskIndex].status = 2;
+        this.showStep = false;
+        this.showTask = true;
+        this.eventListeners = [];
+        this.currentSteps = [];
+        return;
+      }
+      this.stepIndex += 1;
+      this.stepFinish = false;
+      // 更改元素的样式,增加闪烁边框以及增加z-index
+      document.getElementById(this.currentSteps[this.stepIndex].id).classList.add('border-glow');
+      document.getElementById(this.currentSteps[this.stepIndex].popUpId).classList.add('pop-up');
+      const { type } = this.currentSteps[this.stepIndex];
+      let event;
+      const that = this;
+      if (type === 'display') {
+        // 操作类型为仅展示,不需要操作
+        this.stepFinish = true;
+        event = null;
+        this.eventListeners.push(event);
+      } else if (type === 'click') {
+        event = function () {
+          that.stepFinish = true;
+          document.getElementById(that.currentSteps[that.stepIndex].popUpId).classList.remove('pop-up');
+        };
+        document.getElementById(this.currentSteps[this.stepIndex].id).addEventListener('click', event);
+        this.eventListeners.push({ type: 'click', func: event });
+      } else if (type === 'select') {
+        event = function () {
+          const expectedV = that.currentSteps[that.stepIndex].value;
+          const actualV = document.getElementById(that.currentSteps[that.stepIndex].id).value;
+          if (expectedV === null || expectedV === undefined) {
+            that.stepFinish = true;
+          } else {
+            that.stepFinish = expectedV === actualV;
+          }
+        };
+        document.getElementById(this.currentSteps[this.stepIndex].id).addEventListener('focus', event);
+        this.eventListeners.push({ type: 'focus', func: event });
+      } else if (type === 'input') {
+        event = function () {
+          const expectedV = that.currentSteps[that.stepIndex].value;
+          const actualV = document.getElementById(that.currentSteps[that.stepIndex].id).value;
+          if (expectedV === null || expectedV === undefined) {
+            that.stepFinish = true;
+          } else {
+            that.stepFinish = expectedV === actualV;
+          }
+        };
+        document.getElementById(this.currentSteps[this.stepIndex].id).addEventListener('change', event);
+        this.eventListeners.push({ type: 'change', func: event });
+      } else if (type === 'row-click') {
+        event = function () {
+          that.stepFinish = true;
+          document.getElementById(that.currentSteps[that.stepIndex].popUpId).classList.remove('pop-up');
+        };
+        document.getElementById(this.currentSteps[this.stepIndex].id).addEventListener('row-click', event);
+        this.eventListeners.push({ type: 'row-click', func: event });
+      }
+    },
+    closeTutorial() {
+      this.currentSteps = [];
+      this.showStep = false;
+      this.showTask = true;
+      if (this.stepIndex !== -1 && this.eventListeners[this.stepIndex] !== null) {
+        document.getElementById(this.currentSteps[this.stepIndex].id).removeEventListener(this.eventListeners[this.stepIndex].type, this.eventListeners[this.stepIndex].func);
+      }
+      this.eventListeners = [];
+      this.stepIndex = -1;
+      this.stepFinish = false;
+      this.$emit('close');
+    },
+  },
+  emits: ['close'],
+};
+</script>
+
+<style scoped>
+.shade {
+  position: fixed;
+  top: 0px;
+  left: 0px;
+  background-color: rgba(0,0,0,0);
+  z-index: 2000;
+}
+.tutorial {
+  width: 300px;
+  height: 100%;
+  z-index: 5000;
+  padding: 5px;
+  background-color: rgba(255,255,255,1);
+}
+.introduction {
+  padding: 5px;
+  margin-top: 5px;
+  color: #444444;
+}
+.taskLine {
+  padding: 8px 5px;
+  margin-bottom: 10px;
+  border-bottom: solid 1px #eeeeee;
+}
+.taskLine:hover {
+  cursor: pointer;
+}
+.actionDisplay {
+  margin-left: 20px;
+  border-left: 5px solid #909090;
+  margin-bottom: 8px;
+  background-color: whitesmoke;
+  padding: 5px;
+  font-size: smaller;
+}
+.actionDisplaySuccess {
+  margin-left: 20px;
+  margin-bottom: 8px;
+  border-left: 5px solid #67C23A;
+  background-color: #F0F9EB;
+  padding: 5px;
+  font-size: smaller;
+}
+.closeButton {
+  background-image: url("../assets/icon/close.svg");
+  background-size: 25px 25px;
+  background-repeat: no-repeat;
+  border: none;
+  margin-left: 70px;
+}
+</style>
+<style>
+.border-glow {
+  animation: glow 800ms ease-out infinite alternate;
+}
+@keyframes glow {
+  0% {
+    border-color: yellow;
+    box-shadow: 0 0 1px 3px yellow inset;
+  }
+  100% {
+    border-color: yellow;
+    box-shadow: 0 0 1px 5px yellow inset;
+  }
+}
+.pop-up {
+  z-index: 3000;
+}
+</style>

+ 1 - 1
src/views/Project/BugList.vue

@@ -1,5 +1,5 @@
 <template>
-<div class="table-container">
+<div id="bugTable" style="padding: 6px" class="table-container">
   <GeneralTable
     :data="bugList"
     :showAdd="true"

+ 2 - 2
src/views/Project/CodeReview.vue

@@ -2,10 +2,10 @@
   <div class="container">
     <CodeReviewAddDrawer ref="addDrawer"/>
     <FileReviewAddDrawer ref="fileReviewAddDrawer"/>
-    <el-row>
+    <el-row id="codeReviewButtonRow">
       <h2>代码评审列表</h2>
       <div class="button-plate">
-        <el-button type="success" size="medium" @click="addCodeReview">新建分支评审</el-button>
+        <el-button id="addBranchReview" type="success" size="medium" @click="addCodeReview">新建分支评审</el-button>
         <el-button type="primary" size="medium" @click="addFileReview">新建文件评审</el-button>
       </div>
     </el-row>

+ 6 - 6
src/views/Project/Commit.vue

@@ -4,9 +4,9 @@
       <h2>commit记录</h2>
     </el-row>
     <div>
-      <el-row :gutter="20">
+      <el-row id="gitSelectRow" :gutter="20">
         <el-col :span="6">
-          <el-select v-model="currentBranch" class="m-2" placeholder="Select" size="large">
+          <el-select id="gitBranchSelect" v-model="currentBranch" class="m-2" placeholder="Select" size="large">
             <el-option
               v-for="(branch, index) in branches"
               :key="index"
@@ -17,7 +17,7 @@
           </el-select>
         </el-col>
         <el-col :span="6">
-          <el-select
+          <el-select id="gitAuthorSelect"
             v-model="currentAuthors"
             multiple
             collapse-tags
@@ -32,10 +32,10 @@
           </el-select>
         </el-col>
         <el-col :span="8">
-          <el-input v-model="keyword" placeholder="输入检索message内容或Hash" clearable />
+          <el-input id="gitTitleFilter" v-model="keyword" placeholder="输入检索message内容或Hash" clearable />
         </el-col>
         <el-col :span="2">
-          <el-button type="primary" @click="onSearch">过滤</el-button>
+          <el-button id="gitFilterButton" type="primary" @click="onSearch">过滤</el-button>
         </el-col>
         <el-col v-if="!showGraph" :span="2">
           <el-button type="primary" @click="showGraph = canShowGraph">图形</el-button>
@@ -48,7 +48,7 @@
       <div v-if="originCommits.length === 0">
         <el-empty description="暂无commit记录!"></el-empty>
       </div>
-      <div v-else>
+      <div v-else id="gitCommitTree" style="padding: 10px">
         <el-row :gutter="20">
           <el-col style="padding-bottom: 20px; text-align: center; overflow: auto; transform: scaleY(-1)" v-show="(showGraph)" :span="6">
             <div style="transform: scaleY(-1)" id="graph-container"></div>

+ 54 - 50
src/views/Project/Database.vue

@@ -1,55 +1,59 @@
 <template>
-  <ElForm inline ref="sql-form" :model="form" label-width="80px">
-    <ElFormItem label="实例">
-      <ElSelect class="input" v-model="form.deploymentId" placeholder="请选择数据库实例">
-        <ElOption v-for="db in dbs" :key="db.id" :label="db.name" :value="db.id"></ElOption>
-      </ElSelect>
-    </ElFormItem>
-    <ElFormItem label="用户名">
-      <ElInput class="input" v-model="form.username" placeholder="请输入用户名"></ElInput>
-    </ElFormItem>
-    <ElFormItem label="密码">
-      <ElInput class="input" v-model="form.password" type="password" placeholder="请输入密码"></ElInput>
-    </ElFormItem>
-    <ElFormItem label="数据库">
-      <ElInput class="input" v-model="form.db" placeholder="请输入数据库名"></ElInput>
-    </ElFormItem>
-    <ElFormItem label="SQL">
-      <ElInput class="sql" v-model="form.sql" :rows="5" type="textarea" clearable></ElInput>
-    </ElFormItem>
-    <ElFormItem>
-      <ElButton type="primary" @click="exec">执行</ElButton>
-    </ElFormItem>
-  </ElForm>
+  <div id="databaseForm">
+    <ElForm inline ref="sql-form" :model="form" label-width="80px">
+      <ElFormItem id="databaseSelectFI" label="实例">
+        <ElSelect id="databaseSelect" class="input" v-model="form.deploymentId" placeholder="请选择数据库实例">
+          <ElOption v-for="db in dbs" :key="db.id" :label="db.name" :value="db.id"></ElOption>
+        </ElSelect>
+      </ElFormItem>
+      <ElFormItem label="用户名">
+        <ElInput class="input" v-model="form.username" placeholder="请输入用户名"></ElInput>
+      </ElFormItem>
+      <ElFormItem label="密码">
+        <ElInput id="databasePassword" class="input" v-model="form.password" type="password" placeholder="请输入密码"></ElInput>
+      </ElFormItem>
+      <ElFormItem label="数据库">
+        <ElInput class="input" v-model="form.db" placeholder="请输入数据库名"></ElInput>
+      </ElFormItem>
+      <ElFormItem label="SQL">
+        <ElInput id="databaseSQL" class="sql" v-model="form.sql" :rows="5" type="textarea" clearable></ElInput>
+      </ElFormItem>
+      <ElFormItem>
+        <ElButton id="databaseExec" type="primary" @click="exec">执行</ElButton>
+      </ElFormItem>
+    </ElForm>
+  </div>
   <ElDivider content-position="left">当前执行记录</ElDivider>
-  <ElRow type="flex" justify="space-between" v-if="execHistory.size > 0">
-    <ElCol :span="4" height="600px">
-      <div
-        :class="['list-item', active === key?'active':'']"
-        v-for="key in [...execHistory.keys()].reverse()"
-        :key="key"
-        @click="switchRecord(key)"
-      >{{key}}</div>
-    </ElCol>
-    <ElDivider direction="vertical"></ElDivider>
-    <ElCol :span="18" v-show="active > 0">
-      <ElDivider content-position="left">SQL</ElDivider>
-      <pre>{{activeRecord.sql}}</pre>
-      <ElDivider content-position="left">结果</ElDivider>
-      <template v-if="showTable">
-        <pre>{{b}}</pre>
-        <table>
-          <tr v-for="(row, i) in content" :key="i">
-            <td v-for="(cell,j) in row" :key="j">{{cell}}</td>
-          </tr>
-        </table>
-      </template>
-      <template v-else>
-        <pre>{{activeRecord.result}}</pre>
-      </template>
-    </ElCol>
-  </ElRow>
-  <ElEmpty v-else description="暂无记录"></ElEmpty>
+  <div id="databaseHistory" style="padding: 6px">
+    <ElRow type="flex" justify="space-between" v-if="execHistory.size > 0">
+      <ElCol :span="4" height="600px">
+        <div
+          :class="['list-item', active === key?'active':'']"
+          v-for="key in [...execHistory.keys()].reverse()"
+          :key="key"
+          @click="switchRecord(key)"
+        >{{key}}</div>
+      </ElCol>
+      <ElDivider direction="vertical"></ElDivider>
+      <ElCol :span="18" v-show="active > 0">
+        <ElDivider content-position="left">SQL</ElDivider>
+        <pre>{{activeRecord.sql}}</pre>
+        <ElDivider content-position="left">结果</ElDivider>
+        <template v-if="showTable">
+          <pre>{{b}}</pre>
+          <table>
+            <tr v-for="(row, i) in content" :key="i">
+              <td v-for="(cell,j) in row" :key="j">{{cell}}</td>
+            </tr>
+          </table>
+        </template>
+        <template v-else>
+          <pre>{{activeRecord.result}}</pre>
+        </template>
+      </ElCol>
+    </ElRow>
+    <ElEmpty v-else description="暂无记录"></ElEmpty>
+  </div>
 </template>
 
 <script>

+ 10 - 10
src/views/Project/InterfaceTest.vue

@@ -1,7 +1,7 @@
 <template>
   <el-tabs class="tabs" v-model="activeTab">
     <el-tab-pane label="接口测试" name="interfaceTest">
-      <el-table :data="interfaceTests" style="width: 100%" height="600">
+      <el-table id="testElTable" :data="interfaceTests" style="width: 100%" height="600">
         <el-table-column type="expand">
           <template #default="props">
             <el-row type="flex" justify="center">
@@ -63,7 +63,7 @@
           label="详情"
           align="center">
           <template #default="scope">
-            <el-button
+            <el-button :id="'testDetail-'+scope.row.name" style="padding: 5px"
               @click="handleClick('detail', scope.row.id)"
               type="text"
               size="small">查看详情</el-button>
@@ -73,10 +73,10 @@
           align="center">
           <template #header>
             <span>操作</span>
-            <el-button @click="handleClick('create')" type="text" class="add-button">新建</el-button>
+            <el-button id="testCreateButton" style="padding: 5px" @click="handleClick('create')" type="text" class="add-button">新建</el-button>
           </template>
           <template #default="scope">
-            <el-button @click="handleClick('trigger', scope.row.id)" type="text" size="small">触发</el-button>
+            <el-button :id="'testExec-'+scope.row.name" style="padding: 5px" @click="handleClick('trigger', scope.row.id)" type="text" size="small">触发</el-button>
             <el-button @click="handleClick('delete', scope.row.id)" type="text" size="small">删除</el-button>
           </template>
         </el-table-column>
@@ -173,13 +173,13 @@
       label-suffix=":"
       style="width: 80%; margin: 0 auto;">
       <el-form-item label="测试名称" prop="name" required>
-        <el-input v-model="createInterfaceTestForm.name" placeholder="请输入接口测试的名称"></el-input>
+        <el-input id="testCreateTitle" v-model="createInterfaceTestForm.name" placeholder="请输入接口测试的名称"></el-input>
       </el-form-item>
       <el-form-item label="待测URL" prop="url" required>
-        <el-input v-model="createInterfaceTestForm.url" placeholder="请输入待测试的URL"></el-input>
+        <el-input id="testCreateUrl" v-model="createInterfaceTestForm.url" placeholder="请输入待测试的URL"></el-input>
       </el-form-item>
       <el-form-item label="方法" prop="method" required>
-        <el-select v-model="createInterfaceTestForm.method" placeholder="请选择待测URL的方法">
+        <el-select id="testCreateMethod" v-model="createInterfaceTestForm.method" placeholder="请选择待测URL的方法">
           <el-option
             v-for="(method, index) in methodList"
             :key="index"
@@ -188,7 +188,7 @@
         </el-select>
       </el-form-item>
       <el-form-item :label="createInterfaceTestForm.method === 'POST' ? '请求体' : '携带参数'" prop="params">
-        <div>
+        <div id="testCreateParam">
           <vue-json-editor
             :height="'400px'"
             v-model="createInterfaceTestForm.params"
@@ -204,7 +204,7 @@
     </el-form>
     <template #footer>
       <span class="dialog-footer">
-        <el-button type="primary" @click="handleInterfaceCreateConfirm()">确 定</el-button>
+        <el-button id="testCreateConfirm" type="primary" @click="handleInterfaceCreateConfirm()">确 定</el-button>
       </span>
     </template>
   </el-dialog>
@@ -262,7 +262,7 @@
         </el-row>
       </div>
       <el-divider content-position="left">测试执行结果</el-divider>
-      <div style="width: 95%; margin: 0 auto">
+      <div id="testExecHistory" style="width: 95%; margin: 0 auto; padding: 8px">
         <el-tabs v-model="activeTab1">
           <el-tab-pane label="手动触发结果" name="artificial">
             <el-table :data="interfaceTestResults" style="width: 100%" height="800" border>

+ 89 - 83
src/views/Project/Pipeline.vue

@@ -1,92 +1,94 @@
 <template>
-  <ElTabs class="tabs" v-model="activeTab"  v-loading.lock="loading">
+  <ElTabs id="pipelineTabs" class="tabs" v-model="activeTab"  v-loading.lock="loading">
     <ElTabPane label="流水线" name="pipeline">
-      <ElTable :data="pipelines" width="100%" :default-sort="{prop: 'id', order: 'descending'}">
-        <ElTableColumn
-          prop="id"
-          label="ID"
-          align="center"
-          width="60"
-        ></ElTableColumn>
-        <ElTableColumn
-          prop="name"
-          label="名称"
-          align="center"
-          width="180"
-        ></ElTableColumn>
-        <ElTableColumn
-          prop="username"
-          label="最近执行人"
-          align="center"
-          width="180"
-        ></ElTableColumn>
-        <ElTableColumn
-          label="最近执行时间"
-          align="center"
-          :formatter="(row) => formatter(row.startTime)"
-        ></ElTableColumn>
-        <ElTableColumn
-          prop="result"
-          label="执行状态"
-          align="center"
-          width="110"
-          :filters="[
+      <div id="pipelineTable" style="padding: 6px">
+        <ElTable id="pipelineElTable" :data="pipelines" width="100%" :default-sort="{prop: 'id', order: 'descending'}">
+          <ElTableColumn
+            prop="id"
+            label="ID"
+            align="center"
+            width="60"
+          ></ElTableColumn>
+          <ElTableColumn
+            prop="name"
+            label="名称"
+            align="center"
+            width="180"
+          ></ElTableColumn>
+          <ElTableColumn
+            prop="username"
+            label="最近执行人"
+            align="center"
+            width="180"
+          ></ElTableColumn>
+          <ElTableColumn
+            label="最近执行时间"
+            align="center"
+            :formatter="(row) => formatter(row.startTime)"
+          ></ElTableColumn>
+          <ElTableColumn
+            prop="result"
+            label="执行状态"
+            align="center"
+            width="110"
+            :filters="[
               { text: '成功', value: '部署成功' },
               { text: '失败', value: '部署失败' },
               { text: '部署中', value: '部署中' },
               { text: '无记录', value: '无执行记录' }
           ]"
-          :filter-method="(value, row) => {
+            :filter-method="(value, row) => {
             return row.result === value;
           }"
-          filter-placement="bottom-end"
-        >
-          <template #default="scope">
-            <template v-if="scope.row.result === '部署成功'">
-              <ElTag type="success">{{scope.row.result}}</ElTag>
-            </template>
-            <template v-else-if="scope.row.result === '部署失败'">
-              <ElTag type="danger">{{scope.row.result}}</ElTag>
+            filter-placement="bottom-end"
+          >
+            <template #default="scope">
+              <template v-if="scope.row.result === '部署成功'">
+                <ElTag type="success">{{scope.row.result}}</ElTag>
+              </template>
+              <template v-else-if="scope.row.result === '部署失败'">
+                <ElTag type="danger">{{scope.row.result}}</ElTag>
+              </template>
+              <template v-else-if="scope.row.result === '部署中'">
+                <ElTag>{{scope.row.result}}<i class="el-icon-loading"></i></ElTag>
+              </template>
+              <template v-else-if="scope.row.result === '无执行记录'">
+                <ElTag>{{scope.row.result}}</ElTag>
+              </template>
+              <template v-else>
+                <ElTag type="warning">未知状态</ElTag>
+              </template>
             </template>
-            <template v-else-if="scope.row.result === '部署中'">
-              <ElTag>{{scope.row.result}}<i class="el-icon-loading"></i></ElTag>
+          </ElTableColumn>
+          <ElTableColumn
+            label="详情"
+            align="center"
+          >
+            <template #default="scope">
+              <ElButton
+                @click="handleClick('detail', scope.row.recordId)"
+                type="text"
+                size="small"
+                :disabled="scope.row.result==='执行中'"
+              >最近执行详情</ElButton>
+              <ElButton @click="handleClick('history', scope.row.id)" type="text" size="small">历史</ElButton>
             </template>
-            <template v-else-if="scope.row.result === '无执行记录'">
-              <ElTag>{{scope.row.result}}</ElTag>
+          </ElTableColumn>
+          <ElTableColumn
+            align="center"
+          >
+            <template #header>
+              <span>操作</span>
+              <ElButton id="pipelineCreateButton" style="padding: 5px" @click="handleClick('create')" type="text" class="add-button">新建</ElButton>
             </template>
-            <template v-else>
-              <ElTag type="warning">未知状态</ElTag>
+            <template #default="scope">
+              <ElButton :id="'pipelineActivateButton-'+scope.row.name" style="padding: 5px" @click="handleClick('trigger', scope.row.id)" type="text" size="small">触发</ElButton>
+              <ElButton :id="'pipelineEditButton-'+scope.row.name" style="padding: 5px" @click="handleClick('edit', scope.row.id)" type="text" size="small">编辑</ElButton>
+              <ElButton @click="handleClick('delete', scope.row.id)" type="text" size="small">删除</ElButton>
             </template>
-          </template>
-        </ElTableColumn>
-        <ElTableColumn
-          label="详情"
-          align="center"
-        >
-          <template #default="scope">
-            <ElButton
-              @click="handleClick('detail', scope.row.recordId)"
-              type="text"
-              size="small"
-              :disabled="scope.row.result==='执行中'"
-            >最近执行详情</ElButton>
-            <ElButton @click="handleClick('history', scope.row.id)" type="text" size="small">历史</ElButton>
-          </template>
-        </ElTableColumn>
-        <ElTableColumn
-          align="center"
-        >
-          <template #header>
-            <span>操作</span>
-            <ElButton @click="handleClick('create')" type="text" class="add-button">新建</ElButton>
-          </template>
-          <template #default="scope">
-            <ElButton @click="handleClick('trigger', scope.row.id)" type="text" size="small">触发</ElButton>
-            <ElButton @click="handleClick('edit', scope.row.id)" type="text" size="small">编辑</ElButton>
-            <ElButton @click="handleClick('delete', scope.row.id)" type="text" size="small">删除</ElButton>
-          </template>
-        </ElTableColumn>
-      </ElTable>
+          </ElTableColumn>
+        </ElTable>
+      </div>
       <ElDialog v-model="showPipelineDetailModal" destroy-on-close>
         <template #title>历史执行结果详情</template>
         <pre class="log" v-loading="dialogLoading" >{{detail}}</pre>
@@ -164,6 +166,7 @@
         </ElTable>
       </ElDialog>
       <ElDialog
+        id="pipelineEditForm"
         v-model="showPipelineEditModal"
         destroy-on-close
       >
@@ -204,7 +207,7 @@
             </div>
             <template v-for="(val, key) in config.configs" :key="key" placeholder="请选择">
             <ElFormItem :label="key">
-              <ElSelect v-if="key === 'apiTestIds'" v-model="config.configs[key]" multiple >
+              <ElSelect id="pipelineEditInput-testSelect" v-if="key === 'apiTestIds'" v-model="config.configs[key]" multiple >
                 <el-option
                   v-for="item in apiTestOptions"
                   :key="item.id"
@@ -218,7 +221,9 @@
                 type="textarea"
                 :rows="5"
               ></ElInput>
-              <ElInput v-else
+              <ElInput
+                :id="'pipelineEditInput-'+key"
+                v-else
                 :disabled="!getStage(config.name).configs.find((config) => config.name === key).editable"
                 v-model="config.configs[key]"
               ></ElInput>
@@ -228,11 +233,12 @@
         </div>
         <template #footer>
           <ElButton :disabled="activeStep == 0" @click="() => activeStep -= 1">上一步</ElButton>
-          <ElButton :disabled="isLastStep"  @click="() => activeStep += 1">下一步</ElButton>
-          <ElButton type="primary" @click="handlePipelineUpdateConfirm">确定</ElButton>
+          <ElButton id="pipelineEditNextStep" :disabled="isLastStep"  @click="() => activeStep += 1">下一步</ElButton>
+          <ElButton id="pipelineEditFinish" type="primary" @click="handlePipelineUpdateConfirm">确定</ElButton>
         </template>
       </ElDialog>
       <ElDialog
+        id="pipelineCreateForm"
         v-model="showPipelineCreateModal"
         :before-close="(done) => {
           $refs['createPipelineForm'].resetFields();
@@ -255,10 +261,10 @@
           v-loading="dialogLoading"
         >
           <ElFormItem label="名称" prop="name" required>
-            <ElInput v-model="createPipelineForm.name" placeholder="请输入流水线名称"></ElInput>
+            <ElInput id="pipelineCreateTitle" v-model="createPipelineForm.name" placeholder="请输入流水线名称"></ElInput>
           </ElFormItem>
           <ElFormItem label="模板" prop="template" required>
-            <ElSelect v-model="createPipelineForm.template" placeholder="请选择模板">
+            <ElSelect id="pipelineCreateTemplate" v-model="createPipelineForm.template" placeholder="请选择模板">
               <ElOption
                 v-for="(template, index) in templates"
                 :key="index" :label="template"
@@ -269,7 +275,7 @@
         </ElForm>
         <template #footer>
           <span class="dialog-footer">
-            <el-button type="primary" v-loading="confirmLoading" @click="handlePipelineCreateConfirm">确 定</el-button>
+            <el-button id="pipelineCreateConfirm" type="primary" v-loading="confirmLoading" @click="handlePipelineCreateConfirm">确 定</el-button>
           </span>
         </template>
       </ElDialog>

+ 1 - 1
src/views/Project/TaskList.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="table-container">
+  <div class="table-container" id="taskListTable" style="padding: 5px">
     <GeneralTable
       :data="taskList"
       :loading="loading"

+ 16 - 3
src/views/ProjectContainer.vue

@@ -1,8 +1,9 @@
 <template>
+  <Tutorial v-if="showTutorial" @close="closeTutorial" style="height: 100%"></Tutorial>
   <el-aside width="65">
     <SideBar></SideBar>
   </el-aside>
-  <el-main class="container">
+  <el-main id="projectContainer" class="container">
     <router-view></router-view>
   </el-main>
 </template>
@@ -10,13 +11,25 @@
 <script>
 import SideBar from '@/components/SideBar.vue';
 import { WorkspaceDispatcher } from '@/store/dispatchers';
+import Tutorial from '@/components/Tutorial.vue';
 
 export default {
   name: 'ProjectContainer',
-  components: { SideBar },
+  components: { Tutorial, SideBar },
+  data() {
+    return {
+      showTutorial: false,
+    };
+  },
+  methods: {
+    closeTutorial() {
+      this.showTutorial = false;
+    },
+  },
   mounted() {
     const { projectId } = this.$route.params;
     WorkspaceDispatcher.changeProject(parseInt(projectId, 10));
+    this.showTutorial = projectId === '877';
   },
 };
 </script>
@@ -24,7 +37,7 @@ export default {
 <style scoped>
 .container{
   background-color: #FFFFFF;
-  width: calc(100% - 42px);
+  width: calc(100% - 300px);
   min-height: 60vh;
   margin-left: 60px;
 }