wenbobowen il y a 4 ans
Parent
commit
db801f016a
50 fichiers modifiés avec 2494 ajouts et 53 suppressions
  1. 1 1
      package.json
  2. 46 0
      src/api/admin/index.js
  3. 81 0
      src/api/publishTask.js
  4. 16 0
      src/api/toConfigure.js
  5. 138 0
      src/components/actionDynamic/index.vue
  6. 32 0
      src/components/checkListStopConfirm/index.vue
  7. 54 0
      src/components/headTitle/index.vue
  8. 8 2
      src/components/input/normalArea.vue
  9. 11 3
      src/components/input/textArea.vue
  10. 47 2
      src/components/newLayout/Head.vue
  11. 50 0
      src/components/redTipTitle/index.vue
  12. 0 1
      src/components/select/searchPeople.vue
  13. 1 0
      src/icons/svg/add.svg
  14. 10 0
      src/icons/svg/admin-model1.svg
  15. 4 0
      src/icons/svg/admin_check.svg
  16. 10 0
      src/icons/svg/admin_model.svg
  17. 8 0
      src/icons/svg/admin_业务线.svg
  18. 1 0
      src/icons/svg/del.svg
  19. 1 5
      src/icons/svg/problem.svg
  20. 7 0
      src/router/index.js
  21. 26 0
      src/styles/detail-pages.scss
  22. 0 1
      src/views/Platform/MyTinymce/MyTinymce.vue
  23. 0 3
      src/views/Platform/teamPage.vue
  24. 0 4
      src/views/Platform/testPage.vue
  25. 85 0
      src/views/ToConfigure/components/adminIndex.vue
  26. 22 2
      src/views/ToConfigure/components/bizConfigure.vue
  27. 0 1
      src/views/ToConfigure/components/modifyNotice.vue
  28. 96 0
      src/views/ToConfigure/components/toConfigureNodel.vue
  29. 6 2
      src/views/ToConfigure/index.vue
  30. 71 0
      src/views/administrators/components/adminContent.vue
  31. 127 0
      src/views/administrators/components/adminNav.vue
  32. 109 0
      src/views/administrators/components/createAdmin.vue
  33. 145 0
      src/views/administrators/index.vue
  34. 0 1
      src/views/online-quality/HistoryTask/taskDetails.vue
  35. 0 1
      src/views/onlineProblem/problemUpdate.vue
  36. 0 10
      src/views/projectManage/components/record.vue
  37. 30 2
      src/views/projectManage/projectList/components/taskList.vue
  38. 55 0
      src/views/projectManage/publishTask/components/checkboxList.vue
  39. 144 0
      src/views/projectManage/publishTask/components/multipleSelect.vue
  40. 287 0
      src/views/projectManage/publishTask/components/onlineCheckList.vue
  41. 85 0
      src/views/projectManage/publishTask/components/step.vue
  42. 555 0
      src/views/projectManage/publishTask/index.vue
  43. 30 2
      src/views/projectManage/requirement/components/taskList.vue
  44. 0 1
      src/views/projectManage/taskList/components/scheduleList.vue
  45. 51 3
      src/views/projectManage/taskList/taskViewDetail.vue
  46. 0 1
      src/views/quality/components/requireDrawer.vue
  47. 0 1
      src/views/quality/defectStatistics.vue
  48. 44 2
      src/views/reportManagement/testPresentation.vue
  49. 0 1
      src/views/useCase/components/requirementCase.vue
  50. 0 1
      src/views/workbench/team/index.vue

+ 1 - 1
package.json

@@ -63,7 +63,7 @@
     "vue-json-viewer": "^2.2.8",
     "vue-qr": "^2.2.1",
     "vue-router": "3.0.6",
-    "vuedraggable": "^2.23.2",
+    "vuedraggable": "^2.24.3",
     "vuex": "3.1.0",
     "wangeditor": "^3.1.1",
     "webpack": "^4.44.2",

+ 46 - 0
src/api/admin/index.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+import { TeamManagement } from '@/apiConfig/api'
+
+// 创建checkList
+export function createTemplate(data) {
+  return request({
+    url: TeamManagement + `/checklist/createTemplate`,
+    method: 'post',
+    data
+  })
+}
+
+// 编辑checkList
+export function updateTemplate(data) {
+  return request({
+    url: TeamManagement + `/checklist/updateTemplate`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取checkList列表
+export function selectTemplates(data) {
+  return request({
+    url: TeamManagement + `/checklist/selectTemplates`,
+    method: 'post',
+    data
+  })
+}
+
+// 删除checkList
+export function deleteTemplate(data) {
+  return request({
+    url: TeamManagement + `/checklist/deleteTemplate?templateId=${data}`,
+    method: 'get'
+  })
+}
+
+// 删除业务线checklist模板
+export function deleteBizTemplate(data) {
+  return request({
+    url: TeamManagement + `/checklist/deleteBizTemplate`,
+    method: 'post',
+    data
+  })
+}

+ 81 - 0
src/api/publishTask.js

@@ -0,0 +1,81 @@
+// 项目
+import request from '@/utils/request'
+import { TeamManagement } from '@/apiConfig/api'
+
+console.log(TeamManagement)
+// 获取项目列表
+const host = TeamManagement
+export function getCheckListBytask(data) {
+  return request({
+    url: `${host}/checklist/getByTask?taskId=${data.taskId}`,
+    method: 'get'
+  })
+}
+
+export function getBizBindTemList(data) {
+  return request({
+    url: `${host}/checklist/selectTemplates`,
+    method: 'post',
+    data
+  })
+}
+
+export function getOnlineBizModule(data) {
+  return request({
+    url: `${host}/checklist/selectBizModule?taskId=${data.taskId}&moduleName=${data.moduleName}`,
+    method: 'get',
+    data
+  })
+}
+
+export function updateChecklist(data) {
+  return request({
+    url: `${host}/checklist/update`,
+    method: 'post',
+    data
+  })
+}
+
+export function createChecklist(data) {
+  return request({
+    url: `${host}/checklist/create`,
+    method: 'post',
+    data
+  })
+}
+
+// 更新checklist下模板的check状态
+export function updateTemplateCheckStatus(data) {
+  return request({
+    url: `${host}/checklist/updateTemplateCheckStatus`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取评论列表
+export function getCommentList(data) {
+  return request({
+    url: `${host}/comment/list`,
+    method: 'post',
+    data
+  })
+}
+
+// 创建评论列表/comment/create
+export function createComment(data) {
+  return request({
+    url: `${host}/comment/create`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取变更记录列表
+export function getRecordList(data) {
+  return request({
+    url: `${host}/operationLog/checkList`,
+    method: 'post',
+    data
+  })
+}

+ 16 - 0
src/api/toConfigure.js

@@ -178,3 +178,19 @@ export function updateBiz(data) {
   })
 }
 
+// 查询该业务线可添加的checkoutlist模块
+export function selectBizUnAddTemplates(data) {
+  return request({
+    url: TeamManagement + `/checklist/selectBizUnAddTemplates?bizId=${data}`,
+    method: 'get'
+  })
+}
+
+// 新增业务线checklist模板
+export function addBizTemplates(data) {
+  return request({
+    url: TeamManagement + `/checklist/addBizTemplates`,
+    method: 'post',
+    data
+  })
+}

+ 138 - 0
src/components/actionDynamic/index.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="actionDynamic">
+    <el-tabs v-model="activeName" @tab-click="changeTabs">
+      <el-tab-pane label="评论" name="Comments">
+        <div class="Comments">
+          <div class="maxHeight">
+            <div
+              v-for="(item, index) in comments"
+              :key="index"
+            >
+              <div style="font-size: 14px; color: #333b4a; display: inline-block">
+                {{ item.commentInfo.name }}
+              </div>
+              <div
+                style="
+                  margin-left: 20px;
+                  display: inline-block;
+                  color: #9b9b9b;
+                  font-size: 12px;
+                "
+              >
+                {{ item.commentInfo.gmtCreater }}
+              </div>
+              <p
+                style="
+                  font-size: 14px;
+                  color: #333b4a;
+                  margin: 0 0 25px 0;
+                  white-space: pre-line;
+                "
+              >
+                {{ item.commentInfo.content }}
+              </p>
+            </div>
+          </div>
+          <el-input
+            v-model="commentContent"
+            type="textarea"
+            placeholder="请输入评论内容"
+            maxlength="1000"
+            show-word-limit
+            :autosize="{ minRows: 3, maxRows: 5 }"
+            style="margin-bottom: 2%"
+          />
+          <el-button
+            type="primary"
+            size="small"
+            style="float: right"
+            @click="$emit('addComment', commentContent, callback)"
+          >
+            发表评论
+          </el-button>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="变更记录" name="Logs">
+        <div class="maxHeight">
+          <div v-for="(item,index) in changeRecord" :key="index" class="Layout_space_between sign-record">
+            <span class="content">
+              <span class="operatorName">{{ item.operator }} : </span>
+              <span class="remark">{{ item.remark }}</span>
+            </span>
+            <span class="createTime">{{ item.createTime }}</span>
+          </div>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+<script>
+import '@/styles/PublicStyle/index.scss'
+export default {
+  props: {
+    comments: {
+      type: Array,
+      required: false,
+      default: () => []
+    },
+    changeRecord: {
+      type: Array,
+      required: false,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      activeName: 'Comments',
+      commentContent: ''
+    }
+  },
+  methods: {
+    changeTabs(e) {
+      console.log(e)
+    },
+    callback() {
+      console.log('chengg')
+      this.commentContent = ''
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.actionDynamic {
+  padding: 0px 30px 20px 30px;
+  .Comments {
+    padding: 0 34px 20px 34px;
+  }
+  .maxHeight {
+    max-height: 300px;
+    overflow-y: auto;
+  }
+}
+.sign-record {
+  margin: 20px 0;
+  font-size:14px;
+  line-height:20px;
+  opacity:1;
+  font-family:PingFangSC-Regular;
+}
+.createTime {
+  min-width:150px;
+  color:rgba(68,68,68,1);
+}
+
+.remark {
+  min-width:500px;
+  text-align: left;
+  color:#444444;
+}
+.operatorName {
+  min-width: 60px;
+  color:rgba(51,59,74,1);
+  margin-right: 10px;
+}
+.content {
+  display: inline-block;
+  margin-right: 60px;
+}
+</style>

+ 32 - 0
src/components/checkListStopConfirm/index.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="dialog-main">
+    <el-dialog
+      title="设置checklist"
+      :visible.sync="visible"
+      width="30%"
+      :close-on-click-modal="false"
+      :show-close="false"
+    >
+      <div style="position: absolute; top: 23px; left: 12px;width:4px;height:17px;background:#409EFF;border-radius:1px;" />
+      <div align="center">
+        <div>是否需为任务设置发布checklist?</div>
+        <div style="color: #f79232;">您所在的业务线要求提测前设置发布checklist</div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button type="primary" size="mini" @click="$emit('confirm')">是,去设置</el-button>
+        <el-button type="danger" size="mini" @click="$emit('cancel')">不需要</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    visible: {
+      type: Boolean,
+      default: false,
+      required: true
+    }
+  }
+}
+</script>

+ 54 - 0
src/components/headTitle/index.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="main-title">
+    <div class="title-left-icon" />
+    <div class="title-left-name">{{ title }}</div>
+    <div v-if="openEdit" class="editBtn">
+      <i class="el-icon-edit" @click="$emit('editHandle')" />
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    title: {
+      type: String,
+      required: true
+    },
+    openEdit: {
+      type: Boolean,
+      required: false
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.main-title {
+  align-items: center;
+  padding: 20px 30px;
+  .title-left-icon {
+    width: 4px;
+    height: 17px;
+    background: #409eff;
+    border-radius: 1px;
+    display: inline-block;
+    vertical-align: text-top;
+  }
+  .title-left-name {
+    display: inline-block;
+    width: auto;
+    height: 20px;
+    line-height: 20px;
+    font-size: 16px;
+    font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,"\5FAE\8F6F\96C5\9ED1",Arial,sans-serif;
+    color: #333b4a;
+    margin-left: 6px;
+  }
+  .editBtn {
+    display: inline-block;
+    .el-icon-edit {
+      color: #1890FF;
+      margin-left: 6px;
+    }
+  }
+}
+</style>

+ 8 - 2
src/components/input/normalArea.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <article :id="id">
+    <article :id="id" :style="styles">
       <editor :id="'tinymce_'+id" ref="editor" v-model="inputValue" :init="init" @input="changeText" />
     </article>
   </div>
@@ -10,7 +10,6 @@ import tinymce from 'tinymce/tinymce'
 import Editor from '@tinymce/tinymce-vue'
 import 'tinymce/themes/silver/theme'
 import 'tinymce/icons/default/icons'
-
 export default {
   components: {
     Editor
@@ -30,6 +29,13 @@ export default {
       type: Number,
       default: 200,
       required: false
+    },
+    styles: {
+      type: Object,
+      default: () => {
+        return { }
+      },
+      required: false
     }
   },
   data() {

+ 11 - 3
src/components/input/textArea.vue

@@ -3,6 +3,7 @@
     <article
       :id="id"
       v-loading="loading"
+      :style="styles"
       element-loading-text="数据上传中,请稍后"
       element-loading-spinner="el-icon-loading"
     >
@@ -39,6 +40,13 @@ export default {
     Editor
   },
   props: {
+    styles: {
+      type: Object,
+      default: () => {
+        return { padding: '0 30px 20px 30px' }
+      },
+      required: false
+    },
     id: {
       type: String,
       default: '',
@@ -149,9 +157,9 @@ export default {
 }
 </script>
 <style scoped lang="scss">
-article {
-  padding: 0 30px 20px 30px;
-}
+// article {
+//   padding: 0 30px 20px 30px;
+// }
 .text-edit {
   color: #666666;
   font-size: 14px;

+ 47 - 2
src/components/newLayout/Head.vue

@@ -36,7 +36,7 @@
     <div v-if="userInfo" class="user-info">
       <a-popover placement="rightBottom" overlay-class-name="head-popover">
         <template #content>
-          <div class="user-control">
+          <div :class="memberCheck ? 'user-admin-one' : 'user-admin'">
             <div class="user-name">{{ userInfo.name }}</div>
             <div class="line" />
             <div class="user-logout">
@@ -44,6 +44,10 @@
               <el-button v-if="navTagType === 2" type="primary" plain size="small" @click="setNavTagType(1)">侧边导航</el-button>
             </div>
             <div class="line" />
+            <div v-if="memberCheck" class="user-logout">
+              <el-button type="primary" plain size="small" @click="administratorsJump()"> 管 理 员 </el-button>
+            </div>
+            <div v-if="memberCheck" class="line" />
             <div class="user-logout">
               <el-button type="primary" plain size="small" @click="layout()">退出登录</el-button>
             </div>
@@ -61,12 +65,14 @@ import websocket from '@/views/workbench/mixins/websocket'
 import { memberGetLoginInMemberInfoByLdap } from '@/api/projectIndex'
 import { logoutUrl } from '@/apiConfig/requestIP.js'
 import { log } from '@/utils/global'
+import { verifyIsAdmin } from '@/api/configure.js'
 export default {
   mixins: [websocket],
   data() {
     return {
       headList: routes.filter(item => item.name !== '业务线'),
       userInfo: null,
+      memberCheck: false,
       target: true
     }
   },
@@ -83,6 +89,7 @@ export default {
   },
   created() {
     this.getLoginUser()
+    this.verifyIsAdmin()
   },
   methods: {
     goto(name) {
@@ -123,6 +130,11 @@ export default {
       const res = await memberGetLoginInMemberInfoByLdap()
       if (res && res.data) this.userInfo = res.data || null
     },
+    // 查看是否为管理员
+    async verifyIsAdmin() {
+      const res = await verifyIsAdmin()
+      if (res.code === 200) this.memberCheck = res.data
+    },
     // 退出登录
     layout() {
       window.location.href = logoutUrl
@@ -130,6 +142,9 @@ export default {
     topHome() {
       this.$router.push({ path: '/' })
     },
+    administratorsJump() {
+      this.$router.push({ name: '管理员' })
+    },
     // websocket数据接收
     websocketonmessage(e) {
       const { hasReminding } = JSON.parse(e.data)
@@ -231,7 +246,7 @@ export default {
     height: 30px;
   }
 }
-.user-control {
+.user-admin {
   height: 143px;
   width: 95px;
   display: flex;
@@ -246,6 +261,36 @@ export default {
     background-color: rgba(112, 112, 112, 0.2);
   }
 }
+.user-admin-one {
+  height: 190px;
+  width: 95px;
+  display: flex;
+  flex-direction: column;
+  display: grid;
+  grid-template-rows: 47px 1px 47px 1px 47px;
+  justify-items: center;
+  align-items: center;
+  .line {
+    width: 100%;
+    height: 1px;
+    background-color: rgba(112, 112, 112, 0.2);
+  }
+}
+
+// .user-control {
+//   width: 95px;
+//   display: flex;
+//   flex-direction: column;
+//   display: grid;
+//   grid-template-rows: 47px 1px 47px 1px 47px;
+//   justify-items: center;
+//   align-items: center;
+//   .line {
+//     width: 100%;
+//     height: 1px;
+//     background-color: rgba(112, 112, 112, 0.2);
+//   }
+// }
 </style>
 <style lang="scss" scoped>
 .head-popover {

+ 50 - 0
src/components/redTipTitle/index.vue

@@ -0,0 +1,50 @@
+<template>
+  <p class="redTipword" :style="styles">
+    <span class="title" :class="isedit && 'edit'">{{ title }}</span>
+  </p>
+</template>
+<script>
+export default {
+  name: 'Tipword',
+  props: {
+    title: {
+      type: String,
+      required: true
+    },
+    isedit: {
+      type: Boolean,
+      required: false,
+      default: false
+    },
+    styles: {
+      type: Object,
+      default: () => {
+        return {}
+      },
+      required: false
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.redTipword {
+  vertical-align: middle;
+  margin: 35px 0 10px 0px;
+  .title {
+    font-size: 16px;
+    font-weight: 400;
+    line-height: 18px;
+    color: #444;
+  }
+  &:first-child {
+    margin-top: 0px;
+  }
+  .edit {
+    &::before{
+      content: '*';
+      color: #F56C6C;
+      margin-right: 4px;
+    }
+  }
+}
+</style>

+ 0 - 1
src/components/select/searchPeople.vue

@@ -74,7 +74,6 @@ export default {
   watch: {
     value: {
       handler(newV, oldV) {
-        console.log(this.searchValue, newV, this.searchValue === newV)
         if (this.searchValue === newV) {
           return
         }

+ 1 - 0
src/icons/svg/add.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><defs><style>.cls-1{fill:#409eff}</style></defs><g id="添加_2_" data-name="添加 (2)" transform="translate(-138.581 -138.581)"><path id="路径_13078" data-name="路径 13078" class="cls-1" d="M271.147 491.958h-7.309c-.186 0-.328-.095-.328-.219s.142-.219.328-.219h7.309c.186 0 .328.095.328.219s-.142.219-.328.219z" transform="translate(-121.911 -346.152)"/><path id="路径_13079" data-name="路径 13079" class="cls-1" d="M491.739 271.482c-.124 0-.219-.142-.219-.329v-7.315c0-.186.095-.329.219-.329s.219.142.219.329v7.315c0 .186-.095.329-.219.329z" transform="translate(-346.158 -121.91)"/><path id="路径_13080" data-name="路径 13080" class="cls-1" d="M151.468 152.581h-11.773a1.115 1.115 0 01-1.113-1.114V139.7a1.115 1.115 0 011.113-1.114h11.773a1.115 1.115 0 011.113 1.114v11.78a1.12 1.12 0 01-1.113 1.101zm-11.773-13.231a.362.362 0 00-.346.346v11.771a.362.362 0 00.346.346h11.773a.344.344 0 00.346-.346V139.7a.362.362 0 00-.346-.346z"/></g></svg>

+ 10 - 0
src/icons/svg/admin-model1.svg

@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="13.055" height="14.26" viewBox="0 0 13.055 14.26">
+  <g id="数据模块" transform="translate(-68.946 -10.417)">
+    <path id="路径_13072" data-name="路径 13072" d="M75.35,24.677a.382.382,0,0,1-.218-.064L73.54,23.7a.455.455,0,0,1-.164-.609.446.446,0,0,1,.609-.155l1.364.782,5.339-3.084V18.819a.446.446,0,0,1,.446-.446.437.437,0,0,1,.446.446v2.1a.455.455,0,0,1-.218.391l-5.785,3.3A.409.409,0,0,1,75.35,24.677Zm-4.4-2.583a.409.409,0,0,1-.227,0l-1.383-.819a.455.455,0,0,1-.218-.391V14.207a.455.455,0,0,1,.218-.391l5.794-3.338a.437.437,0,0,1,.446,0l5.785,3.338a.455.455,0,0,1,.218.391v1.455a.437.437,0,0,1-.446.446.446.446,0,0,1-.446-.446v-1.2L75.35,11.379l-5.339,3.084v6.167l1.155.673a.428.428,0,0,1,.164.6A.446.446,0,0,1,70.948,22.094Z" transform="translate(-0.171)" fill="#559df7"/>
+    <path id="路径_13073" data-name="路径 13073" d="M75.179,249.716a.4.4,0,0,1-.218-.064l-5.785-3.275a.437.437,0,0,1-.173-.6.446.446,0,0,1,.609-.173l5.785,3.275a.446.446,0,0,1-.218.837Z" transform="translate(0 -231.788)" fill="#559df7"/>
+    <path id="路径_13074" data-name="路径 13074" d="M489.081,254a.446.446,0,0,1-.218-.837l5.458-3.083a.446.446,0,0,1,.609.173.455.455,0,0,1-.164.609l-5.458,3.083A.482.482,0,0,1,489.081,254Z" transform="translate(-413.72 -236.204)" fill="#559df7"/>
+    <path id="路径_13075" data-name="路径 13075" d="M476.606,482.951a.446.446,0,0,1-.446-.446v-6.531a.455.455,0,1,1,.91,0v6.531a.446.446,0,0,1-.464.446Z" transform="translate(-401.426 -458.493)" fill="#559df7"/>
+    <path id="路径_13076" data-name="路径 13076" d="M842.637,504.717m-1.037,0a1.037,1.037,0,1,0,1.037-1.037A1.037,1.037,0,0,0,841.6,504.717Z" transform="translate(-761.672 -486.253)" fill="#559df7"/>
+    <path id="路径_13077" data-name="路径 13077" d="M159.117,750.477m-1.037,0a1.037,1.037,0,1,0,1.037-1.037A1.037,1.037,0,0,0,158.08,750.477Z" transform="translate(-87.867 -728.52)" fill="#559df7"/>
+  </g>
+</svg>

+ 4 - 0
src/icons/svg/admin_check.svg

@@ -0,0 +1,4 @@
+
+<svg xmlns="http://www.w3.org/2000/svg" width="14.2" height="14.2" viewBox="0 0 14.2 14.2">
+  <path id="模块设置" d="M69.6,64H64.7a.7.7,0,0,0-.7.7v4.9a.7.7,0,0,0,.7.7h4.9a.7.7,0,0,0,.7-.7V64.7a.7.7,0,0,0-.7-.7Zm0,5.6H64.7V64.7h4.9v4.9Zm0,2.1H64.7a.7.7,0,0,0-.7.7v4.9a.7.7,0,0,0,.7.7h4.9a.7.7,0,0,0,.7-.7V72.4a.7.7,0,0,0-.7-.7Zm0,5.6H64.7V72.4h4.9v4.9ZM77.3,64H72.4a.7.7,0,0,0-.7.7v4.9a.7.7,0,0,0,.7.7h4.9a.7.7,0,0,0,.7-.7V64.7A.7.7,0,0,0,77.3,64Zm0,5.6H72.4V64.7h4.9v4.9Zm-4.9,4.9a.349.349,0,0,0-.35.35v2.8a.35.35,0,0,0,.7,0v-2.8A.349.349,0,0,0,72.4,74.5Zm1.75,0a.349.349,0,0,0-.35.35v2.8a.35.35,0,0,0,.7,0v-2.8A.349.349,0,0,0,74.15,74.5Zm1.75-1.4a.349.349,0,0,0-.35.35v4.2a.35.35,0,0,0,.7,0v-4.2A.349.349,0,0,0,75.9,73.1Zm1.75-.7a.349.349,0,0,0-.35.35v4.9a.35.35,0,0,0,.7,0v-4.9A.349.349,0,0,0,77.65,72.4Z" transform="translate(-63.9 -63.9)" fill="#fff" stroke="#fff" stroke-width="0.2"/>
+</svg>

+ 10 - 0
src/icons/svg/admin_model.svg

@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="13.055" height="14.26" viewBox="0 0 13.055 14.26">
+  <g id="数据模块" transform="translate(-68.946 -10.417)">
+    <path id="路径_13072" data-name="路径 13072" d="M75.35,24.677a.382.382,0,0,1-.218-.064L73.54,23.7a.455.455,0,0,1-.164-.609.446.446,0,0,1,.609-.155l1.364.782,5.339-3.084V18.819a.446.446,0,0,1,.446-.446.437.437,0,0,1,.446.446v2.1a.455.455,0,0,1-.218.391l-5.785,3.3A.409.409,0,0,1,75.35,24.677Zm-4.4-2.583a.409.409,0,0,1-.227,0l-1.383-.819a.455.455,0,0,1-.218-.391V14.207a.455.455,0,0,1,.218-.391l5.794-3.338a.437.437,0,0,1,.446,0l5.785,3.338a.455.455,0,0,1,.218.391v1.455a.437.437,0,0,1-.446.446.446.446,0,0,1-.446-.446v-1.2L75.35,11.379l-5.339,3.084v6.167l1.155.673a.428.428,0,0,1,.164.6A.446.446,0,0,1,70.948,22.094Z" transform="translate(-0.171)" fill="#444"/>
+    <path id="路径_13073" data-name="路径 13073" d="M75.179,249.716a.4.4,0,0,1-.218-.064l-5.785-3.275a.437.437,0,0,1-.173-.6.446.446,0,0,1,.609-.173l5.785,3.275a.446.446,0,0,1-.218.837Z" transform="translate(0 -231.788)" fill="#444"/>
+    <path id="路径_13074" data-name="路径 13074" d="M489.081,254a.446.446,0,0,1-.218-.837l5.458-3.083a.446.446,0,0,1,.609.173.455.455,0,0,1-.164.609l-5.458,3.083A.482.482,0,0,1,489.081,254Z" transform="translate(-413.72 -236.204)" fill="#444"/>
+    <path id="路径_13075" data-name="路径 13075" d="M476.606,482.951a.446.446,0,0,1-.446-.446v-6.531a.455.455,0,1,1,.91,0v6.531a.446.446,0,0,1-.464.446Z" transform="translate(-401.426 -458.493)" fill="#444"/>
+    <path id="路径_13076" data-name="路径 13076" d="M842.637,504.717m-1.037,0a1.037,1.037,0,1,0,1.037-1.037A1.037,1.037,0,0,0,841.6,504.717Z" transform="translate(-761.672 -486.253)" fill="#444"/>
+    <path id="路径_13077" data-name="路径 13077" d="M159.117,750.477m-1.037,0a1.037,1.037,0,1,0,1.037-1.037A1.037,1.037,0,0,0,158.08,750.477Z" transform="translate(-87.867 -728.52)" fill="#444"/>
+  </g>
+</svg>

+ 8 - 0
src/icons/svg/admin_业务线.svg

@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="14.5" viewBox="0 0 16 14.5">
+  <g id="业务管理_1_" data-name="业务管理 (1)" transform="translate(-125.673 -130.816)">
+    <path id="路径_13135" data-name="路径 13135" d="M432.95,271.313h-4.3a.43.43,0,0,1,0-.86h4.3a.43.43,0,0,1,0,.86Zm0,2.581h-4.3a.43.43,0,0,1,0-.86h4.3a.43.43,0,1,1,0,.86Z" transform="translate(-296.141 -136.61)" fill="#fff"/>
+    <path id="路径_13136" data-name="路径 13136" d="M320.888,138.989a.43.43,0,0,1-.43-.43v-6.883h-7.743v6.883a.43.43,0,0,1-.86,0v-7.313a.43.43,0,0,1,.43-.43h8.6a.43.43,0,0,1,.43.43v7.313A.43.43,0,0,1,320.888,138.989Z" transform="translate(-181.366 0)" fill="#fff"/>
+    <path id="路径_13137" data-name="路径 13137" d="M198.072,230.359h-2.151a.43.43,0,0,1-.43-.43v-5.592a.43.43,0,0,1,.43-.43h2.151a.43.43,0,0,1,.43.43v5.592A.43.43,0,0,1,198.072,230.359Zm-1.721-.86h1.29v-4.732h-1.29Z" transform="translate(-68.528 -91.37)" fill="#fff"/>
+    <path id="路径_13138" data-name="路径 13138" d="M141.2,532.9H126.143a.452.452,0,0,1-.471-.43v-5.592a.452.452,0,0,1,.471-.43H132.1a.468.468,0,0,1,.446.294l.52,1.426h1.675l.52-1.426a.469.469,0,0,1,.446-.294H141.2a.452.452,0,0,1,.471.43v5.592A.452.452,0,0,1,141.2,532.9Zm-14.588-.86h14.118v-4.732h-4.68l-.52,1.426a.469.469,0,0,1-.446.294h-2.353a.468.468,0,0,1-.446-.294l-.52-1.426h-5.152Z" transform="translate(0 -387.588)" fill="#fff"/>
+  </g>
+</svg>

+ 1 - 0
src/icons/svg/del.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><defs><style>.cls-1{fill:#409eff}</style></defs><g id="添加_2_" data-name="添加 (2)" transform="translate(-138.581 -138.581)"><path id="路径_13078" data-name="路径 13078" class="cls-1" d="M272.138 492.1h-8.258c-.21 0-.371-.125-.371-.288s.161-.288.371-.288h8.258c.21 0 .371.125.371.288s-.16.288-.371.288z" transform="translate(-122.17 -346.22)"/><path id="路径_13080" data-name="路径 13080" class="cls-1" d="M151.468 152.581h-11.773a1.115 1.115 0 01-1.113-1.114V139.7a1.115 1.115 0 011.113-1.114h11.773a1.115 1.115 0 011.113 1.114v11.78a1.12 1.12 0 01-1.113 1.101zm-11.773-13.231a.362.362 0 00-.346.346v11.771a.362.362 0 00.346.346h11.773a.344.344 0 00.346-.346V139.7a.362.362 0 00-.346-.346z"/></g></svg>

+ 1 - 5
src/icons/svg/problem.svg

@@ -1,6 +1,3 @@
-<<<<<<< HEAD
-<svg xmlns="http://www.w3.org/2000/svg" width="13.308" height="14.215"><defs><linearGradient id="a" x1=".5" x2=".5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#409eff"/><stop offset="1" stop-color="#80c9ff"/></linearGradient></defs><g transform="translate(-201.5 -191.2)" fill="url(#a)"><path data-name="路径 13053" d="M212.3 205.415h-9.6a1.157 1.157 0 01-1.2-1.111v-11.993a1.158 1.158 0 011.2-1.111h9.6a1.157 1.157 0 011.2 1.111v1.8a.443.443 0 01-.887 0v-1.8c0-.119-.145-.222-.309-.222h-9.6c-.165 0-.309.1-.309.222V204.3c0 .119.145.222.309.222h9.6c.165 0 .309-.1.309-.222v-.7a.443.443 0 11.887 0v.709a1.156 1.156 0 01-1.2 1.106z"/><path data-name="路径 13054" d="M210.565 195.652h-6.664a.45.45 0 010-.9h6.664a.45.45 0 010 .9zm-1.332 3.095h-5.332a.439.439 0 110-.878h5.329a.439.439 0 110 .878zm1.332 3.117h-6.664a.45.45 0 010-.9h6.664a.45.45 0 010 .9z"/><path data-name="路径 13055" d="M214.363 197.923a.444.444 0 01-.443-.443.91.91 0 10-1.82 0 .444.444 0 01-.887 0 1.8 1.8 0 113.6 0 .445.445 0 01-.45.443z"/><path data-name="路径 13056" d="M213.103 201.123a.444.444 0 01-.443-.443v-.72a1.9 1.9 0 01.56-1.361 1.908 1.908 0 00.694-1.124.451.451 0 01.439-.441.437.437 0 01.443.415 2.553 2.553 0 01-.964 1.789 1 1 0 00-.29.722v.72a.442.442 0 01-.439.443z"/><path data-name="路径 13057" d="M212.62900000000002 201.912a.474.474 0 10.474-.474.474.474 0 00-.474.474z"/></g></svg>
-=======
 
 <svg xmlns="http://www.w3.org/2000/svg" width="8.272" height="9.613" viewBox="0 0 8.272 9.613">
   <g id="问题" transform="translate(-160.5 -103.5)">
@@ -8,5 +5,4 @@
     <path id="路径_433" data-name="路径 433" d="M165.2,112.347h-3.692a1.008,1.008,0,0,1-1.006-1.006v-6.835a1.008,1.008,0,0,1,1.006-1.006h6.26a1.008,1.008,0,0,1,1.006,1.006v3.8a.335.335,0,1,1-.671,0v-3.8a.336.336,0,0,0-.335-.335h-6.26a.336.336,0,0,0-.335.335v6.835a.336.336,0,0,0,.335.335H165.2a.335.335,0,1,1,0,.671Z" fill="#666"/>
     <path id="路径_434" data-name="路径 434" d="M646.23,572.333a.333.333,0,0,1-.335-.332,1.675,1.675,0,0,1,.688-1.32.518.518,0,0,0,.192-.539.538.538,0,0,0-.406-.388.589.589,0,0,0-.5.109.521.521,0,0,0-.2.406.335.335,0,1,1-.671,0,1.186,1.186,0,0,1,.449-.928,1.256,1.256,0,0,1,1.064-.241,1.2,1.2,0,0,1,.913.89,1.188,1.188,0,0,1-.433,1.224,1.014,1.014,0,0,0-.427.784A.34.34,0,0,1,646.23,572.333Zm0,.87a.335.335,0,0,1,0-.671h0a.335.335,0,1,1,0,.671Z" transform="translate(-478.799 -460.089)" fill="#666"/>
   </g>
-</svg>
->>>>>>> http_mock
+</svg>

+ 7 - 0
src/router/index.js

@@ -69,6 +69,13 @@ export const constantRoutes = [{
   hidden: true
 },
 
+{
+  path: '/administrators',
+  name: '管理员',
+  component: () => import('@/views/administrators/index.vue'),
+  hidden: true
+},
+
 {
   path: '/env-platform',
   component: Layout,

+ 26 - 0
src/styles/detail-pages.scss

@@ -171,4 +171,30 @@
       margin-bottom: 0;
     }
   }
+}
+@mixin main-title {
+  align-items: center;
+  padding: 20px 30px;
+  .title-left-icon {
+    width: 4px;
+    height: 17px;
+    background: #409eff;
+    border-radius: 1px;
+    display: inline-block;
+    vertical-align: text-top;
+  }
+  .title-left-name {
+    display: inline-block;
+    width: auto;
+    height: 20px;
+    line-height: 20px;
+    font-size: 16px;
+    font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,"\5FAE\8F6F\96C5\9ED1",Arial,sans-serif;
+    color: #333b4a;
+    margin-left: 6px;
+  }
+}
+p {
+  padding: 0;
+  margin: 0;
 }

+ 0 - 1
src/views/Platform/MyTinymce/MyTinymce.vue

@@ -75,7 +75,6 @@ export default {
       this.value = e
       this.$emit('change', e)
       this.$store.state.data.RichText = e
-      console.log(this.$store.state.data.RichText)
     }
   }
 }

+ 0 - 3
src/views/Platform/teamPage.vue

@@ -209,7 +209,6 @@ export default {
 
     // 查询
     queryList(val) {
-      console.log(val)
       getMemberList(val).then(res => {
         this.list = res.data
         // this.form = {}
@@ -248,7 +247,6 @@ export default {
 
     // 编辑
     changeData(vel) {
-      console.log(vel)
       this.titleName = '编辑'
       this.MemberData = vel
       this.updateDetailDialog(2)
@@ -299,7 +297,6 @@ export default {
       }
     },
     clickFun(e) {
-      console.log(e)
       this.startId = e.value
       this.startName = e.label
       getMemberList({ teamId: e.value }).then(res => {

+ 0 - 4
src/views/Platform/testPage.vue

@@ -418,7 +418,6 @@ export default {
     },
 
     handleSizeChange1(size) {
-      console.log(size, '1')
       this.pageSize_one = size
       this.pageIndex1()
     },
@@ -633,7 +632,6 @@ export default {
 
     // 点击节点
     clickFun(e) {
-      console.log(e)
       this.test_plan = {}
       this.pegs = ''
       e.codes === '1' ? this.Parentids = e.id : ''
@@ -669,7 +667,6 @@ export default {
       updateTestPlanCase({ creator: this.userInformation, modifier: this.userInformation, id: ele.ids, status: 3, testPlanId: ele.thrr }).then(res => { this.implement() })
     },
     Unclicked4(e, index, ele) {
-      console.log(ele)
       this.gridData[index].keys = 0
       updateTestPlanCase({ creator: this.userInformation, modifier: this.userInformation, id: ele.ids, status: 0, testPlanId: ele.thrr }).then(res => { this.implement() })
     },
@@ -702,7 +699,6 @@ export default {
 
     // 删除table信息
     deleteCaseData(e) {
-      console.log(e, '删除')
       this.$confirm('是否确认删除', '确认信息', {
         distinguishCancelAndClose: true,
         confirmButtonText: '确定',

+ 85 - 0
src/views/ToConfigure/components/adminIndex.vue

@@ -0,0 +1,85 @@
+<template>
+  <div>
+    <el-container class="admin-back">
+      <el-aside width="215px" class="admin-conent">
+        <!-- 导航 -->
+        <admin-nav :datas="datas" :type="1" @delete="deleteTemplate" @createDialog="show = true" @clickName="getNavList" @querySelect="selectTemplates" />
+        <!-- 导航 -->
+      </el-aside>
+      <el-main style="padding: 0; margin-left: 10px" class="admin-conent">
+        <!-- 内容 -->
+        <adminContent :data="admin_content" :type="1" />
+        <!-- 内容 -->
+        <!-- 创建/编辑 -->
+        <Configure ref="configure" :show.sync="show" :title="'增加模版项'" @update="selectTemplates" />
+        <!-- 创建/编辑 -->
+      </el-main>
+    </el-container>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import { selectTemplates, deleteBizTemplate } from '@/api/admin/index'
+import Configure from './toConfigureNodel.vue'
+import adminNav from '@/views/administrators/components/adminNav.vue'
+import adminContent from '@/views/administrators/components/adminContent.vue'
+export default {
+  components: {
+    adminContent,
+    adminNav,
+    Configure
+  },
+  data() {
+    return {
+      show: false,
+      datas: [],
+      admin_content: {}
+    }
+  },
+  computed: {
+    ...mapGetters(['bizId'])
+  },
+  created() {
+    this.selectTemplates()
+  },
+  methods: {
+    async selectTemplates(val) {
+      this.show = false
+      const ruleForm = { bizId: this.bizId }
+      if (val) {
+        ruleForm.name = val
+        delete ruleForm.content
+        delete ruleForm.type
+      }
+      const res = await selectTemplates(ruleForm)
+      if (res.code === 200) {
+        this.admin_content = res.data[0] || { name: '', content: '暂无数据' }
+        this.datas = res.data || [{ name: '', content: '暂无数据' }]
+      }
+    },
+    async deleteTemplate(cal) {
+      const res = await deleteBizTemplate({ bizId: this.bizId, templateId: cal.id })
+      if (res.code === 200) {
+        this.selectTemplates()
+        this.$refs.configure.selectBizUnAddTemplates()
+        this.$message({ message: '模块删除成功', type: 'success', duration: 1000, offset: 150 })
+      }
+    },
+    getNavList(val) {
+      this.admin_content = val
+    }
+  }
+}
+</script>
+
+<style>
+.admin-back {
+   background: #f2f3f6;
+}
+.admin-conent {
+  min-height: calc(100vh - 80px);
+  border-radius: 4px;
+  background: #FFF;
+}
+</style>

+ 22 - 2
src/views/ToConfigure/components/bizConfigure.vue

@@ -10,7 +10,21 @@
     </el-radio-group>
     <el-button v-if="!Prohibit" size="small" class="biz_buttom" @click="cancel"> 取消 </el-button>
     <el-button v-if="!Prohibit" size="small" class="biz_buttom" type="primary" @click="preservation"> 保存 </el-button>
-
+    <!--- ck ---->
+    <p class="biz_property">
+      提测前checklist拦截
+      <el-tooltip class="item" effect="dark" content="设置为拦截后,业务线发送提测报告前会校验checklist是否已创建" placement="top">
+        <i class="el-icon-info" />
+      </el-tooltip>
+      <i v-if="!isCkEdit" class="el-icon-edit icon-sty" @click="isCkEdit = true" />
+    </p>
+    <el-radio-group v-model="ckStatus" :disabled="!isCkEdit" class="biz_radio">
+      <el-radio label="1"> 拦截 </el-radio>
+      <el-radio label="0"> 不拦截</el-radio>
+    </el-radio-group>
+    <el-button v-if="isCkEdit" size="small" class="biz_buttom" @click="cancel"> 取消 </el-button>
+    <el-button v-if="isCkEdit" size="small" class="biz_buttom" type="primary" @click="preservation"> 保存 </el-button>
+    <!-- ck -->
     <div v-if="bizObj.fromDpm">
       <p class="biz_property">
         排期同步望岳
@@ -39,6 +53,8 @@ export default {
       radio: '1',
       Prohibit: true,
       Schedule: true, // 排期同步望岳
+      isCkEdit: false, // checklist编辑
+      ckStatus: '0', // ckecklist状态
       bizObj: {},
       num: 30
     }
@@ -62,18 +78,22 @@ export default {
         this.bizObj = res.data[0]
         this.num = this.bizObj.syncScheduleDpm
         this.radio = JSON.stringify(this.bizObj.isSecret)
+        this.ckStatus = '' + this.bizObj.isChecklistIntercept
       }
     },
     async preservation() { // 保存业务线配置
-      const res = await settingUpdateBiz({ id: this.bizId, isSecret: Number(this.radio), bizName: this.bizObj.name })
+      const res = await settingUpdateBiz({ id: this.bizId, isSecret: Number(this.radio), bizName: this.bizObj.name, isChecklistIntercept: Number(this.ckStatus) })
       if (res.code === 200) {
         this.Prohibit = true
+        this.isCkEdit = false
         this.$message({ message: '修改成功', type: 'success', duration: 1000, offset: 150 })
       }
     },
     cancel() {
       this.Prohibit = true
+      this.isCkEdit = false
       this.radio = JSON.stringify(this.bizObj.isSecret)
+      this.ckStatus = '' + this.bizObj.isChecklistIntercept
     },
     async changeSchedule() { // 设置同步望岳时间
       const res = await updateBiz({ id: this.bizId, syncScheduleDpm: this.num })

+ 0 - 1
src/views/ToConfigure/components/modifyNotice.vue

@@ -316,7 +316,6 @@ export default {
     'formData.clientId': { // 客户端改变,版本默认取第一个版本
       handler(newV) {
         // this.formData.clientVersionId = (this.clientList[0] && this.clientList[0].code) || null
-        console.log(newV)
         if (newV === null || newV === '' || newV === undefined) {
           this.formData.clientVersionId = null
         }

+ 96 - 0
src/views/ToConfigure/components/toConfigureNodel.vue

@@ -0,0 +1,96 @@
+<template>
+  <el-dialog :title="title" :visible.sync="show" width="30%" class="demo-dialog" :before-close="handleClose" :close-on-click-modal="false">
+    <div class="blueStripe" />
+    <el-form ref="ruleForm" :model="ruleForm" label-position="left" status-icon :rules="rules" label-width="80px">
+      <el-form-item label="请选择" prop="name">
+        <el-select v-model="ruleForm.name" multiple placeholder="请选择" style="width: 100%;">
+          <el-option v-for="(item,index) in modelList" :key="item.id + index" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="handleClose">取 消</el-button>
+      <el-button type="primary" @click="createTemplate">保 存</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import { selectBizUnAddTemplates, addBizTemplates } from '@/api/toConfigure.js'
+export default {
+  props: {
+    data: { type: Object, default: null },
+    show: { type: Boolean, default: false, required: true },
+    title: { type: String, default: '增加模版项' }
+  },
+  data() {
+    return {
+      ruleForm: {
+        name: []
+      },
+      modelList: [],
+      rules: {
+        name: [{ required: true, message: '请输入名称', trigger: 'change' }]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['bizId'])
+  },
+  created() {
+    this.selectBizUnAddTemplates()
+  },
+  methods: {
+    async selectBizUnAddTemplates() {
+      const res = await selectBizUnAddTemplates(this.bizId)
+      if (res.code === 200) {
+        this.modelList = res.data
+      }
+    },
+    createTemplate() {
+      this.$refs.ruleForm.validate(async(valid) => {
+        if (valid) {
+          const data = { bizId: this.bizId, templateIds: this.ruleForm.name }
+          const res = await addBizTemplates(data)
+          if (res.code === 200) {
+            this.selectBizUnAddTemplates()
+            this.$emit('update')
+            this.$nextTick(() => {
+              this.$refs.ruleForm.resetFields()
+            })
+            this.$message({ message: '模块添加成功', type: 'success', duration: 1000, offset: 150 })
+          }
+        }
+      })
+    },
+    handleClose() {
+      this.$emit('update')
+      this.ruleForm.name = []
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.demo-ruleForm {
+  padding: 0 30px;
+}
+.demo-dialog {
+  /deep/ .el-dialog__title {
+    line-height: 24px;
+    font-size: 16px;
+    color: #303133;
+    padding-left: 10px;
+}
+}
+.blueStripe {
+  width:4px;
+  height:17px;
+  background:#409EFF;
+  border-radius:1px;
+  position: absolute;
+  top: 23px;
+  left: 20px;
+}
+</style>

+ 6 - 2
src/views/ToConfigure/index.vue

@@ -7,6 +7,7 @@
         <el-tab-pane label="需求方向配置" name="second" />
         <el-tab-pane label="技术模块配置" name="third" />
         <el-tab-pane label="通知配置" name="fourth" />
+        <el-tab-pane label="checklist模版" name="check" />
         <el-tab-pane label="业务线配置" name="fourths" />
       </el-tabs>
     </el-header>
@@ -23,7 +24,8 @@
         <Business v-if="tabIndex === '1'" class="member_padding" />
         <Technology v-if="tabIndex === '2'" class="member_padding" />
         <notice-config v-if="tabIndex === '3'" class="member_padding" />
-        <biz-configure v-if="tabIndex === '4'" class="member_padding" />
+        <admin-page v-if="tabIndex === '4'" />
+        <biz-configure v-if="tabIndex === '5'" class="member_padding" />
       </el-main>
     </el-container>
   </el-container>
@@ -36,6 +38,7 @@ import Technology from './components/businessTechnology.vue'
 import noticeConfig from './components/noticeConfig.vue'
 import memberConfiguration from './components/memberConfiguration.vue'
 import MemberDetails from './components/MemberDetails.vue'
+import adminPage from './components/adminIndex.vue'
 
 export default {
   components: {
@@ -44,7 +47,8 @@ export default {
     Technology,
     noticeConfig,
     memberConfiguration,
-    MemberDetails
+    MemberDetails,
+    adminPage
   },
   data() {
     return {

+ 71 - 0
src/views/administrators/components/adminContent.vue

@@ -0,0 +1,71 @@
+<template>
+  <el-container>
+    <el-header style="height: auto;">
+      <div class="admin-content-title">{{ data.name }}
+        <i v-if="data.type === 2 && type !== 1" class="el-icon-edit admin-content-update" @click="$emit('update', '编辑', data)" />
+      </div>
+    </el-header>
+    <el-main>
+      <div v-html="data.content" />
+      <div v-if="data.onlineModule" class="admin-content-online admin-content-start">
+        <span style="margin-right: 10px;">上线顺序</span>
+        <div v-for="(item, index) in onlineOrder" :key="index" style="margin: 0 10px;">
+          <div class="admin-content-start admin-content-item"><div class="admin-content-code">{{ index + 1 }}</div> {{ item }} </div>
+        </div>
+      </div>
+    </el-main>
+  </el-container>
+</template>
+
+<script>
+export default {
+  props: {
+    data: { type: Object, required: true },
+    type: { type: Number, default: 1 }
+  },
+  data() {
+    return {
+      onlineOrder: ['A', 'B', 'C']
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.admin-content-title {
+  font-size: 16px;
+  font-family: PingFang SC;
+  font-weight: 500;
+  padding-top: 20px;
+  color: #444444;
+}
+.admin-content-item {
+  font-weight: 400;
+  color: #999999;
+  font-size: 14px;
+}
+.admin-content-code {
+  width: 16px;
+  height: 16px;
+  line-height: 14px;
+  text-align: center;
+  border: 1px solid #999;
+  border-radius: 50%;
+  margin: 2px 5px;
+}
+.admin-content-online {
+  font-size: 14px;
+  font-family: Microsoft Sans Serif;
+  font-weight: 400;
+  color: #444444;
+  margin: 20px 0;
+}
+.admin-content-start {
+  display: flex;
+  justify-content: flex-start;
+}
+.admin-content-update {
+  cursor: pointer;
+  color: #409eff;
+}
+</style>

+ 127 - 0
src/views/administrators/components/adminNav.vue

@@ -0,0 +1,127 @@
+<template>
+  <el-container>
+    <el-header class="admin-nav-header admin-nav-between">
+      <el-input v-model="admin_query" placeholder="请输入内容" clearable size="small" @change="$emit('querySelect', admin_query)">
+        <i slot="prefix" class="el-input__icon el-icon-search" />
+      </el-input>
+      <div class="admin-nav-div">
+        <i class="el-icon-circle-plus-outline admin-nav-icon" @click="$emit('createDialog', '新建')" />
+      </div>
+    </el-header>
+    <el-main style="padding: 10px; max-height: calc(100vh - 129px); overflow-y: auto;">
+      <div v-for="(item, index) in admin_navList" :key="index" class="admin-nav-between admin-nav-col">
+        <div class="admin-nav-start admin-nav-cursor">
+          <svg-icon :icon-class="index === adminColor ? 'admin-model1' : 'admin_model'" />
+          <el-tooltip v-if="item.name.length >= 9" class="item" effect="dark" :content="item.name" placement="top">
+            <div class="admin-nav-name admin-nav-cursor" :class="{'admin-name-color': index === adminColor}" @click="$emit('clickName', item), adminColor = index"> {{ item.name }} </div>
+          </el-tooltip>
+          <div v-else class="admin-nav-name admin-nav-cursor" :class="{'admin-name-color': index === adminColor}" @click="$emit('clickName', item), adminColor = index"> {{ item.name }} </div>
+        </div>
+        <i v-if="type === 1" class="el-icon-close admin-nav-cursor" @click="deleteModel = true, deleteId = item" />
+        <i v-else-if="item.type === 2" class="el-icon-close admin-nav-cursor" @click="deleteModel = true, deleteId = item" />
+      </div>
+    </el-main>
+
+    <el-dialog title="移除确认" :visible.sync="deleteModel" class="demo-dialog" width="30%">
+      <div class="blueStripe" />
+      <div align="center">是否要移除 {{ deleteId.name }} ? </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="deleteModel = false">取 消</el-button>
+        <el-button type="primary" @click="$emit('delete', deleteId), deleteModel = false">确 定</el-button>
+      </span>
+    </el-dialog>
+  </el-container>
+</template>
+
+<script>
+export default {
+  props: {
+    datas: { type: Array, required: true },
+    type: { type: Number, default: 1 }
+  },
+  data() {
+    return {
+      adminColor: '',
+      deleteModel: false, // 删除dialog
+      deleteId: {},
+      admin_query: '', // checkList模版查询
+      admin_navList: []
+    }
+  },
+  watch: {
+    datas: {
+      handler(newV) {
+        this.admin_navList = newV
+      },
+      deep: true
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.admin-nav-header {
+  padding: 15px 10px;
+}
+.admin-nav-icon {
+  border-radius: 4px;
+  margin-left: 10px;
+  line-height: 34px;
+  font-size: 20px;
+  cursor: pointer;
+  color: #888;
+}
+.admin-nav-icon:hover {
+  color: #409eff;
+}
+.admin-nav-between {
+  display: flex;
+  justify-content: space-between;
+}
+.admin-nav-start {
+  display: flex;
+  justify-content: flex-start;
+}
+
+.admin-nav-col {
+  line-height: 15px;
+  margin-bottom: 20px;
+}
+.admin-nav-div {
+  line-height: 30px;
+}
+.admin-nav-cursor:hover {
+  cursor: pointer;
+  color: #409eff;
+}
+.admin-name-color {
+  color:  #409eff;
+}
+.admin-nav-name {
+  width: 149px;
+  font-size: 14px;
+  font-family: Microsoft Sans Serif;
+  font-weight: 400;
+  padding-left: 10px;
+  overflow: hidden;
+  text-overflow:ellipsis;
+  white-space: nowrap;
+}
+.demo-dialog {
+  /deep/ .el-dialog__title {
+    line-height: 24px;
+    font-size: 16px;
+    color: #303133;
+    padding-left: 10px;
+}
+}
+.blueStripe {
+  width:4px;
+  height:17px;
+  background:#409EFF;
+  border-radius:1px;
+  position: absolute;
+  top: 23px;
+  left: 20px;
+}
+</style>

+ 109 - 0
src/views/administrators/components/createAdmin.vue

@@ -0,0 +1,109 @@
+<template>
+  <el-dialog :title="title" :visible.sync="show" width="60%" class="demo-dialog" :before-close="handleClose">
+    <div class="blueStripe" />
+    <el-form ref="ruleForm" :model="ruleForm" label-position="left" status-icon :rules="rules" label-width="60px" class="demo-ruleForm">
+      <el-form-item label="名称" prop="name">
+        <el-input v-model="ruleForm.name" placeholder="请输入模版名称" />
+      </el-form-item>
+      <el-form-item label="内容" prop="content">
+        <normal-area :id="'admin-template' + title" :value.sync="ruleForm.content" :height="394" />
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="handleClose">取 消</el-button>
+      <el-button type="primary" @click="createTemplate"> {{ title === '新建模版' ? '创 建' : '保 存' }}</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import normalArea from '@/components/input/normalArea' // 富文本
+import 'tinymce/plugins/table'// 插入表格插件
+import { createTemplate, updateTemplate } from '@/api/admin/index'
+export default {
+  components: {
+    normalArea
+  },
+  props: {
+    data: { type: Object, default: null },
+    show: { type: Boolean, default: false, required: true },
+    title: { type: String, default: '标题' }
+  },
+  data() {
+    return {
+      ruleForm: {},
+      rules: {
+        name: [
+          { required: true, message: '请输入名称', trigger: 'change' },
+          { max: 20, message: '最多20个字符', trigger: 'blur' }
+        ],
+        content: [{ required: true, message: '富文本不能为空', trigger: 'change' }]
+      }
+    }
+  },
+  watch: {
+    data: {
+      handler(newV) {
+        if (newV) {
+          this.ruleForm = newV
+        } else {
+          this.$refs.ruleForm.resetFields()
+          this.ruleForm = {}
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    createTemplate() {
+      this.ruleForm.type = 2
+      this.ruleForm.isCheck = false
+      this.ruleForm.belongType = 1
+      this.$refs.ruleForm.validate(async(valid) => {
+        if (valid) {
+          if (this.title === '新建模版') {
+            const res = await createTemplate(this.ruleForm)
+            if (res.code === 200) {
+              this.$emit('update')
+              this.$message({ message: '模块添加成功', type: 'success', center: true })
+            }
+          } else if (this.title === '编辑模版') {
+            const res = await updateTemplate(this.ruleForm)
+            if (res.code === 200) {
+              this.$emit('update')
+              this.$message({ message: '模块修改成功', type: 'success', center: true })
+            }
+          }
+        }
+      })
+    },
+    handleClose() {
+      this.$emit('update')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.demo-ruleForm {
+  padding: 0 30px;
+}
+.demo-dialog {
+  /deep/ .el-dialog__title {
+    line-height: 24px;
+    font-size: 16px;
+    color: #303133;
+    padding-left: 10px;
+}
+}
+.blueStripe {
+  width:4px;
+  height:17px;
+  background:#409EFF;
+  border-radius:1px;
+  position: absolute;
+  top: 23px;
+  left: 20px;
+}
+</style>

+ 145 - 0
src/views/administrators/index.vue

@@ -0,0 +1,145 @@
+<template>
+  <el-container>
+    <el-header class="admin-title" style="padding: 0;">
+      <div class="admin-zhihui" @click="$router.push({ name: '首页' })"><img :src="logo"> 质惠</div>
+      <div class="admin-title">
+        <div class="admin-nav"><svg-icon icon-class="admin_业务线" class="admin-margin" /> 业务线管理</div>
+        <div class="admin-nav, admin-nav-background" @click="jump()"><svg-icon icon-class="admin_check" class="admin-margin" /> checklist模块管理</div>
+      </div>
+    </el-header>
+    <el-container class="admin-back">
+      <el-aside width="215px" class="admin-conent">
+        <!-- 导航 -->
+        <admin-nav
+          :type="2"
+          :datas="datas"
+          @querySelect="querySelect"
+          @close="show = false"
+          @createDialog="createDialog"
+          @clickName="getNavList"
+          @delete="deleteTemplate"
+        />
+        <!-- 导航 -->
+      </el-aside>
+      <el-main style="padding: 0; margin: 10px" class="admin-conent">
+        <!-- 内容 -->
+        <adminContent :data="admin_content" :type="2" @update="createDialog" />
+        <!-- 内容 -->
+        <!-- 创建/编辑 -->
+        <adminDialog :show.sync="show" :title="admin_title + '模版'" :data="admin_data_list" @update="selectTemplates" />
+        <!-- 创建/编辑 -->
+      </el-main>
+    </el-container>
+  </el-container>
+</template>
+
+<script>
+import logoUrl from '@/assets/内页logo2@2x.png'
+import adminNav from './components/adminNav.vue'
+import adminContent from './components/adminContent.vue'
+import adminDialog from './components/createAdmin.vue'
+import { deleteTemplate, selectTemplates } from '@/api/admin/index'
+export default {
+  components: {
+    adminNav,
+    adminContent,
+    adminDialog
+  },
+  data() {
+    return {
+      show: false,
+      datas: [],
+      logo: logoUrl,
+      admin_content: {},
+      admin_data_list: {},
+      admin_title: '新建'
+    }
+  },
+  created() {
+    this.selectTemplates()
+  },
+  methods: {
+    async selectTemplates(val) {
+      this.show = false
+      const ruleForm = { name: '', content: '', type: 2, belongType: 1 }
+      if (val) {
+        ruleForm.name = val
+        delete ruleForm.content
+        delete ruleForm.type
+      }
+      const res = await selectTemplates(ruleForm)
+      if (res.code === 200) {
+        this.admin_content = res.data[0]
+        this.datas = res.data
+      }
+    },
+    createDialog(ele, val) { // 新建还是编辑
+      this.admin_data_list = val
+      this.admin_title = ele
+      this.show = true
+    },
+    querySelect(val) { // 查询
+      this.selectTemplates(val)
+    },
+    async deleteTemplate(ele) {
+      const res = await deleteTemplate(ele.id)
+      if (res.code === 200) {
+        this.selectTemplates()
+        this.$message({ message: '模块移除成功', type: 'success', center: true })
+      }
+    },
+    getNavList(val) { // 点击导航展示content
+      this.admin_content = val
+    },
+    jump() {
+      this.$router.push({ name: '管理员' })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.admin-title {
+  background: #409eff;
+  line-height: 60px;
+  color: #FFFFFF;
+  font-size: 14px;
+  display: flex;
+  justify-content: flex-start;
+}
+.admin-zhihui {
+  width: 215px;
+  text-align: center;
+  color: #FFFFFF;
+  font-weight: 600;
+  font-size: 20pt;
+  cursor: pointer;
+  font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+  }
+.admin-nav {
+  cursor: pointer;
+  margin: 0 50px 0 20px;
+  padding: 0 10px;
+}
+.admin-nav:hover {
+  background: #1e89f7;
+}
+
+.admin-nav-background {
+  cursor: pointer;
+  margin: 0 50px 0 20px;
+  padding: 0 10px;
+  background: #1e89f7;
+}
+.admin-back {
+   background: #eee;
+}
+.admin-margin {
+  margin-right: 10px;
+}
+.admin-conent {
+  min-height: calc(100vh - 80px);
+  border-radius: 4px;
+  background: #FFF;
+}
+</style>

+ 0 - 1
src/views/online-quality/HistoryTask/taskDetails.vue

@@ -175,7 +175,6 @@ export default {
       getCheckResult({ taskId: this.taskId })
         .then(res => {
           this.task = res.data
-          console.log(this.task)
           if (this.task.checkResultJson) { this.task.checkResultJson = JSON.parse(this.task.checkResultJson) }
           if (this.task.diffResultJson) { this.task.diffResultJson = JSON.parse(this.task.diffResultJson) }
           if (this.task.checkResultJson.lineName) {

+ 0 - 1
src/views/onlineProblem/problemUpdate.vue

@@ -389,7 +389,6 @@ export default {
           this.uptataKey.splice(i, 1)
         }
       }
-      console.log(this.uptataKey)
     },
     // 提交表单并且返回刷新
     createFormData(form) {

+ 0 - 10
src/views/projectManage/components/record.vue

@@ -4,17 +4,7 @@
     <div v-for="(item,index) in changeRecord" :key="index" class="Layout_space_between sign-record">
       <span>
         <span class="operatorName">{{ item.operator }} : </span>
-        <!-- <el-tooltip
-          v-if="item.remark.length > 50"
-          class="item"
-          effect="dark"
-          :content="item.remark"
-          placement="top-start"
-          popper-class="tip-style"
-        > -->
         <span class="remark">{{ item.remark }}</span>
-        <!-- </el-tooltip>
-        <span v-else class="remark">{{ item.remark.length > 50 ? item.remark.substring(0, 50) + '...' : item.remark }}</span> -->
       </span>
       <span class="createTime">{{ item.createTime }}</span>
     </div>

+ 30 - 2
src/views/projectManage/projectList/components/taskList.vue

@@ -117,12 +117,18 @@
       title="新建排期"
       @update="get_allTask()"
     />
+    <checkListStopConfirm
+      :visible="checklistStopVisible"
+      @confirm="checklistConfirm"
+      @cancel="checklistCancel"
+    />
   </div>
 </template>
 <script>
 import { analysisBizId_id, EncryptId } from '@/utils/crypto-js.js'
 import { mapGetters } from 'vuex'
 import imgUrl from '@/assets/建立档案@2x.png'
+import checkListStopConfirm from '@/components/checkListStopConfirm'
 import TestReport from '@/views/reportManagement/components/TestingReport' // 提测
 import DailyReport from '@/views/reportManagement/components/DailyReport' // 日报
 import ReleaseReport from '@/views/reportManagement/components/ReleaseReport' // 准出
@@ -141,7 +147,8 @@ export default {
     ReleaseReport,
     scheduleList,
     taskDialog,
-    modifySchedule
+    modifySchedule,
+    checkListStopConfirm
   },
   data() {
     return {
@@ -167,7 +174,9 @@ export default {
       nowChangeTask: null, // 当前正在改变的任务对象
       taskId: '', // 将要修改状态的任务id
       visibleSchedule: false, // 排期弹框
-      selectTaskList: [] // 已选任务的id
+      selectTaskList: [], // 已选任务的id
+      checklistStopVisible: false, // checklist拦截弹窗是否显示
+      firstChecklistTaskId: -1
     }
   },
   computed: {
@@ -297,6 +306,11 @@ export default {
       const data = this.curcentList.map(item => { return item.id })
       const res = await reportdelivertestCheckStatus(data)
       if (res.code === 200) {
+        if (res.data) {
+          this.checklistStopVisible = true
+          this.firstChecklistTaskId = res.data
+          return
+        }
         this.dialogTestReport = true
         this.$nextTick(() => {
           this.$refs.TestReport.init(7, this.curcentList.map(item => { return item.id }))
@@ -329,6 +343,20 @@ export default {
     link_task(id) { // 跳转到任务详情页
       const bizId_id = EncryptId(`${this.bizId}_${id}`)
       this.$router.push({ name: '任务详情', query: { bizId_id: bizId_id }})
+    },
+    checklistConfirm() {
+      this.checklistStopVisible = false
+      const { bizId = null } = this.$store.state.global || {}
+      const bizId_id = EncryptId(`${bizId}_${this.firstChecklistTaskId}`)
+      const newTab = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id, page: 6 }})
+      window.open(newTab.href, '_blank')
+    },
+    checklistCancel() {
+      this.checklistStopVisible = false
+      this.dialogTestReport = true
+      this.$nextTick(() => {
+        this.$refs.TestReport.init(7, this.curcentList.map(item => { return item.id }))
+      })
     }
   }
 }

+ 55 - 0
src/views/projectManage/publishTask/components/checkboxList.vue

@@ -0,0 +1,55 @@
+<template>
+  <div class="checkboxList">
+    <el-checkbox-group v-model="List" @change="$emit('change', List)">
+      <el-checkbox v-for="item in data" :key="item.id" class="checkbox" :label="item.id">{{ item.name }}</el-checkbox>
+    </el-checkbox-group>
+  </div>
+</template>
+<script>
+// const cityOptions = ['上海', '北京', '广州', '深圳', 'ss', 'qq', 'www', 'eeee', 'ssss', 'vvvv', 'ggg', 'jjj']
+export default {
+  props: {
+    selectedList: {
+      type: Array,
+      required: false,
+      default: () => []
+    },
+    data: {
+      type: Array,
+      required: false,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      checkAll: false,
+      // checkedCities: ['上海', '北京'],
+      // cities: cityOptions,
+      isIndeterminate: true,
+      List: this.selectedList
+    }
+  },
+  methods: {
+    handleCheckAllChange(val) {
+      // this.checkedCities = val ? cityOptions : []
+      this.isIndeterminate = false
+    },
+    handleCheckedCitiesChange(value) {
+      const checkedCount = value.length
+      this.checkAll = checkedCount === this.cities.length
+      this.isIndeterminate = checkedCount > 0 && checkedCount < this.cities.length
+    }
+  }
+}
+</script>
+<style scoped lang='scss'>
+.checkboxList {
+  width: 800px;
+  .checkbox {
+    // width: 130px;
+    // margin-right: 50px;
+    margin: 10px 40px 10px 0;
+  }
+}
+
+</style>

+ 144 - 0
src/views/projectManage/publishTask/components/multipleSelect.vue

@@ -0,0 +1,144 @@
+<template>
+  <div class="taskSelect" :style="styles">
+    <el-select
+      v-if="isedit"
+      v-model="value"
+      class="maxWidth"
+      :size="size"
+      multiple
+      filterable
+      remote
+      reserve-keyword
+      :placeholder="placeholder"
+      :remote-method="remoteMethod"
+      :loading="loading"
+      @change="clearHandle"
+    >
+      <el-option
+        v-for="item in options"
+        :key="item.id"
+        :value="item.id"
+      >
+        <p class="content" style="margin: 0">
+          <span>
+            <span class="taskId">TASK-{{ item.id }}</span>
+            <span class="ml20">{{ item.name }}</span>
+          </span>
+          <!-- <i v-if="isedit" class="el-icon-circle-close didi-hover" @click="$emit('delate', item.id)" /> -->
+        </p>
+      </el-option>
+    </el-select>
+    <div class="maxWidth">
+      <p v-for="item in data" :key="item.id" class="content">
+        <span>
+          <span class="taskId">TASK-{{ item.id }}</span>
+          <span class="ml20 title" @click="goto(item.id)">{{ item.name }}</span>
+        </span>
+        <i v-if="isedit" class="el-icon-circle-close didi-hover" @click="$emit('change', item, 'del')" />
+      </p>
+    </div>
+  </div>
+</template>
+<script>
+import { taskList } from '@/api/taskIndex'
+import { EncryptId } from '@/utils/crypto-js.js'
+export default {
+  name: 'MultipleSelect',
+  props: {
+    styles: {
+      type: Object,
+      required: false,
+      default: () => {
+        return { maxWidth: '690px' }
+      }
+    },
+    size: {
+      type: String,
+      required: false,
+      default: 'medium'
+    },
+    placeholder: {
+      type: String,
+      required: false,
+      default: '请输入'
+    },
+    isedit: {
+      type: Boolean,
+      required: false,
+      default: false
+    },
+    data: {
+      type: Array,
+      required: false,
+      default: () => []
+    },
+    taskId: {
+      type: Number,
+      required: false,
+      default: null
+    }
+  },
+  data() {
+    return {
+      options: [],
+      value: [],
+      loading: false
+    }
+  },
+  methods: {
+    async remoteMethod(query) {
+      this.query = query
+      if (query !== '') {
+        this.loading = true
+        const res = await taskList({ taskId: this.taskId, name: query })
+        this.options = res.data
+        this.loading = false
+      } else {
+        this.options = []
+      }
+    },
+    clearHandle(val) {
+      let item = null
+      this.options.forEach(t => {
+        if (t.id === val[0]) {
+          item = t
+        }
+      })
+      this.$emit('change', item, 'add')
+      this.query = ''
+      this.value = null
+    },
+    goto(id) {
+      const { bizId = null } = this.$store.state.global || {}
+      const bizId_id = EncryptId(`${bizId}_${id}`)
+      const newTab = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id }})
+      window.open(newTab.href, '_blank')
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.taskSelect {
+  .maxWidth {
+    width: 100%;
+  }
+  .ml20 {
+    margin-left: 20px;
+  }
+}
+.content {
+  display: flex;
+  justify-content: space-between;
+  margin: 10px 0;
+  .taskId {
+    display: inline-block;
+    width: 120px;
+  }
+  .title {
+    cursor: pointer;
+    &:hover {
+      color: #007aff;
+    }
+  }
+}
+</style>

+ 287 - 0
src/views/projectManage/publishTask/components/onlineCheckList.vue

@@ -0,0 +1,287 @@
+<template>
+  <div class="onlineCheckList" :style="styles">
+    <table class="table">
+      <tr>
+        <th class="">模块</th>
+        <th>模块名</th>
+      </tr>
+      <tr v-for="(d, index) in data.tableContent" :key="d.id">
+        <td>
+          <el-input v-if="isedit" v-model="d.module" placeholder="请输入模块" :size="size" />
+          <span v-else>{{ d.module }}</span>
+        </td>
+        <td>
+          <div v-if="isedit" class="addmodule">
+            <el-select
+              v-model="value"
+              class="addSelect"
+              :size="size"
+              multiple
+              filterable
+              remote
+              reserve-keyword
+              placeholder="请选择模块"
+              :remote-method="remoteMethod"
+              :loading="loading"
+              @change="clearHandle(index)"
+            >
+              <el-option
+                v-for="item in options"
+                :key="item"
+                :label="item"
+                :value="item"
+              />
+            </el-select>
+            <span class="addBtn" @click="addModule(index)">添加</span>
+          </div>
+          <div v-if="isedit">
+            <el-tag
+              v-for="tag in d.moduleNames"
+              :key="tag"
+              class="tag"
+              size="small"
+              closable
+              type="info"
+              @close="handleClose(index, tag)"
+            >
+              {{ tag }}
+            </el-tag>
+          </div>
+          <div v-else>
+            <span v-for="tag in d.moduleNames" :key="tag" class="tag word">{{ tag }}</span>
+          </div>
+          <div v-if="isedit" class="btnGroup">
+            <svg-icon icon-class="add" class="svg" @click="$emit('changeRow', 'add', moduleId, index)" />
+            <svg-icon v-if="data.tableContent.length !== 1" icon-class="del" class="svg" @click="$emit('changeRow', 'del', moduleId, index)" />
+          </div>
+        </td>
+      </tr>
+    </table>
+    <div class="inlineList">
+      <div class="subTitle">
+        上线顺序
+        <el-tooltip effect="dark" content="鼠标拖动模块,可调整顺序" placement="top-start">
+          <i class="el-icon-info" />
+        </el-tooltip>
+      </div>
+      <div class="itemList">
+        <draggable
+          v-if="isedit"
+          v-model="data.onlineOrder"
+          chosen-class="chosen"
+          force-fallback="true"
+          group="people"
+          animation="1000"
+          @start="onStart"
+          @end="onEnd"
+        >
+          <transition-group>
+            <div
+              v-for="(element, index) in data.onlineOrder"
+              :key="element"
+              class="onlineItem"
+            >
+              <span class="dragNo">{{ index+ 1 }}</span>
+              <span class="dragword">{{ element }}</span>
+            </div>
+          </transition-group>
+        </draggable>
+        <div v-else>
+          <div
+            v-for="(element, index) in data.onlineOrder"
+            :key="element"
+            class="onlineItem textItem"
+          >
+            <span class="dragNo">{{ index+ 1 }}</span>
+            <span class="dragword">{{ element }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import draggable from 'vuedraggable'
+import { getOnlineBizModule } from '@/api/publishTask'
+export default {
+  components: {
+    draggable
+  },
+  props: {
+    isedit: {
+      type: Boolean,
+      required: false,
+      default: false
+    },
+    data: {
+      type: Object,
+      required: false,
+      default: () => {}
+    },
+    moduleId: {
+      type: Number,
+      required: true,
+      default: -1
+    },
+    taskId: {
+      type: Number,
+      required: false,
+      default: null
+    },
+    styles: {
+      type: Object,
+      default: () => {
+        return {}
+      },
+      required: false
+    }
+  },
+  data() {
+    return {
+      drag: false,
+      options: [],
+      value: [],
+      loading: false,
+      size: 'small',
+      moduleName: '',
+      name: ''
+    }
+  },
+  methods: {
+    async remoteMethod(moduleName) {
+      this.moduleName = moduleName
+      if (moduleName !== '') {
+        this.loading = true
+        const res = await getOnlineBizModule({ taskId: this.taskId, moduleName })
+        this.options = res.data
+        this.loading = false
+      } else {
+        this.options = []
+      }
+    },
+    clearHandle(subIdx) {
+      this.$emit('changeSelectedHandle', this.moduleId, subIdx, this.value[0], 'add')
+      this.moduleName = ''
+      this.value = null
+    },
+    addModule(subIdx) {
+      if (this.moduleName) {
+        this.$emit('changeSelectedHandle', this.moduleId, subIdx, this.moduleName, 'add')
+      }
+    },
+    handleClose(subIdx, val) {
+      this.$emit('changeSelectedHandle', this.moduleId, subIdx, val, 'del')
+    },
+    // 开始拖拽事件
+    onStart() {
+      this.drag = true
+    },
+    // 拖拽结束事件
+    onEnd() {
+      this.drag = false
+    }
+  }
+}
+</script>
+<style scoped lang='scss'>
+.onlineCheckList {
+  width: 690px;
+  padding-bottom: 20px;
+  .table {
+    width: 100%;
+    border-radius: 4px;
+    border-collapse: collapse;
+    border: none;
+    th {
+      background: #E8E8E8;
+      text-align: center;
+      color: '#333B4A';
+      font-size: '14px';
+      font-weight: '400';
+      &:first-child {
+        width: 216px;
+      }
+    }
+    th, td {
+      border: 1px solid #D1D0D0;
+      padding: 12px 10px;
+      position: relative;
+      &:first-child {
+        text-align: center;
+      }
+    }
+    .btnGroup {
+      position: absolute;
+      bottom: 0px;
+      right: -60px;
+      width: 60px;
+      text-align: center;
+      .svg {
+        margin: 0 5px;
+        font-size: 14px;
+      }
+    }
+  }
+  .inlineList {
+    .itemList {
+      width: 800px;
+      // margin-top: 10px;
+      .onlineItem {
+        display: inline-block;
+        margin: 10px 20px 0px 0px;
+        font-size: 14px;
+        border: solid 2px transparent;
+        cursor: move;
+        &.textItem{
+          cursor: text;
+        }
+      }
+    }
+    .dragNo {
+      display: inline-block;
+      width: 16px;
+      height:16px;
+      line-height: 14px;
+      text-align: center;
+      border: 1px solid #999;
+      border-radius: 50%;
+      margin-right: 5px;
+    }
+    .dragword {
+      font-size: 14px;
+    }
+    .subTitle {
+      margin-top: 16px;
+      .el-icon-info {
+        color: #999;
+      }
+    }
+  }
+  .tag {
+    margin-right: 12px;
+    margin-bottom: 5px;
+    &.word {
+      margin-right: 0px;
+      &::after{
+        content: ',';
+      }
+      &:last-child::after {
+        content: '';
+      }
+    }
+  }
+  .addmodule {
+    margin-bottom: 5px;
+    .addBtn {
+      font-size: 12px;
+      color: #409eff;
+      margin-left: 6px;
+      cursor: pointer;
+    }
+  }
+}
+
+.chosen {
+  border: solid 2px #3089dc !important;
+}
+</style>

+ 85 - 0
src/views/projectManage/publishTask/components/step.vue

@@ -0,0 +1,85 @@
+<template>
+  <div class="stepBox">
+    <div class="line">
+      <span class="before circle" />
+      <div v-for="item in data" :key="item.parentTemplateId" class="subTitle" @click="$emit('goto', `s${item.parentTemplateId}`)">
+        <i class="el-icon-success icon" :class="getclass(item.parentTemplateId)" />
+        {{ item.name }}
+      </div>
+      <span class="after circle" />
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    data: {
+      type: Array,
+      default: () => [],
+      required: false
+    },
+    typeList: {
+      type: Array,
+      default: () => [],
+      required: false
+    }
+  },
+  methods: {
+    getclass(id) {
+      let type = 'el-icon-question'
+      this.typeList.map(t => {
+        if (t.parentTemplateId === id && t.isCheck) {
+          type = 'el-icon-success'
+        }
+      })
+      return type
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.line {
+  border-right: 2px solid #D1D1D1;
+  position: relative;
+  padding: 2px 0;
+  .circle {
+    display: inline-block;
+    width: 6px;
+    height: 6px;
+    border-radius: 50%;
+    border: 1px solid #666;
+    background-color: #fff;
+    position: absolute;
+    left: calc(100% - 2px);
+  }
+  .subTitle {
+    width: 200px;
+    text-align: center;
+    margin: 16px 0px 16px 50%;
+    padding: 0 16px;
+    background: #fff;
+    cursor: pointer;
+    position: relative;
+    color: #444;
+    .icon {
+      position: absolute;
+      left: 0px;
+      top: 4px;
+      font-size: 14px;
+    }
+    .el-icon-success {
+      color: #1890FF;
+    }
+    .el-icon-question {
+      color: #999;
+    }
+  }
+  .before {
+    top: 0px;
+    margin-bottom: 8px;
+  }
+  .after {
+    bottom: 0px;
+  }
+}
+</style>

+ 555 - 0
src/views/projectManage/publishTask/index.vue

@@ -0,0 +1,555 @@
+<template>
+  <div class="editPublishTask">
+    <section class="main-section pubconfig">
+      <div v-if="showEmpty">
+        <header>
+          <headTitle title="checklist" />
+        </header>
+        <div class="empty">
+          未设置 <span class="createBtn" @click="addAction">点击添加</span>
+        </div>
+      </div>
+      <div v-else>
+        <header>
+          <headTitle title="checklist" :open-edit="openEdit" @editHandle="editHandle" />
+        </header>
+        <div class="wrap">
+          <redTipword title="关联任务" :isedit="edit" />
+          <multipleSelect placeholder="🔍 请输入任务名称或ID" :isedit="edit" :data="data.tasks" :task-id="taskId" @change="changeTask" />
+          <div v-if="edit" style="margin-top: 40px">
+            <redTipword title="选择checklist列表" :isedit="edit" />
+            <checkboxList :selected-list="data.selectedBizTemplateIds" :data="temList" @change="updateSelectedTemHandle" />
+          </div>
+        </div>
+        <div class="moduleList wrap">
+          <redTipword v-if="!edit" title="检查项" :isedit="edit" :styles="{ marginTop: '40px' }" />
+          <div class="checkBox">
+            <div v-for="(item, index) in data.templates" :key="item.parentTemplateId">
+              <div v-if="item.type === 1" class="item">
+                <p :id="`s${item.parentTemplateId}`" class="title">
+                  <el-checkbox v-if="!edit" v-model="item.isCheck" :label="item.name" class="fontRest" @change="updateCheckItemHandle(item)">{{ item.name }}</el-checkbox>
+                  <span v-else class="fontName">{{ item.name }}</span>
+                </p>
+                <onlineCheckList
+                  :module-id="item.parentTemplateId"
+                  :isedit="edit"
+                  :styles="{ marginLeft: '24px' }"
+                  :data="item.onlineModule"
+                  :task-id="taskId"
+                  @changeSelectedHandle="changeOnlineSelectedHandle"
+                  @changeRow="changeOnlineModuleRow"
+                  @onChangeModuleName="(val, subIdx) => onChangeModuleName(val, subIdx, index)"
+                />
+              </div>
+              <div v-else class="item">
+                <p :id="`s${item.parentTemplateId}`" class="title">
+                  <el-checkbox v-if="!edit" v-model="item.isCheck" :label="item.name" class="fontRest" @change="updateCheckItemHandle(item)">{{ item.name }}</el-checkbox>
+                  <span v-else class="fontName">{{ item.name }}</span>
+                </p>
+                <normal-area
+                  v-if="edit"
+                  :id="'tem'+item.parentTemplateId"
+                  :value.sync="item.content"
+                  :empty-text="'点击'"
+                  :input-button="'修改模板'"
+                  :height="300"
+                  :styles="{ padding: '0 0px 20px 0px', width: '690px', marginLeft: '24px' }"
+                />
+                <div v-else style="padding: 0 0px 20px 0px; margin-left: 24px; overflow-y: auto; width: 690px">
+                  <div v-html="item.content" />
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div v-if="edit" class="control">
+          <el-button size="small" @click="cancel()">取消</el-button>
+          <el-button type="primary" size="small" @click="saveHandle()">
+            保存
+          </el-button>
+        </div>
+      </div>
+    </section>
+    <div v-if="!edit">
+      <section class="main-section">
+        <div>
+          <headTitle title="动态" />
+        </div>
+        <actionDynamic :comments="commentlist" :change-record="changeRecordList" @addComment="createCommentHandle" />
+      </section>
+      <div v-if="!showEmpty" id="stepWrap" class="step">
+        <step :data="data.templates" :type-list="data.templates" @goto="scrollToHandle" />
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+const _ = require('lodash')
+import redTipword from '@/components/redTipTitle'
+import headTitle from '@/components/headTitle'
+import multipleSelect from './components/multipleSelect'
+import checkboxList from './components/checkboxList'
+import onlineCheckList from './components/onlineCheckList'
+import actionDynamic from '@/components/actionDynamic'
+import step from './components/step'
+// 富文本
+// import textArea from '@/components/input/textArea'
+import normalArea from '@/components/input/normalArea' // 富文本
+import 'tinymce/plugins/table'// 插入表格插件
+import store from '@/store'
+import {
+  getCheckListBytask,
+  getBizBindTemList,
+  updateChecklist,
+  createChecklist,
+  updateTemplateCheckStatus,
+  getCommentList,
+  createComment,
+  getRecordList
+} from '@/api/publishTask'
+export default {
+  components: {
+    redTipword,
+    multipleSelect,
+    checkboxList,
+    onlineCheckList,
+    normalArea,
+    headTitle,
+    actionDynamic,
+    step
+  },
+  props: {
+    taskId: {
+      type: Number,
+      required: true,
+      default: -1
+    },
+    taskName: {
+      type: String,
+      required: true,
+      default: ''
+    },
+    userNames: {
+      type: String,
+      required: true,
+      default: ''
+    },
+    userInformation: {
+      type: String,
+      required: true,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      description: '<p style="color:red;">123</p>',
+      edit: false, // 是否是编辑状态
+      showEmpty: true,
+      openEdit: true,
+      data: {},
+      temList: [],
+      commentlist: [], // 评价列表
+      changeRecordList: [], // 变更记录列表
+      checkListId: -1
+    }
+  },
+  mounted() {
+    // 获取模板列表
+    this.getBizBindTemList()
+    // 获取checklist详情
+    this.getList()
+    // 获取评论列表
+    this.getCommentList()
+    // 监听滚动条
+    const container = document.getElementsByClassName('main-wrapper')[0]
+    container.addEventListener('scroll', this.handleScroll) // 监听滚动事件,然后用handleScroll这个方法进行相应的处理
+  },
+  methods: {
+    // 监听滚动条
+    handleScroll() {
+      const containerWrap = document.getElementsByClassName('main-wrapper')[0]
+      const stepWrap = document.getElementById('stepWrap')
+      const fullHeight = containerWrap.scrollHeight
+      const top = containerWrap.scrollTop
+      if (fullHeight - top <= 900) {
+        stepWrap.style.bottom = '450px'
+        stepWrap.style.top = 'auto'
+      } else {
+        if (stepWrap.style.bottom === '450px') {
+          stepWrap.style.bottom = 'auto'
+          stepWrap.style.top = '150px'
+        }
+      }
+    },
+    // 获取checklist详情
+    async getList() {
+      if (this.taskId) {
+        const res = await getCheckListBytask({ taskId: this.taskId })
+        // res.data = null
+        if (res.data) {
+          // 如果绑定过
+          this.showEmpty = false
+          this.data = res.data
+          this.checkListId = res.data.id
+          // 获取变更记录
+          this.getRecordList()
+        } else {
+          this.showEmpty = true
+        }
+      }
+    },
+
+    // 获取业务线下绑定的可以选checklist列表
+    async getBizBindTemList() {
+      const { bizId = null } = store.state.global || {}
+      const res = await getBizBindTemList({ name: '', bizId })
+      this.temList = res.data
+    },
+
+    async getCommentList() {
+      const res = await getCommentList({ type: 5, joinId: this.taskId })
+      if (res.code === 200) {
+        this.commentlist = res.data
+      }
+    },
+
+    // 获取变更记录
+    async getRecordList() {
+      const res = await getRecordList({ checkListId: this.checkListId })
+      if (res.code === 200) {
+        this.changeRecordList = res.data
+      }
+    },
+    // 添加评论
+    async createCommentHandle(content, callback) {
+      const commentInfo = {
+        joinId: this.taskId,
+        content,
+        type: 5,
+        fatherId: 0,
+        name: this.userNames,
+        email: this.userInformation
+      }
+      const user = { name: this.userNames, ename: this.userInformation, id: '' }
+      const res = await createComment({ commentInfo, user })
+      if (res.code === 200) {
+        this.$message({ message: '评论成功', type: 'success', duration: 1000, offset: 150 })
+        this.getCommentList()
+        callback()
+      } else {
+        this.$message.warning(res.msg)
+      }
+    },
+
+    // 添加或者删除线上模板的模版名
+    changeOnlineSelectedHandle(id, subIdx, value, type) {
+      /**
+       * id: 模块id
+       * name: 线上模块中哪个模块下的模块名称
+       * value: 模块名
+       * type: 是添加还是删除
+      **/
+      // const tem = this.data.templates
+      this.data.templates.map(t => {
+        if (t.parentTemplateId === id) {
+          if (type === 'del') {
+            t.onlineModule.onlineOrder = t.onlineModule.onlineOrder.filter(g => g !== value)
+            t.onlineModule.tableContent.map((t, i) => {
+              if (i === subIdx) {
+                t.moduleNames = t.moduleNames.filter(g => g !== value)
+              }
+            })
+          } else if (!t.onlineModule.onlineOrder.includes(value)) {
+            t.onlineModule.onlineOrder.push(value)
+            t.onlineModule.tableContent.map((t, i) => {
+              if (i === subIdx) {
+                t.moduleNames.push(value)
+              }
+            })
+          } else {
+            this.$message({
+              message: '已经添加过该模块名称',
+              type: 'error'
+            })
+          }
+        }
+      })
+    },
+
+    changeOnlineModuleRow(type, mId, index) {
+      this.data.templates.map(t => {
+        if (t.parentTemplateId === mId) {
+          if (type === 'del') {
+            const delModuleNames = t.onlineModule.tableContent[index].moduleNames
+            t.onlineModule.onlineOrder = t.onlineModule.onlineOrder.filter(t => !delModuleNames.includes(t))
+            t.onlineModule.tableContent.splice(index, 1)
+          } else {
+            t.onlineModule.tableContent.splice(index + 1, 0, {
+              module: '',
+              moduleNames: []
+            })
+          }
+        }
+      })
+    },
+
+    // 保存
+    async saveHandle() {
+      if (this.data.tasks.length < 1) {
+        this.$message({
+          message: '请关联一个任务',
+          type: 'error'
+        })
+        return
+      }
+      let res = null
+      if (this.data.id) {
+        res = await updateChecklist(this.data)
+      } else {
+        res = await createChecklist(this.data)
+      }
+      if (res.code === 200) {
+        this.edit = false
+        this.openEdit = true
+        // 保存更新变更记录
+        this.getRecordList()
+        this.getList()
+        this.$message({
+          message: '保存成功',
+          type: 'success'
+        })
+      }
+    },
+
+    // 取消
+    cancel() {
+      this.edit = false
+      this.openEdit = true
+      this.data = this.copyData
+      if (!this.data || JSON.stringify(this.data) === '{}') {
+        this.showEmpty = true
+      }
+    },
+    // 点击添加
+    addAction() {
+      // 校验是否绑定过checklist模板
+      if (!this.RegHasCheckListTem()) {
+        return
+      }
+      // 复制一份数据,以便取消时复原
+      this.copyData = this.data
+      // 编辑按钮隐藏
+      this.openEdit = false
+      // 编辑状态打开
+      this.edit = true
+      // 是否显示空状态
+      this.showEmpty = false
+      this.data = {
+        selectedBizTemplateIds: [],
+        templates: [],
+        tasks: [{
+          id: this.taskId,
+          name: this.taskName
+        }]
+      }
+      // this.checkAllTem()
+    },
+
+    // 编辑
+    editHandle() {
+      // 校验是否绑定过checklist模板
+      if (!this.RegHasCheckListTem()) {
+        return
+      }
+      // 复制一份数据,以便取消时复原
+      this.copyData = this.data
+      // 编辑状态打开
+      this.edit = true
+      // 编辑按钮隐藏
+      this.openEdit = false
+      // this.checkAllTem()
+    },
+
+    // 添加和编辑checklist时 如果没有选择模版默认全选。
+    // checkAllTem() {
+    //   const { selectedBizTemplateIds } = this.data
+    //   if (!selectedBizTemplateIds || selectedBizTemplateIds.length < 1) {
+    //     this.temList.map(t => {
+    //       this.data.selectedBizTemplateIds.push(t.id)
+    //       const { content, isCheck, name, onlineModule, type, id: parentTemplateId } = t
+    //       this.data.templates.push({
+    //         content,
+    //         isCheck,
+    //         name,
+    //         onlineModule,
+    //         type,
+    //         parentTemplateId,
+    //         belongType: 2 // checklist的模板
+    //       })
+    //     })
+    //   }
+    // },
+
+    // 校验是否该业务线有绑定checklist模板
+    RegHasCheckListTem() {
+      if (!this.temList || this.temList.length < 1) {
+        this.$message({
+          message: '该业务线暂无绑定checklist模板,请先绑定checklist模板',
+          type: 'error'
+        })
+        return false
+      } else {
+        return true
+      }
+    },
+
+    // 修改checklist绑定模版列表
+    updateSelectedTemHandle(checkedIds) {
+      const selectedBizTemplateIds = []
+      const tems = []
+      const newcheckedIds = []
+      const { templates } = this.data
+      // 循环都有哪些tem被选择了
+      this.temList.forEach(t => {
+        if (checkedIds.includes(t.id)) {
+          newcheckedIds.push(t.id)
+        }
+      })
+      newcheckedIds.map(checkedId => {
+        // 先循环是否有存过模板数据
+        this.temList.map(g => {
+          if (g.id === checkedId) {
+            selectedBizTemplateIds.push(g.id)
+            const { content, isCheck, name, onlineModule, type, id: parentTemplateId } = g
+            tems.push({
+              content,
+              isCheck,
+              name,
+              onlineModule,
+              type,
+              parentTemplateId,
+              belongType: 2 // checklist的模板
+            })
+          }
+        })
+      })
+      tems.map((h, index) => templates.map(j => {
+        if (h.parentTemplateId === j.parentTemplateId) {
+          tems[index] = { ...j }
+        }
+      }))
+      this.data = { ...this.data, templates: tems, selectedBizTemplateIds }
+    },
+
+    // 锚点
+    scrollToHandle(targe) {
+      const anchorH = document.getElementById(targe).offsetTop
+      const container = document.getElementsByClassName('main-wrapper')[0]
+      container.scrollTop = anchorH - 30
+    },
+
+    // 解绑删除任务
+    changeTask(task, type) {
+      let hasTask = false
+      let tasks = []
+      this.data.tasks.map(g => {
+        if (g.id === task.id) {
+          hasTask = true
+        }
+      })
+      if (type === 'del') {
+        tasks = this.data.tasks.filter(t => t.id !== task.id)
+      } else if (!hasTask) {
+        tasks = [...this.data.tasks, task]
+      } else {
+        this.$message({
+          message: '已经添加过该任务',
+          type: 'error'
+        })
+        return
+      }
+      this.data = { ...this.data, tasks }
+    },
+
+    // 更新检查项到数据库
+    async updateCheckItemHandle(item) {
+      const { isCheck, id } = item
+      const res = await updateTemplateCheckStatus({ isCheck, id, checkListId: this.checkListId })
+      if (res.code === 200) {
+        this.getRecordList()
+        this.$message({
+          message: '检查项状态更新成功',
+          type: 'success'
+        })
+      }
+    },
+
+    // 修改线上问题模块
+    onChangeModuleName: _.debounce(function(val, subIdx, index) {
+      this.data.templates[index].onlineModule.tableContent[subIdx].module = val
+    })
+  }
+}
+</script>
+<style scoped lang="scss">
+@import '@/styles/detail-pages.scss';
+.editPublishTask {
+  min-height: 400px;
+  overflow-y: auto;
+  padding-bottom: 20px;
+  .step {
+    position: fixed;
+    top: 200px;
+    right:150px;
+  }
+  .pubconfig {
+    .control {
+      width: 100%;
+      text-align: right;
+      padding: 0px 20px 20px 0px;
+    }
+  }
+  .main-section {
+    @include main-section;
+  }
+  .wrap{
+    padding: 0 40px;
+  }
+  .moduleList {
+    padding-bottom: 40px;
+    .checkBox {
+      margin-top: 10px;
+    }
+    .item {
+      // padding-bottom: 30px;
+      .title {
+        font-weight: 400;
+        color: #444444;
+        font-size: 14px;
+        margin: 0px 0px 12px 0px;
+        .fontRest {
+          color: #444;
+          font-weight: 600;
+        }
+      }
+      width: 690px;
+      .fontName {
+        font-weight: 600;
+      }
+    }
+  }
+}
+.empty {
+  padding: 0px 30px 40px 30px;
+  color: #444;
+  font-size: 14px;
+  .createBtn {
+    color: #409EFF;
+    margin-left: 5px;
+    cursor: pointer;
+  }
+}
+.main-title {
+  @include main-title;
+}
+</style>

+ 30 - 2
src/views/projectManage/requirement/components/taskList.vue

@@ -119,12 +119,18 @@
       type="requirement"
       @update="get_allTask()"
     />
+    <checkListStopConfirm
+      :visible="checklistStopVisible"
+      @confirm="checklistConfirm"
+      @cancel="checklistCancel"
+    />
   </div>
 </template>
 <script>
 import { analysisBizId_id, EncryptId } from '@/utils/crypto-js.js'
 import { mapGetters } from 'vuex'
 import imgUrl from '@/assets/建立档案@2x.png'
+import checkListStopConfirm from '@/components/checkListStopConfirm'
 import TestReport from '@/views/reportManagement/components/TestingReport' // 提测
 import DailyReport from '@/views/reportManagement/components/DailyReport' // 日报
 import ReleaseReport from '@/views/reportManagement/components/ReleaseReport' // 准出
@@ -143,7 +149,8 @@ export default {
     ReleaseReport,
     scheduleList,
     taskDialog,
-    modifySchedule
+    modifySchedule,
+    checkListStopConfirm
   },
   data() {
     return {
@@ -168,7 +175,9 @@ export default {
       nowChangeTask: null, // 当前正在改变的任务对象
       taskId: '', // 将要修改状态的任务id
       visibleSchedule: false, // 排期弹框
-      selectTaskList: [] // 已选任务的id
+      selectTaskList: [], // 已选任务的id
+      checklistStopVisible: false, // checklist拦截弹窗是否显示
+      firstChecklistTaskId: -1
     }
   },
   computed: {
@@ -305,6 +314,11 @@ export default {
       const data = this.curcentList.map(item => { return item.id })
       const res = await reportdelivertestCheckStatus(data)
       if (res.code === 200) {
+        if (res.data) {
+          this.checklistStopVisible = true
+          this.firstChecklistTaskId = res.data
+          return
+        }
         this.dialogTestReport = true
         this.$nextTick(() => {
           this.$refs.TestReport.init(7, this.curcentList.map(item => { return item.id }))
@@ -335,6 +349,20 @@ export default {
     link_task(ele) { // 跳转到任务详情页
       const bizId_id = EncryptId(`${ele.bizId}_${ele.id}`)
       this.$router.push({ name: '任务详情', query: { bizId_id: bizId_id }})
+    },
+    checklistConfirm() {
+      this.checklistStopVisible = false
+      const { bizId = null } = this.$store.state.global || {}
+      const bizId_id = EncryptId(`${bizId}_${this.firstChecklistTaskId}`)
+      const newTab = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id, page: 6 }})
+      window.open(newTab.href, '_blank')
+    },
+    checklistCancel() {
+      this.checklistStopVisible = false
+      this.dialogTestReport = true
+      this.$nextTick(() => {
+        this.$refs.TestReport.init(7, this.curcentList.map(item => { return item.id }))
+      })
     }
   }
 }

+ 0 - 1
src/views/projectManage/taskList/components/scheduleList.vue

@@ -223,7 +223,6 @@ export default {
       }
     },
     async taskUpdatePreOnlineVersion() {
-      console.log(this.taskId, 'csdcds')
       const res = await taskUpdatePreOnlineVersion(this.taskId)
       if (res.code === 200) {
         this.listByTask(this.taskId)

+ 51 - 3
src/views/projectManage/taskList/taskViewDetail.vue

@@ -67,6 +67,7 @@
             <el-tab-pane label="缺陷" name="3" />
             <el-tab-pane label="报告" name="4" />
             <el-tab-pane label="统计" name="5" />
+            <el-tab-pane label="发布" name="6" />
           </el-tabs>
         </div>
         <div class="top-control">
@@ -320,6 +321,21 @@
         </section>
       </el-container>
       <!-- 统计 -->
+
+      <!-- 发布 -->
+      <el-container v-if="activeName === '6'" class="is-vertical">
+        <!-- <section class="main-section contain"> -->
+        <publishTask
+          v-if="loaded"
+          :task-id="form_query.id"
+          :task-name="form_query.name"
+          :user-names="userNames"
+          :user-information="userInformation"
+        />
+        <!-- </section> -->
+      </el-container>
+      <!-- 发布 -->
+
       <!-- 新建(bug) -->
       <createdBug v-if="bug_open" ref="createdBug" @getBugList="reloadList" />
       <create-children v-if="createChildren" :visible.sync="createChildren" :data="form_query" :new-add="true" @change="reloadList" />
@@ -374,6 +390,11 @@
         @childValInput="childVal"
         @click.stop
       />
+      <checkListStopConfirm
+        :visible="checklistStopVisible"
+        @confirm="checklistConfirm"
+        @cancel="checklistCancel"
+      />
     </el-container>
   </div>
 </template>
@@ -383,6 +404,7 @@ import Vue from 'vue'
 import VueClipboard from 'vue-clipboard2'
 Vue.use(VueClipboard)
 import { mapGetters } from 'vuex'
+// import store from '@/store'
 import { EncryptId, analysisBizId_id } from '@/utils/crypto-js.js'
 import {
   taskGet,
@@ -396,6 +418,7 @@ import {
   configShowRequirementVersionEnum,
   scheduleGetTaskScheduleHistory
 } from '@/api/taskIndex'
+import checkListStopConfirm from '@/components/checkListStopConfirm'
 import { listByTask, taskUpdates } from '@/api/projectViewDetails'
 import { projectListProject, scheduleGetHistoryScheduleById, taskListAvailableDpmTask, taskSetTaskRelated, taskDeleteRelationship } from '@/api/requirement.js'
 import searchPeople from '@/components/select/searchPeople'
@@ -417,6 +440,7 @@ import stage1 from '@/assets/detailPage/正常状态.png'
 import stage2 from '@/assets/detailPage/延期状态.png'
 import taskDialog from '@/views/projectManage/taskList/dialog/taskDialog' // 任务状态修改(已上线/已提测/已准出)
 import bugTableDialog from '@/views/projectManage/bugList/details/bugTableDialog' // 缺陷表格
+import publishTask from '@/views/projectManage/publishTask'
 import schedule from '@/views/projectManage/schedule' // 排期锁定弹窗
 import download from '@/views/projectManage/components/export.vue'
 import record from '@/views/projectManage/components/record.vue'
@@ -448,7 +472,9 @@ export default {
     record,
     timeLine,
     workflowAndStatus,
-    synchronizeDialog
+    synchronizeDialog,
+    publishTask,
+    checkListStopConfirm // checklist拦截弹窗
   },
   filters: {
     ellipsis(value, num) {
@@ -511,7 +537,10 @@ export default {
       comments: [], // 评论列表
       taskIds: '', // 将要修改状态的任务id
       synchronizeDialog: false, // 同步任务至望月弹框
-      dplOption: [] // 关联的望岳任务
+      dplOption: [], // 关联的望岳任务
+      checklistStopVisible: false, // checklist拦截弹窗是否显示
+      firstChecklistTaskId: -1,
+      loaded: false // 是否请求到当前任务的task信息
     }
   },
 
@@ -682,6 +711,9 @@ export default {
       const res = await taskGet(this.taskId)
       if (res.code === 200) {
         this.form_query = res.data
+        if (!this.loaded) {
+          this.loaded = true
+        }
         if (this.form_query.isDirectlyFromDpm === 0 || this.form_query.isDirectlyFromDpm === 1) {
           this.toilp = this.form_query.relatedDpmTaskInfo.taskId + this.form_query.relatedDpmTaskInfo.name
         }
@@ -786,11 +818,15 @@ export default {
         case 1: // 提测
           reportdelivertestCheckStatus([this.taskId]).then(res => {
             if (res.code === 200) {
+              if (res.data) {
+                this.checklistStopVisible = true
+                this.firstChecklistTaskId = res.data
+                return
+              }
               this.dialogTest = true
               this.$nextTick(() => { this.$refs.TestReport.init(7, [this.taskId]) })
             }
           })
-
           break
         case 2: // 日报
           dailyReportCheckStatus([this.taskId]).then(res => {
@@ -867,6 +903,18 @@ export default {
         this.taskGet()
         this.$message({ message: '已取消关联', type: 'success', offset: 150 })
       }
+    },
+    checklistConfirm() {
+      this.checklistStopVisible = false
+      const { bizId = null } = this.$store.state.global || {}
+      const bizId_id = EncryptId(`${bizId}_${this.firstChecklistTaskId}`)
+      const newTab = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id, page: 6 }})
+      window.open(newTab.href, '_blank')
+    },
+    checklistCancel() {
+      this.checklistStopVisible = false
+      this.dialogTest = true
+      this.$nextTick(() => { this.$refs.TestReport.init(7, [this.taskId]) })
     }
   }
 }

+ 0 - 1
src/views/quality/components/requireDrawer.vue

@@ -140,7 +140,6 @@ export default {
       return data
     },
     jumper(val) {
-      console.log(name)
       const bizId_id = EncryptId(`${val.bizId}_${val.id}`)
       const newTab = this.$router.resolve({ name: this.Statistics.typeStr + '详情', query: { bizId_id: bizId_id }})
       window.open(newTab.href, '_blank')

+ 0 - 1
src/views/quality/defectStatistics.vue

@@ -748,7 +748,6 @@ export default {
       this.getMemberDistributeData()
     },
     getRequiredNum(value) {
-      console.log(value, 'cdcsdcd')
       this.drawer = true
       value.typeStr = '缺陷'
       this.requireList = value

+ 44 - 2
src/views/reportManagement/testPresentation.vue

@@ -146,6 +146,11 @@
         <acceptTheReport v-if="acceptTheReport" :message="message" />
       </div>
     </el-dialog>
+    <checkListStopConfirm
+      :visible="checklistStopVisible"
+      @confirm="checklistConfirm"
+      @cancel="checklistCancel"
+    />
   </div>
 </template>
 
@@ -154,6 +159,7 @@ const _ = require('lodash')
 import { EncryptId } from '@/utils/crypto-js.js'
 import { mapGetters } from 'vuex'
 import '@/styles/PublicStyle/index.scss'
+import checkListStopConfirm from '@/components/checkListStopConfirm'
 import { dailyReportDelete } from '@/api/testPresentetion' // 日报
 import { projectTestReportList } from '@/api/ResultPage' // 准出
 import { launchTestList } from '@/api/InterfaceReport' // 提测
@@ -174,7 +180,8 @@ export default {
     ReleaseReport,
     testPresenyL,
     ResultPageyL,
-    acceptTheReport
+    acceptTheReport,
+    checkListStopConfirm
   },
   data() {
     return {
@@ -212,7 +219,10 @@ export default {
       indexPage: {
         pageSize: 10,
         curIndex: 1
-      }
+      },
+      goDataReport: -1,
+      checklistStopVisible: false, // checklist拦截弹窗是否显示
+      firstChecklistTaskId: -1
     }
   },
   computed: {
@@ -375,6 +385,12 @@ export default {
               const data = res.data
               reportdelivertestCheckStatus(data.taskIds).then(response => {
                 if (response.code === 200) {
+                  if (response.data) {
+                    this.checklistStopVisible = true
+                    this.firstChecklistTaskId = response.data
+                    this.goDataReport = data
+                    return
+                  }
                   this.dialogVisible1 = true
                   this.$nextTick(() => {
                     this.$refs.TestReport.init(4, data)
@@ -453,6 +469,12 @@ export default {
           const res = await reportdelivertestCheckStatus([vel])
           if (res.code === 200) {
             this.centerDialogVisible = false
+            if (res.data) {
+              this.checklistStopVisible = true
+              this.firstChecklistTaskId = res.data
+              this.goDataReport = vel
+              return
+            }
             this.dialogVisible1 = true
             this.$nextTick(() => {
               this.$refs.TestReport.init(7, [vel])
@@ -553,6 +575,26 @@ export default {
     handleCurrentChange1(curIndex) { // used 分页
       this.curIndex = curIndex
       this.gethistoryData()
+    },
+    checklistConfirm() {
+      this.checklistStopVisible = false
+      const { bizId = null } = this.$store.state.global || {}
+      const bizId_id = EncryptId(`${bizId}_${this.firstChecklistTaskId}`)
+      const newTab = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id, page: 6 }})
+      window.open(newTab.href, '_blank')
+    },
+    checklistCancel() {
+      this.checklistStopVisible = false
+      this.dialogVisible1 = true
+      if (this.goDataReport.taskIds) {
+        this.$nextTick(() => {
+          this.$refs.TestReport.init(4, this.goDataReport)
+        })
+      } else {
+        this.$nextTick(() => {
+          this.$refs.TestReport.init(7, [this.goDataReport])
+        })
+      }
     }
   }
 }

+ 0 - 1
src/views/useCase/components/requirementCase.vue

@@ -25,7 +25,6 @@ export default {
     ...mapGetters(['bizId']),
     src() {
       const bizId = EncryptId(`${this.bizId}`)
-      console.log(bizId, this.bizId)
       const host = getEnv() === 'test' ? 'http://10.96.83.94:9000/index.html#' : 'http://agiletc.intra.xiaojukeji.com/#'
       const src = `${host}${this.srcHost}${encodeURIComponent(bizId)}`
       return src

+ 0 - 1
src/views/workbench/team/index.vue

@@ -407,7 +407,6 @@ export default {
       }
     },
     handleBizId(e) { // 业务线变动
-      console.log(e)
       this.searchForm.bizId = e
       this.queryTeamInfoList()// 重新获取团队
       const res = this.searchEnum.businesslines.find(item => item.code === e)