chenyitao.0928 5 anos atrás
pai
commit
82670e4a08

+ 110 - 0
src/components/AddBugDrawerContent.vue

@@ -0,0 +1,110 @@
+<template>
+  <div class="drawer-content">
+    <el-form
+      ref="form"
+      :rules="rules"
+      :model="param"
+      label-width="80px"
+      style="width: 80%;margin-left: 20px"
+      size="small">
+      <el-form-item label="标题" prop="title">
+        <el-input v-model="param.title"></el-input>
+      </el-form-item>
+      <el-form-item label="描述">
+        <el-input 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="0" :max="200"/> h
+      </el-form-item>
+      <el-form-item label="优先级">
+        <el-select placeholder="选择优先级" v-model="param.priority">
+          <el-option
+            v-for="item in  priorityOptions"
+            :key="item.value"
+            :value="item.value"
+            :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="经办人">
+        <el-select placeholder="选择经办人" v-model="param.processorId">
+          <el-option
+            v-for="item in  processorOptions"
+            :key="item.value"
+            :value="item.value"
+            :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="submitAdd">创建</el-button>
+        <el-button @click="cancelAdd">取消</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { BugListAPI } from '../api';
+
+export default {
+  name: 'AddBugDrawerContent',
+  data() {
+    return {
+      param: {
+        title: '',
+        description: '',
+        type: '',
+        timeToTake: null,
+        priority: null,
+        userId: null,
+      },
+      priorityOptions: [
+        { label: '紧急', value: 1 },
+        { label: '宽松', value: 2 },
+        { label: '一般', value: 3 },
+      ],
+      relateRequirementOptions: [],
+      processorOptions: [],
+      rules: {
+        title: [{
+          required: true, massage: '请输入标题', trigger: 'blur',
+        }],
+        type: [{
+          required: true, massage: '请选择类型', trigger: 'change',
+        }],
+      },
+    };
+  },
+  mounted() {
+    this.getProcessorOptions();
+  },
+  methods: {
+    getProcessorOptions() {
+      this.processorOptions = [
+        { label: 'cyt', value: 1 },
+        { label: 'hks', value: 2 },
+        { label: 'abc', value: 3 },
+      ];
+    },
+    cancelAdd() {
+      this.$emit('cancel-add');
+    },
+    submitAdd() {
+      // BugListAPI.createBugRecord()
+      this.$emit('finish-add');
+    },
+  },
+};
+</script>
+
+<style scoped>
+.drawer-content{
+  width: 100%;
+  padding: 10px;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+</style>

+ 363 - 0
src/components/BugDrawerContent.vue

@@ -0,0 +1,363 @@
+<template>
+  <div class="drawer-content">
+    <el-row class="entry-row">
+      <div class="node-type">Bug</div>
+      <h3>{{title}}</h3>
+      <div class="edit-icon" @click="editEntry('title')"></div>
+      <i class="el-icon-close"
+         style="margin-left: auto;margin-right: 30px; font-size: 20px;cursor: pointer"
+         @click="closeDrawer"></i>
+    </el-row>
+    <el-row class="entry-row" v-if="isEditing.title">
+      <el-input placeholder="请输入标题" size="mini" style="width: 300px;display: inline;" v-model="editedBug.title"/>
+      <el-button
+        style="margin-left: 5px"
+        type="primary"
+        size="mini"
+        icon="el-icon-edit"
+        circle
+        @click="submitEdit('title')" />
+      <el-button
+        style="margin-left: 5px"
+        type="danger"
+        size="mini"
+        icon="el-icon-close"
+        circle
+        @click="cancelEdit('title')" />
+    </el-row>
+    <!-- 描述 -->
+    <el-row class="entry-row" style="margin-top: 15px">
+      <h4>需求描述</h4>
+      <div class="edit-icon" @click="editEntry('description')"></div>
+    </el-row>
+    <el-row class="entry-row">
+      <div v-if="isEditing.description">
+        <el-input placeholder="请输入描述"
+                  type="textarea"
+                  maxlength="120"
+                  show-word-limit
+                  :rows="3" style="width: 300px;" v-model="editedBug.description" />
+        <br/>
+        <el-button
+          style="margin-left: 5px; margin-top: 5px"
+          type="primary"
+          size="mini"
+          icon="el-icon-edit"
+          circle
+          @click="submitEdit('description')" />
+        <el-button
+          style="margin-left: 5px; margin-top: 5px"
+          type="danger"
+          size="mini"
+          icon="el-icon-close"
+          circle
+          @click="cancelEdit('description')" />
+      </div>
+      <p v-else>{{description}}</p>
+    </el-row>
+    <!-- 状态、优先级等 -->
+    <el-row class="entry-row" style="margin-top: 15px">
+      <h4>详情</h4>
+    </el-row>
+    <el-row style="margin: 3px 20px;width: 100%">
+      <el-col :span="12">
+        <div class="detail-row">
+          <span>状态:</span>
+          <div  v-if="!isEditing.state"   @click="editEntry('state')" class="detail-value">
+            <StateTag :state="state"></StateTag>
+            <div class="edit-icon" />
+          </div>
+          <div v-else>
+            <el-select style="width: 160px" size="mini" v-model="editedBug.state">
+              <el-option
+                v-for="item in stateOptions"
+                :key="item.value"
+                :value="item.value"
+                :label="item.value" />
+            </el-select>
+            <el-button
+              style="margin-left: 5px"
+              type="primary"
+              size="mini"
+              icon="el-icon-edit"
+              circle
+              @click="submitEdit('state')" />
+            <el-button
+              style="margin-left: 5px"
+              type="danger"
+              size="mini"
+              icon="el-icon-close"
+              circle
+              @click="cancelEdit('state')" />
+          </div>
+        </div>
+        <div class="detail-row">
+          <span>优先级:</span>
+          <div class="detail-value"  v-if="!isEditing.priority"   @click="editEntry('priority')">
+            <PriorityTag :priority="priority"></PriorityTag>
+            <div class="edit-icon" />
+          </div>
+          <div v-else>
+            <el-select style="width: 160px" size="mini" v-model="editedBug.priority">
+              <el-option
+                v-for="item in  priorityOptions"
+                :key="item.value"
+                :value="item.value"
+                :label="item.label" />
+            </el-select>
+            <el-button
+              style="margin-left: 5px"
+              type="primary"
+              size="mini"
+              icon="el-icon-edit"
+              circle
+              @click="submitEdit('priority')" />
+            <el-button
+              style="margin-left: 5px"
+              type="danger"
+              size="mini"
+              icon="el-icon-close"
+              circle
+              @click="cancelEdit('priority')" />
+          </div>
+        </div>
+        <div class="detail-row">
+          <span>经办人:</span>
+          <div class="detail-value"   v-if="!isEditing.processorId"  @click="editEntry('processorId')">
+            <ElTag>{{userId}}</ElTag>
+            <div class="edit-icon" />
+          </div>
+          <div v-else>
+            <el-select style="width: 160px" size="mini" v-model="editedBug.processorId" >
+              <el-option
+                v-for="item in  processorOptions"
+                :key="item.value"
+                :value="item.value"
+                :label="item.label" />
+            </el-select>
+            <el-button
+              style="margin-left: 5px"
+              type="primary"
+              size="mini"
+              icon="el-icon-edit"
+              circle
+              @click="submitEdit('processorId')" />
+            <el-button
+              style="margin-left: 5px"
+              type="danger"
+              size="mini"
+              icon="el-icon-close"
+              circle
+              @click="cancelEdit('processorId')" />
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="12">
+        <div class="detail-row">
+          <span>工作量:</span>
+          <div class="detail-value" v-if="!isEditing.timeToTake" @click="editEntry('timeToTake')">
+            <span>{{timeToTake}}h</span>
+            <div class="edit-icon" />
+          </div>
+          <div v-else >
+            <el-input-number size="mini" v-model="editedBug.timeToTake" :min="1" :max="200"/>
+            <el-button
+              style="margin-left: 5px"
+              type="primary"
+              size="mini"
+              icon="el-icon-edit"
+              circle
+              @click="submitEdit('timeToTake')" />
+            <el-button
+              style="margin-left: 5px"
+              type="danger"
+              size="mini"
+              icon="el-icon-close"
+              circle
+              @click="cancelEdit('timeToTake')" />
+          </div>
+        </div>
+        <div class="detail-row">
+          <span>创建时间:</span>
+          <span>{{startTime}}</span>
+        </div>
+        <div class="detail-row"><span>完成时间:</span>
+          <span>{{endTime}}</span></div>
+      </el-col>
+    </el-row>
+    <!-- 相关提交 -->
+    <el-row class="entry-row" style="margin-top: 15px">
+      <h4>相关提交(0)</h4>
+    </el-row>
+  </div>
+
+</template>
+
+<script>
+import PriorityTag from '@/components/PriorityTag.vue';
+import StateTag from '@/components/StateTag.vue';
+import { BugListAPI, RequirementAPI } from '@/api';
+
+export default {
+  name: 'BugDrawerContent',
+  components: { PriorityTag, StateTag },
+  props: {
+    id: Number,
+    title: String,
+    description: String,
+    state: String,
+    priority: String,
+    processorId: Number,
+    processorName: String,
+    timeToTake: Number,
+    startTime: String,
+    endTime: String,
+  },
+  data() {
+    return {
+      isEditing: {
+        title: false,
+        description: false,
+        state: false,
+        timeToTake: false,
+        priority: false,
+        processorId: false,
+      },
+      editedBug: {
+        title: null,
+        description: null,
+        state: null,
+        timeToTake: null,
+        priority: null,
+        processorId: null,
+      },
+      stateOptions: [
+        { label: '已创建', value: 0 },
+        { label: '进行中', value: 1 },
+        { label: '已完成', value: 2 },
+      ],
+      priorityOptions: [
+        { label: '紧急', value: 1 },
+        { label: '宽松', value: 2 },
+        { label: '一般', value: 3 },
+      ],
+      processorOptions: [],
+    };
+  },
+  mounted() {
+    this.getProcessorOptions();
+  },
+  methods: {
+    getProcessorOptions() {
+      this.processorOptions = [
+        { label: 'cyt', value: 1 },
+        { label: 'hks', value: 2 },
+        { label: 'abc', value: 3 },
+      ];
+    },
+    editEntry(key) {
+      Object.keys(this.isEditing).forEach((item) => {
+        if (key === item) this.isEditing[item] = true;
+        else this.isEditing[item] = false;
+      });
+    },
+    submitEdit(key) {
+      // BugListAPI.updateBugRecord()
+      this.$emit('bug-update');
+    },
+    cancelEdit(key) {
+      this.isEditing[key] = false;
+      this.editedBug[key] = null;
+    },
+    closeDrawer() {
+      this.$emit('close-drawer');
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.drawer-content{
+  width: 100%;
+  padding: 10px;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+.entry-row{
+  width: 100%;
+  margin: 3px 20px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-start;
+  .edit-icon{
+    margin-left: 5px;
+    display: none;
+    cursor: pointer;
+    width: 20px;
+    height: 20px;
+    background-position: center;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    transition: all .2s linear;
+    background-image: url("../assets/icon/edit.svg");
+    &:hover{
+      background-image: url("../assets/icon/edit_hover.svg");
+    }
+  }
+  &:hover .edit-icon{
+    display: block;
+  }
+  h3, h4{
+    color: #172b4d
+  }
+}
+.detail-row{
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  line-height: 24px;
+  margin: 3px 0;
+  .edit-icon{
+    margin-left: 5px;
+    display: none;
+    width: 20px;
+    height: 20px;
+    background-position: center;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    transition: all .2s linear;
+    background-image: url("../assets/icon/edit.svg");
+    cursor: pointer;
+    &:hover{
+      background-image: url("../assets/icon/edit_hover.svg");
+    }
+  }
+  &:hover .edit-icon{
+    display: block;
+  }
+}
+.detail-value{
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+.node-type{
+  color: #FFFFFF;
+  border-radius: 3px;
+  font-size: 14px;
+  background-color: #42b983;
+  padding: 1px 4px;
+  margin-right: 4px;
+}
+.state-entry{
+  border-radius: 5px;
+  background-color: cornflowerblue;
+  font-size: 12px;
+  color: #FFFFFF;
+  padding: 0px 4px;
+  cursor: pointer
+}
+</style>

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

@@ -6,6 +6,23 @@
     @add="addBugRecord"
     @row-click="openDrawer"
   />
+  <ElDrawer v-model="showAddBugDrawer" size="650px">
+    <template #title>
+      <h3>新建缺陷记录</h3>
+    </template>
+    <template #default>
+      <AddBugDrawerContent
+        @cancel-add="this.showAddBugDrawer=false"
+      @finish-add="refresh"></AddBugDrawerContent>
+    </template>
+  </ElDrawer>
+  <ElDrawer v-model="showBugDetailDrawer"  :with-header="false" size="650px">
+    <template #default>
+      <BugDrawerContent
+        v-bind="selectedBug"
+        @close-drawer="showBugDetailDrawer=false" @bug-update="refresh"></BugDrawerContent>
+    </template>
+  </ElDrawer>
 </div>
 </template>
 
@@ -13,12 +30,17 @@
 import { BugListAPI } from '@/api';
 
 import GeneralTable from '@/components/GeneralTable.vue';
+import AddBugDrawerContent from '@/components/AddBugDrawerContent.vue';
+import BugDrawerContent from '@/components/BugDrawerContent.vue';
 
 export default {
-  components: { GeneralTable },
+  components: { BugDrawerContent, AddBugDrawerContent, GeneralTable },
   data() {
     return {
       bugList: [],
+      showAddBugDrawer: false,
+      showBugDetailDrawer: false,
+      selectedBug: null,
     };
   },
   mounted() {
@@ -29,12 +51,19 @@ export default {
       this.bugList = await BugListAPI.getBugListByProjectId(this.$store.state.workspace.currentProjectId);
     },
     openDrawer(row) {
+      this.selectedBug = Array.prototype.find.call(this.bugList, (bug) => bug.id === row.id);
+      this.showBugDetailDrawer = true;
       // 打开详情抽屉
       console.log(row);
     },
     addBugRecord() {
+      this.showAddBugDrawer = true;
       // TODO: 添加一条bug记录
     },
+    refresh() {
+      this.fetch();
+      this.showAddBugDrawer = false;
+    },
   },
 };
 </script>

+ 0 - 1
src/views/Project/Schedule.vue

@@ -7,7 +7,6 @@
   </el-row>
   <Tree :data="requirements" @change="handleTreeChange" @nodeClick="handleNodeClick" ref="tree"></Tree>
   <ElDrawer v-model="showRequirementDrawer"  :with-header="false" size="650px">
-    <!-- TODO: 供展示和编辑节点详情,可在taskList中复用  -->
     <template #default>
       <TaskDrawerContent
         @change="handleDrawerContentChange"