wenbobowen 4 years ago
parent
commit
13c38a9600
44 changed files with 2591 additions and 797 deletions
  1. 36 0
      src/api/requirement.js
  2. 53 0
      src/api/taskIndex.js
  3. 1 0
      src/apiConfig/requestIP.js
  4. 142 0
      src/components/chartView/index.vue
  5. 5 5
      src/components/dialog/normalDialog.vue
  6. 83 0
      src/components/filterModal/index.vue
  7. 202 0
      src/components/input/editor.vue
  8. 92 3
      src/components/input/normalArea.vue
  9. 55 6
      src/components/input/textArea.vue
  10. 13 5
      src/components/mainTitle/index.vue
  11. 1 1
      src/components/newLayout/Aside.vue
  12. 98 31
      src/components/newLayout/Head.vue
  13. 10 66
      src/components/searchHeader/searchBox.vue
  14. 146 0
      src/components/searchHeader/searchForm.vue
  15. 32 0
      src/components/ui/plainBtn.vue
  16. 5 0
      src/icons/svg/admin.svg
  17. 3 0
      src/icons/svg/icon-qp.svg
  18. 3 0
      src/icons/svg/icon-sx.svg
  19. 8 0
      src/icons/svg/setting.svg
  20. 6 0
      src/styles/PublicStyle/index.scss
  21. 5 0
      src/utils/global.js
  22. 11 1
      src/utils/options.js
  23. 34 28
      src/views/projectManage/bugList/bugindex.vue
  24. 2 2
      src/views/projectManage/bugList/details/bugTableDialog.vue
  25. 30 23
      src/views/projectManage/bugList/details/index.vue
  26. 0 1
      src/views/projectManage/bugList/details/statusChange.vue
  27. 32 22
      src/views/projectManage/bugList/file/createdBug.vue
  28. 7 2
      src/views/projectManage/components/filterList.vue
  29. 6 3
      src/views/projectManage/onlineproblem/component/header/index.vue
  30. 3 3
      src/views/projectManage/onlineproblem/create/index.vue
  31. 14 12
      src/views/projectManage/projectList/components/modifySchedule.vue
  32. 73 71
      src/views/projectManage/projectList/components/taskList.vue
  33. 2 7
      src/views/projectManage/projectList/projectIndex.vue
  34. 491 181
      src/views/projectManage/requirement/list/index.vue
  35. 92 0
      src/views/projectManage/requirement/renderData/chartSearchForm.js
  36. 92 0
      src/views/projectManage/taskList/renderData/chartSearchForm.js
  37. 535 179
      src/views/projectManage/taskList/taskIndex.vue
  38. 69 67
      src/views/projectManage/version/components/taskList.vue
  39. 6 2
      src/views/reportManagement/ReleaseReport/newReleaeTemplate.vue
  40. 6 1
      src/views/reportManagement/Testing/newTestingTemplate.vue
  41. 6 1
      src/views/reportManagement/daily/dailyTemplate.vue
  42. 6 1
      src/views/reportManagement/daily/newReportTemplate.vue
  43. 2 2
      src/views/workbench/team/components/needsList.vue
  44. 73 71
      src/views/workbench/team/components/taskList.vue

+ 36 - 0
src/api/requirement.js

@@ -354,3 +354,39 @@ export function requirementUpdatePreOnlineVersion(id) {
     method: 'get'
   })
 }
+
+// 搜索员工信息
+export function getPerson(data) {
+  return request({
+    url: requestIp + `/member/queryMemberInfoByIDAPorName`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取chart视图数据
+export function getChartData(data) {
+  return request({
+    url: requestIp + `/requirement/queryRequirementStatisticInfoList`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取chart视图数据
+export function getChartListData(data) {
+  return request({
+    url: requestIp + `/requirement/queryRequirementStatisticDetail`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取chart视图数据
+export function updateStatus(data) {
+  return request({
+    url: requestIp + `/requirement/updateRequirementStatus`,
+    method: 'post',
+    data
+  })
+}

+ 53 - 0
src/api/taskIndex.js

@@ -309,3 +309,56 @@ export function getByTasks(data) {
     data
   })
 }
+
+// 获取过滤器
+export function getFilterList(data) {
+  return request({
+    url: TeamManagement + '/filter/getFilterList',
+    method: 'post',
+    data
+  })
+}
+
+// 创建过滤器
+export function createFilter(data) {
+  return request({
+    url: TeamManagement + `/filter/createFilter`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取单个筛选项
+export function filterGetFilter(id) {
+  return request({
+    url: TeamManagement + `/filter/getFilter?id=${id}`,
+    method: 'get'
+  })
+}
+
+// 获取chart视图数据
+export function getChartData(data) {
+  return request({
+    url: TeamManagement + `/task/listStatistic`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取chart视图数据
+export function getChartListData(data) {
+  return request({
+    url: TeamManagement + `/task/listStatisticDetail`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取chart视图数据
+export function updateStatus(data) {
+  return request({
+    url: TeamManagement + `/task/updateTaskStatusStatistic`,
+    method: 'post',
+    data
+  })
+}

+ 1 - 0
src/apiConfig/requestIP.js

@@ -1,4 +1,5 @@
 export let host = 'http://zhihui-test.intra.xiaojukeji.com'
+// export let host = 'http://zhihui-pre.intra.xiaojukeji.com'
 export let requestIp = host + '/zuul'
 export let loginUrl = host + '/sso/login?jumpto=' + 'http://zhihui-test.intra.xiaojukeji.com' + location.pathname
 export let logoutUrl = host + '/sso/logout?jumpto=' + 'http://zhihui-test.intra.xiaojukeji.com' + location.pathname

+ 142 - 0
src/components/chartView/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="op-chart">
+    <div class="chartSearchbar inlineBetween">
+      <div class="inlineBetween">
+        <div class="subtitle" style="width: 200px">
+          {{ data.title }}
+        </div>
+        <div class="tip">
+          <span v-for="item in data.option" :key="item.key" class="item" @click="$emit('changeList', item.code)">
+            <span class="title">{{ item.key }}:</span>
+            <span class="num">{{ item.value }}</span>
+          </span>
+        </div>
+      </div>
+      <div>
+        <slot name="searchBox" />
+      </div>
+    </div>
+    <div class="chartSearchbar inlineBetween mt15">
+      <div style="width: 200px">
+        <span class="label">分布类型:</span>
+        <el-select
+          v-model="chartSearchData.viewType"
+          size="small"
+          filterable
+          style="width: 115px"
+          @change="$emit('search')"
+        >
+          <el-option v-for="(t, index) in typeOptionList" :key="index" :label="t.label" :value="t.value" />
+        </el-select>
+      </div>
+    </div>
+    <div class="chartViewHeight">
+      <normal-echart v-if="echartsOption3" :chart-id="'chartThird'" :option="echartsOption3" @onClick="changeList" />
+    </div>
+  </div>
+</template>
+<script>
+import normalEchart from '@/components/chart/normalEchart'
+import { getBarOption } from '@/utils/options'
+export default {
+  components: {
+    normalEchart
+  },
+  props: {
+    data: {
+      type: Object,
+      default: () => {},
+      required: true
+    },
+    chartSearchData: {
+      type: Object,
+      default: null,
+      required: true
+    },
+    typeOptionList: {
+      type: Array,
+      default: () => [],
+      required: false
+    }
+  },
+  data() {
+    return {
+      echartsOption3: null
+    }
+  },
+  watch: {
+    data: {
+      handler(newV) {
+        if (newV) {
+          this.echartsOption3 = getBarOption(newV.xaxis, newV.data)
+        }
+      },
+      immediate: true
+    },
+    chartSearchData: {
+      handler(newV) {
+        this.year = newV.year
+        this.type = newV.type
+      },
+      immediate: true
+    }
+  },
+  mounted() {
+    // const d = new Date()
+    const { data, xaxis } = this.data
+    this.echartsOption3 = getBarOption(xaxis, data)
+  },
+  methods: {
+    changeList(data) {
+      this.$emit('changeList', data.data.code)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.op-chart {
+  height: 370px;
+  .chartViewHeight {
+    height: 324px;
+  }
+  .mt15 {
+    margin-top: 15px;
+  }
+  .subtitle {
+    color: #333;
+    font-size: 16px;
+    background: #fff;
+    font-weight: 700;
+  }
+  .chartSearchbar {
+    padding: 0 5%;
+    .label {
+      font-size: 14px;
+      color: #444;
+    }
+    .tip {
+      width: 240px;
+      margin: 0px 25px;
+      .item {
+        display: inline-block;
+        margin-right: 15px;
+        cursor: pointer;
+        .title {
+          font-size: 14px;
+          color: #444;
+        }
+        .num {
+          color: #409EFF;
+          font-size: 18px;
+          font-weight: 600;
+        }
+      }
+    }
+  }
+  .inlineBetween {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+</style>

+ 5 - 5
src/components/dialog/normalDialog.vue

@@ -92,22 +92,22 @@ export default {
 }
 </script>
 <style scoped lang="scss">
->>>.el-dialog__header {
+/deep/.el-dialog__header {
   padding: 20px !important;
   // border-bottom:1px solid rgba(238,238,238,1);
 }
->>>.el-dialog__footer {
+/deep/.el-dialog__footer {
   // border-top:1px solid rgba(238,238,238,1);
   padding: 20px;
 }
->>>.el-dialog__body {
+/deep/.el-dialog__body {
   padding: 20px;
 }
->>>.el-dialog__title{
+/deep/.el-dialog__title{
   padding-left: 10px;
   position: relative;
 }
->>>.el-dialog__title::before {
+/deep/.el-dialog__title::before {
   content:" ";
   display: inline-block;
   position: absolute;

+ 83 - 0
src/components/filterModal/index.vue

@@ -0,0 +1,83 @@
+<template>
+  <div class="coms-filterModal">
+    <el-dialog
+      :visible.sync="visible"
+      :width="width"
+      :modal="false"
+      @close="$emit('cancel', false)"
+    >
+      <div slot="title" class="dialog-title">
+        {{ title }}
+      </div>
+      <slot />
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="reset()">重置</el-button>
+        <el-button type="primary" @click="confirm()">筛选</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    title: {
+      type: String,
+      default: '',
+      required: false
+    },
+    width: {
+      type: String,
+      default: '450px',
+      required: false
+    },
+    showDialog: {
+      type: Boolean,
+      default: false,
+      required: true
+    }
+  },
+  data() {
+    return {
+      visible: this.showDialog
+    }
+  },
+  watch: {
+    showDialog() {
+      this.visible = this.showDialog
+    }
+  },
+  methods: {
+    confirm() {
+      this.$emit('confirm')
+    },
+    reset() {
+      this.$emit('reset', false)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.coms-filterModal {
+  /deep/.el-dialog {
+    margin: 0px!important;
+    margin-left: calc(100% - 470px)!important;
+    top: 60px;
+  }
+  .dialog-title {
+    font-size: 16px;
+    color: #333;
+    text-align: center;
+  }
+  /deep/.el-dialog__footer {
+    padding: 10px 20px 10px;
+    border-top: 1px solid #e2e2e2;
+  }
+  /deep/.el-dialog__body {
+    padding: 20px
+  }
+  /deep/.el-dialog__header {
+    border-bottom: 1px solid #e2e2e2;
+    padding: 15px;
+  }
+}
+</style>

+ 202 - 0
src/components/input/editor.vue

@@ -0,0 +1,202 @@
+<template>
+  <div>
+    <article :id="id" :style="styles">
+      <a id="edit-btn" href="javascript:;" @click="() => styleHandle('bold')">加粗</a>
+      <a id="edit-btn" href="javascript:;" @click="() => styleHandle('italic')">italic</a>
+      <a id="edit-btn" href="javascript:;" @click="() => styleHandle('enableInlineTableEditing')">表格</a>
+      <a id="edit-btn" href="javascript:;" @click="() => styleHandle('backColor', '#666')">背景颜色</a>
+      <a id="edit-btn" href="javascript:;" @click="() => insertTable()">插入表格</a>
+      <div :id="'editor_'+id" contenteditable="true" style="display:inline-block;border:1px solid #eee; width:200px; height:200px" class="editor" v-html="value">
+        <p>12321</p>
+      </div>
+      <!-- <div :id="'tinymce_'+id" class="editor" contenteditable="true" style="display:inline-block;border:1px solid #eee; width:300px; height:200px">
+        <p>12321</p>
+      </div> -->
+      <div id="menu">
+        <div class="menu" @click.stop="getCursorPosition">功能1</div>
+        <div class="menu">功能2</div>
+        <div class="menu">功能3</div>
+        <div class="menu">功能4</div>
+        <div class="menu">功能5</div>
+      </div>
+    </article>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    id: {
+      type: String,
+      default: '',
+      required: true
+    },
+    value: {
+      type: String,
+      default: '',
+      required: false
+    },
+    height: {
+      type: Number,
+      default: 200,
+      required: false
+    },
+    styles: {
+      type: Object,
+      default: () => {
+        return { }
+      },
+      required: false
+    }
+  },
+  data() {
+    return {
+      inputValue: '',
+      edit: false,
+      init: {
+        auto_focus: true,
+        language_url: '/tinymce/langs/zh_CN.js',
+        language: 'zh_CN',
+        skin_url: '/tinymce/skins/ui/oxide', // 编辑器需要一个skin才能正常工作,所以要设置一个skin_url指向之前复制出来的skin文件
+        height: this.height,
+        browser_spellcheck: true, // 拼写检查
+        branding: false, // 去水印
+        elementpath: false, // 禁用编辑器底部的状态栏
+        statusbar: false, // 隐藏编辑器底部的状态栏
+        paste_data_images: true, // 允许粘贴图像
+        menubar: false, // 隐藏最上方menu
+        fontsize_formats: '14px 16px 18px 20px 24px 26px 28px 30px 32px 36px', // 字体大小
+        file_picker_types: 'image',
+        images_upload_credentials: true,
+        plugins: 'lists table textcolor wordcount contextmenu', // 引入插件
+        toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect',
+        table_toolbar: 'tableprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells'
+      }
+    }
+  },
+  watch: {
+    value: {
+      handler(newV, oldV) {
+        this.inputValue = newV
+      },
+      immediate: true
+    }
+  },
+  mounted() {
+    const editor = document.getElementById(`editor_${this.id}`)
+    editor.oncontextmenu = function(e) {
+      console.log(11111)
+      // 取消默认的浏览器自带右键 很重要!!
+      e.preventDefault()
+
+      // 获取我们自定义的右键菜单
+      var menu = document.querySelector('#menu')
+      console.log(e)
+      // 根据事件对象中鼠标点击的位置,进行定位
+      menu.style.left = e.clientX + 'px'
+      menu.style.top = e.clientY + 'px'
+
+      // 改变自定义菜单的宽,让它显示出来
+      menu.style.width = '125px'
+    }
+    editor.onclick = function(e) {
+      console.log(2222, e)
+      console.log('第几列', e.target.cellIndex + 1, '第几行', e.target.parentNode.rowIndex + 1)
+      const ForeColor = document.queryCommandValue('ForeColor') // 字体颜色
+      const FontSize = document.queryCommandValue('FontSize') // 字体大小
+      const bold = document.queryCommandValue('bold') // 是否加粗
+      const italic = document.queryCommandValue('italic')
+      const BackgroundColor = document.queryCommandValue('BackColor')
+      console.log(ForeColor, FontSize, bold, italic, BackgroundColor, 111)
+      console.log('这是table', e.path[3])
+      const tableBox = e.path[3]
+      console.log(tableBox)
+      // 必须保存一下不然下面会变
+      // const idx = e.target.cellIndex
+      //  在一行添加一行
+      // tableBox.insertRow(e.target.parentNode.rowIndex)
+      // 插入一列
+      console.log(tableBox.rows)
+      for (let i = 0; i < tableBox.rows.length; i++) {
+        console.log(i, e.target.cellIndex)
+        // 在之后插入一列
+        // tableBox.rows[i].insertCell(e.target.cellIndex+1)
+        // 在之前一列
+        // 在之前一列插入
+        // tableBox.rows[i].insertCell(idx)
+        console.log(tableBox.rows[i])
+      }
+      // tableBox.rows[e.target.parentNode.rowIndex].insertCell()
+      // 用户触发click事件就可以关闭了,因为绑定在window上,按事件冒泡处理,不会影响菜单的功能
+      document.querySelector('#menu').style.width = 0
+    }
+  },
+  methods: {
+    changeText(e) { // 富文本内容改变
+      this.inputValue = e
+      this.$emit('update:value', this.inputValue)
+      this.$emit('change', this.inputValue)
+    },
+    styleHandle(aCommandName, val) {
+      // const editor = document.getElementById('cc')
+      document.execCommand(aCommandName, false, val)
+    },
+    insertTable() {
+      const HTML = `<table border='1' border-collapse: collapse; style='border-color: #666;width:90%'>
+      <tr>
+        <td><span>123</span></td>
+        <td>1</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td><span>1233</span></td>
+        <td>4</td>
+        <td>5</td>
+      </tr>
+      <tr>
+        <td><span>1235</span></td>
+        <td>6</td>
+        <td>7</td>
+      </tr>
+      </table>`
+
+      document.execCommand('insertHTML', false, HTML)
+    },
+    getCursorPosition(event) {
+      const editEl = event.target
+      // return console.log(editEl);
+      console.log(event)
+      if (editEl.selectionStart || editEl.selectionStart === 0) {
+        console.log(3333)
+        // 非IE浏览器
+        this.cursorPosition = editEl.selectionStart
+      } else {
+        console.log(4444)
+        // IE
+        const range = document.selection.createRange()
+        range.moveStart('character', -editEl.value.length)
+        this.cursorPosition = range.text.length
+      }
+      console.log(this.cursorPosition)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.editor {
+  border: 1px solid #666;
+}
+#menu{
+  width: 0; /*设置为0 隐藏自定义菜单*/
+  height: 125px;
+  overflow: hidden; /*隐藏溢出的元素*/
+  box-shadow: 0 1px 1px #888,1px 0 1px #ccc;
+  position: absolute; /*自定义菜单相对与body元素进行定位*/
+}
+.menu{
+  width: 130px;
+  height: 25px;
+  line-height: 25px;
+  padding: 0 10px;
+  cursor: pointer;
+}
+</style>

+ 92 - 3
src/components/input/normalArea.vue

@@ -1,6 +1,19 @@
 <template>
   <div>
-    <article :id="id" :style="styles">
+    <article :id="id" :style="fullScreen ? { ...fullPositionStyle, ...styles } : styles" class="article" :class="getClass">
+      <!-- <textEditor :id="id" :value="inputValue" /> -->
+      <span v-show="fullScreen" class="changeSizeBtn" @click="changeSize">
+        <svg-icon
+          icon-class="icon-sx"
+          class="icon"
+        />
+      </span>
+      <span v-show="!fullScreen" class="changeSizeBtn" @click="changeSize">
+        <svg-icon
+          icon-class="icon-qp"
+          class="icon"
+        />
+      </span>
       <editor :id="'tinymce_'+id" ref="editor" v-model="inputValue" :init="init" @input="changeText" />
     </article>
   </div>
@@ -10,9 +23,11 @@ import tinymce from 'tinymce/tinymce'
 import Editor from '@tinymce/tinymce-vue'
 import 'tinymce/themes/silver/theme'
 import 'tinymce/icons/default/icons'
+// import textEditor from './editor'
 export default {
   components: {
     Editor
+    // textEditor
   },
   props: {
     id: {
@@ -30,16 +45,29 @@ export default {
       default: 200,
       required: false
     },
+    fullPositionStyle: {
+      type: Object,
+      default: () => {
+        return { }
+      },
+      required: false
+    },
     styles: {
       type: Object,
       default: () => {
         return { }
       },
       required: false
+    },
+    bottomMargin: {
+      type: Boolean,
+      default: false,
+      required: false
     }
   },
   data() {
     return {
+      fullScreen: false,
       inputValue: '',
       edit: false,
       init: {
@@ -57,12 +85,24 @@ export default {
         fontsize_formats: '14px 16px 18px 20px 24px 26px 28px 30px 32px 36px', // 字体大小
         file_picker_types: 'image',
         images_upload_credentials: true,
-        plugins: 'lists table textcolor wordcount contextmenu', // 引入插件
-        toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect',
+        plugins: 'fullscreen lists table textcolor wordcount contextmenu', // 引入插件
+        toolbar: 'fullscreen bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect',
         table_toolbar: 'tableprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells'
       }
     }
   },
+  computed: {
+    getClass() {
+      let className = ''
+      if (this.fullScreen) {
+        className += 'fullScreen'
+      }
+      if (this.bottomMargin) {
+        className += ' bottomMargin'
+      }
+      return className
+    }
+  },
   watch: {
     value: {
       handler(newV, oldV) {
@@ -79,7 +119,56 @@ export default {
       this.inputValue = e
       this.$emit('update:value', this.inputValue)
       this.$emit('change', this.inputValue)
+    },
+    changeSize() {
+      this.fullScreen = !this.fullScreen
     }
   }
 }
 </script>
+<style scoped lang="scss">
+.article {
+  position: relative;
+  .changeSizeBtn {
+    position: absolute;
+    top: 3px;
+    right: 4px;
+    z-index: 1000;
+    height: 34px;
+    width: 34px;
+    text-align: center;
+    line-height: 34px;
+    border-radius: 3px;
+    .icon {
+      color: #409eff;
+      font-weight: 700;
+      font-size: 18px;
+    }
+    &:hover {
+      background: #c8cbcf;
+      border: 0;
+      box-shadow: none;
+    }
+  }
+}
+.fullScreen {
+  position: fixed;
+  top: 0px;
+  bottom: 0;
+  left: 225px;
+  right: 0;
+  z-index: 1000;
+  height: 100vh!important;
+  /deep/.tox-tinymce {
+    height: 100vh!important;
+  }
+  &.bottomMargin {
+    /deep/.tox-tinymce {
+      height: calc(100vh - 40px)!important;
+    }
+  }
+}
+.editor {
+  border: 1px solid #666;
+}
+</style>

+ 55 - 6
src/components/input/textArea.vue

@@ -11,7 +11,19 @@
         {{ emptyText }}
         <el-button type="text" @click="ImmediateAddition">{{ inputButton }}</el-button>
       </div>
-      <div v-show="edit">
+      <div v-show="edit" class="editArticle" :class="fullScreen ? 'fullScreen' : ''">
+        <span v-show="fullScreen" class="changeSizeBtn" @click="changeSize">
+          <svg-icon
+            icon-class="icon-sx"
+            class="icon"
+          />
+        </span>
+        <span v-show="!fullScreen" class="changeSizeBtn" @click="changeSize">
+          <svg-icon
+            icon-class="icon-qp"
+            class="icon"
+          />
+        </span>
         <el-tooltip effect="dark" content="单击‘编辑’" placement="bottom">
           <editor v-model="inputValue" :class="'tinymce_'+id" :init="init" @input="changeText" />
         </el-tooltip>
@@ -75,6 +87,7 @@ export default {
   },
   data() {
     return {
+      fullScreen: false,
       loading: false,
       inputValue: '',
       edit: false,
@@ -94,8 +107,8 @@ export default {
         file_picker_types: 'image',
         images_upload_credentials: true,
         plugins: 'lists table textcolor wordcount contextmenu', // 引入插件
-        toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect',
-        table_toolbar: 'tableprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells'
+        toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect | fullscreen',
+        table_toolbar: 'tableprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells | fullscreen'
       }
     }
   },
@@ -152,14 +165,50 @@ export default {
         const reg = new RegExp(/<\/?p[^>]*>/gi)
         return val.replace(reg, '')
       }
+    },
+    changeSize() {
+      this.fullScreen = !this.fullScreen
     }
   }
 }
 </script>
 <style scoped lang="scss">
-// article {
-//   padding: 0 30px 20px 30px;
-// }
+.editArticle {
+  position: relative;
+  .changeSizeBtn {
+    position: absolute;
+    top: 3px;
+    right: 4px;
+    z-index: 1000;
+    height: 34px;
+    width: 34px;
+    text-align: center;
+    line-height: 34px;
+    border-radius: 3px;
+    .icon {
+      color: #409eff;
+      font-weight: 700;
+      font-size: 18px;
+    }
+    &:hover {
+      background: #c8cbcf;
+      border: 0;
+      box-shadow: none;
+    }
+  }
+}
+.fullScreen {
+  position: fixed;
+  top: 0px;
+  bottom: 0;
+  left: 225px;
+  right: 0;
+  z-index: 1000;
+  height: 100vh!important;
+  /deep/.tox-tinymce {
+    height: 100vh!important;
+  }
+}
 .text-edit {
   color: #666666;
   font-size: 14px;

+ 13 - 5
src/views/projectManage/onlineproblem/component/mainTitle.vue → src/components/mainTitle/index.vue

@@ -9,12 +9,12 @@
               <svg-icon
                 icon-class="list"
                 class="icon"
-                :style="nowTab === 'list' ? { color: '#fff' } : { color: '#606266' }"
+                :style="nowTab === 'list' ? { color: '#409EFF' } : { color: '#606266' }"
               />
               列表视图
             </el-radio-button>
             <el-radio-button label="charts" class="chart">
-              <svg-icon icon-class="chart" class="icon" :style="nowTab === 'charts' ? { color: '#fff' } : { color: '#606266' }" />
+              <svg-icon icon-class="chart" class="icon" :style="nowTab === 'charts' ? { color: '#409EFF' } : { color: '#606266' }" />
               统计视图
             </el-radio-button>
           </el-radio-group>
@@ -60,23 +60,31 @@ export default {
   }
 }
 </script>
-<style lang="scss">
+<style scoped lang="scss">
 .wb-mainTitle {
   .titleBox {
     display: flex;
     .radio {
       margin-left: 18px;
-      .el-radio-button__inner {
+      ::v-deep.el-radio-button__inner {
         &:hover {
           color: #606266;
         }
       }
       .is-active {
-        .el-radio-button__inner {
+        ::v-deep.el-radio-button__inner {
           &:hover {
             color: #fff;
           }
         }
+        /deep/.el-radio-button__inner:hover {
+          background: #fff;
+          color: #409EFF;
+        }
+        /deep/.el-radio-button__orig-radio:checked+.el-radio-button__inner {
+          background: #fff;
+          color: #409EFF;
+        }
       }
     }
   }

+ 1 - 1
src/components/newLayout/Aside.vue

@@ -216,7 +216,7 @@ section {
     align-items: center;
     font-size: 14px;
     color: #444444;
-    height: calc(100vh - 110px);
+    height: calc(100vh - 170px);
     overflow-y: auto;
     li {
       width: 100%;

+ 98 - 31
src/components/newLayout/Head.vue

@@ -36,8 +36,50 @@
     <div v-if="userInfo" class="user-info">
       <a-popover placement="rightBottom" overlay-class-name="head-popover">
         <template #content>
-          <div :class="memberCheck ? 'user-admin-one' : 'user-admin'">
-            <div class="user-name">{{ userInfo.name }}</div>
+          <div class="user-admin-one">
+            <div class="title line">
+              <svg-icon icon-class="setting" class="icon" />
+              <span class="label">设置</span>
+            </div>
+            <div class="item">
+              <div v-if="navTagType === 1" class="label line" @click="setNavTagType(2)">
+                顶部导航
+                <el-tooltip effect="dark" content="当前为左侧导航,点击切换为顶部导航。" placement="top-start">
+                  <i class="el-icon-info" />
+                </el-tooltip>
+              </div>
+              <div v-if="navTagType === 2" class="label line" @click="setNavTagType(1)">
+                侧边导航
+                <el-tooltip effect="dark" content="当前为顶部导航,点击切换为侧边导航。" placement="top-start">
+                  <i class="el-icon-info" />
+                </el-tooltip>
+              </div>
+              <div v-if="openPageHandle === 'self'" class="label line" @click="setOpenPageHandle('blank')">
+                详情页当前标签页打开
+                <el-tooltip effect="dark" content="当前详情页在新标签页打开,点击切换详情页在当前标签页打开。" placement="top-start">
+                  <i class="el-icon-info" />
+                </el-tooltip>
+              </div>
+              <div v-if="openPageHandle === 'blank'" class="label line" @click="setOpenPageHandle('self')">
+                详情页新标签页打开
+                <el-tooltip effect="dark" content="当前详情页在当前标签页打开,点击切换详情页在新标签页打开。" placement="top-start">
+                  <i class="el-icon-info" />
+                </el-tooltip>
+              </div>
+            </div>
+            <div class="title line" :class="memberCheck && 'clickText'" @click="administratorsJump()">
+              <svg-icon icon-class="admin" class="icon" />
+              <span class="label">管理员</span>
+            </div>
+            <div class="item">
+              <div class="label line">
+                {{ userInfo.name }} {{ userInfo.idap }}
+              </div>
+              <div class="label line">
+                <el-button type="primary" plain size="small" @click="layout()">退出登录</el-button>
+              </div>
+            </div>
+            <!-- <div class="user-name">{{ userInfo.name }}</div>
             <div class="line" />
             <div class="user-logout">
               <el-button v-if="navTagType === 1" type="primary" plain size="small" @click="setNavTagType(2)">顶部导航</el-button>
@@ -50,7 +92,7 @@
             <div v-if="memberCheck" class="line" />
             <div class="user-logout">
               <el-button type="primary" plain size="small" @click="layout()">退出登录</el-button>
-            </div>
+            </div> -->
           </div>
         </template>
         <img :src="userInfo.phoneUrl">
@@ -72,7 +114,8 @@ export default {
       headList: routes.filter(item => item.name !== '业务线'),
       userInfo: null,
       memberCheck: false,
-      target: true
+      target: true,
+      openPageHandle: localStorage.getItem('openPageHandle') || 'blank'
     }
   },
   computed: {
@@ -124,10 +167,15 @@ export default {
       this.$store.dispatch('global/setNavTagType', type)
       localStorage.setItem('navTagType', type)
     },
+    setOpenPageHandle(type) {
+      this.openPageHandle = type
+      localStorage.setItem('openPageHandle', type)
+    },
     // 获取登录人员信息
     async getLoginUser() {
       const res = await memberGetLoginInMemberInfoByLdap()
       if (res && res.data) this.userInfo = res.data || null
+      console.log(res.data)
     },
     // 查看是否为管理员
     async verifyIsAdmin() {
@@ -142,7 +190,9 @@ export default {
       this.$router.push({ path: '/' })
     },
     administratorsJump() {
-      this.$router.push({ name: '管理员' })
+      if (this.memberCheck) {
+        this.$router.push({ name: '管理员' })
+      }
     },
     // websocket数据接收
     websocketonmessage(e) {
@@ -245,35 +295,52 @@ export default {
     height: 30px;
   }
 }
-.user-admin {
-  height: 143px;
-  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-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;
+  // height: 190px;
+  .title {
+    cursor: no-drop;
+    .icon {
+      margin-right: 5px;
+      font-size: 12px;
+      color: #93C8FF ;
+    }
+    .label {
+      color: #9A9A9A;
+      font-size: 14px;
+    }
+  }
+  .clickText {
+    cursor: pointer;
+    .label {
+      color: #444;
+    }
+    .icon {
+      color: #409EFF;
+    }
+  }
   .line {
-    width: 100%;
-    height: 1px;
-    background-color: rgba(112, 112, 112, 0.2);
+    margin-bottom: 10px;
+  }
+  .item {
+    margin-left: 18px;
+    cursor: pointer;
+    .label {
+      color: #444;
+      font-size: 12px;
+    }
   }
+  // 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 {

+ 10 - 66
src/components/searchHeader/searchBox.vue

@@ -1,69 +1,26 @@
 <template>
   <div class="searchBox">
     <div v-for="(item, index) in list" :key="index" class="row">
-      <div v-for="l in item" :key="l.name" class="Layout" style="display: inline-flex;padding-left: 15px; width:270px;">
-        <div class="name">{{ l.name }}</div>
-        <el-select
-          v-if="l.type === 'select'"
-          v-model="l.value"
-          size="small"
-          :multiple="l.multiple"
-          clearable
-          filterable
-          :placeholder="l.placeholder"
-          @change="$emit('change')"
-        >
-          <el-option v-for="o in l.option" :key="o.value" :label="o.label" :value="o.value" />
-        </el-select>
-        <el-select
-          v-else-if="l.type === 'remoteSelect'"
-          v-model="l.value"
-          filterable
-          remote
-          clearable
-          :placeholder="l.placeholder"
-          :remote-method="(q) => $emit('getOption', l.key, q, l.utilName)"
-          :loading="loading"
-          size="small"
-          @change="$emit('change')"
-        >
-          <!-- <slot v-if="hasSlot" name="option" /> -->
-          <div v-if="l.hasSlot">
-            <el-option v-for="o in l.option" :key="o.value" :label="o.label" :value="o.value">
-              <div class="item-style">
-                <div class="item-detail">{{ o.deptName }}</div>
-                <div style="min-width:80px">{{ o.name }}</div>
-                <div class="item-detail">{{ o.idap }}</div>
-              </div>
-            </el-option>
-          </div>
-          <el-option v-for="o in l.option" v-else :key="o.value" :label="o.label" :value="o.value" />
-        </el-select>
-        <el-input
-          v-else
-          v-model="l.value"
-          style="width: 72% !important"
-          size="small"
-          clearable
-          :placeholder="l.placeholder"
-          @change="$emit('change')"
-        />
-      </div>
+      <searchForm
+        :data="item"
+        :loading="loading"
+        @change="$emit('change')"
+        @getOption="(key, q, utilName) => $emit('getOption', key, q, utilName)"
+      />
     </div>
   </div>
 </template>
 <script>
+import searchForm from './searchForm'
 export default {
+  components: {
+    searchForm
+  },
   props: {
     list: {
       type: Array,
       required: false,
       default: () => []
-    },
-    hasSlot: {
-      type: Boolean,
-      default: false,
-      required: false
     }
   },
   data() {
@@ -82,18 +39,5 @@ export default {
       margin-top: 0;
     }
   }
-  .name {
-    width: 80px;
-  }
-}
-.item-style {
-  display: flex;
-  justify-content: flex-start;
-  .item-detail {
-    min-width:100px;
-    color: #8492a6;
-    font-size: 13px;
-    overflow:hidden
-  }
 }
 </style>

+ 146 - 0
src/components/searchHeader/searchForm.vue

@@ -0,0 +1,146 @@
+<template>
+  <div class="searchForm">
+    <div v-for="l in data" :key="l.key" class="Layout" style="display: inline-flex;padding-left: 15px; width:270px;" :style="styles">
+      <div class="name">{{ l.name }}</div>
+      <el-select
+        v-if="l.type === 'select'"
+        v-model="l.value"
+        size="small"
+        :multiple="l.multiple"
+        clearable
+        filterable
+        :placeholder="l.placeholder"
+        class="chooseItem"
+        @change="(e) => $emit('change', l.key, e)"
+      >
+        <el-option v-for="o in l.option" :key="o.value" :label="o.label" :value="o.value" />
+      </el-select>
+      <el-select
+        v-else-if="l.type === 'remoteSelect'"
+        v-model="l.value"
+        filterable
+        remote
+        clearable
+        :placeholder="l.placeholder"
+        :remote-method="(q) => $emit('getOption', l.key, q, l.utilName)"
+        :loading="loading"
+        size="small"
+        class="chooseItem"
+        @change="(e) => $emit('change', l.key, e)"
+      >
+        <!-- <slot v-if="hasSlot" name="option" /> -->
+        <div v-if="l.hasSlot">
+          <el-option v-for="o in l.option" :key="o.idap" :label="o.name" :value="o.idap">
+            <div class="item-style">
+              <div class="item-detail">{{ o.deptName }}</div>
+              <div style="min-width:80px">{{ o.name }}</div>
+              <div class="item-detail">{{ o.idap }}</div>
+            </div>
+          </el-option>
+        </div>
+        <el-option v-for="o in l.option" v-else :key="o.value" :label="o.label" :value="o.value" />
+      </el-select>
+      <el-date-picker
+        v-else-if="l.type === 'dateStartAndEnd'"
+        v-model="l.value"
+        type="daterange"
+        align="right"
+        unlink-panels
+        range-separator="至"
+        start-placeholder="开始日期"
+        end-placeholder="结束日期"
+        size="small"
+        class="chooseItem"
+        value-format="yyyy-MM-dd HH:mm:ss"
+        :default-time="['00:00:00','23:59:59']"
+        :picker-options="pickerOptions"
+        @change="(e) => $emit('change', l.key, e)"
+      />
+      <el-input
+        v-else
+        v-model="l.value"
+        style="width: 72% !important"
+        size="small"
+        class="chooseItem"
+        clearable
+        :placeholder="l.placeholder"
+        @change="(e) => $emit('change', l.key, e)"
+      />
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    data: {
+      type: Array,
+      required: false,
+      default: () => []
+    },
+    loading: {
+      type: Boolean,
+      default: false,
+      required: true
+    },
+    styles: {
+      type: Object,
+      default: () => {},
+      required: false
+    }
+  },
+  data() {
+    return {
+      pickerOptions: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一个月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近三个月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      }
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.searchForm {
+  .name {
+    min-width: 80px;
+  }
+  .chooseItem {
+    flex: 1;
+    /deep/.el-range-separator {
+      width: auto;
+    }
+  }
+}
+.item-style {
+  display: flex;
+  justify-content: flex-start;
+  .item-detail {
+    min-width:100px;
+    color: #8492a6;
+    font-size: 13px;
+    overflow:hidden
+  }
+}
+</style>

+ 32 - 0
src/components/ui/plainBtn.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="btn" :class="type">
+    {{ text }}11
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    text: {
+      type: String,
+      default: '',
+      required: true
+    },
+    type: {
+      type: String,
+      default: 'primary',
+      required: true
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.btn {
+  padding: 7px 15px;
+  border-radius: 3px;
+  border: 1px solid #dcdfe6;
+  &.primary {
+    border-color: #50A6FF;
+    color: #50A6FF;
+  }
+}
+</style>

+ 5 - 0
src/icons/svg/admin.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+  <defs>
+  </defs>
+  <path id="管理员" d="M74.091,71.773a.416.416,0,0,1-.383.385h-.031a.671.671,0,0,0-.669.669.78.78,0,0,0,.059.255.482.482,0,0,1-.165.584l-.018.012-.777.427a.5.5,0,0,1-.213.049.519.519,0,0,1-.381-.163.622.622,0,0,0-1.1-.006.525.525,0,0,1-.576.12l-.768-.427a.489.489,0,0,1-.181-.6.772.772,0,0,0,.059-.253.671.671,0,0,0-.67-.669h-.026a.418.418,0,0,1-.388-.386,2.953,2.953,0,0,1,0-1.242.418.418,0,0,1,.383-.386h.031a.67.67,0,0,0,.67-.668.752.752,0,0,0-.06-.256.484.484,0,0,1,.166-.585l.018-.011.8-.438.015-.006a.529.529,0,0,1,.571.119.618.618,0,0,0,1.072.005.53.53,0,0,1,.572-.114l.782.432a.488.488,0,0,1,.182.6.788.788,0,0,0-.058.253.67.67,0,0,0,.669.668H73.7a.418.418,0,0,1,.388.386,3.979,3.979,0,0,1,.066.621A4.24,4.24,0,0,1,74.091,71.773Zm-.583-1.031A1.277,1.277,0,0,1,72.4,69.477a1.254,1.254,0,0,1,.068-.387l-.553-.307a2.279,2.279,0,0,1-.228.185,1.06,1.06,0,0,1-1.386,0,2,2,0,0,1-.229-.19l-.579.318a1.249,1.249,0,0,1,.069.386,1.278,1.278,0,0,1-1.112,1.266,2.2,2.2,0,0,0,0,.817,1.25,1.25,0,0,1,1.043,1.653l.535.3a2.4,2.4,0,0,1,.229-.193,1.057,1.057,0,0,1,1.421.006,2.337,2.337,0,0,1,.23.2l.56-.309a1.254,1.254,0,0,1,1.043-1.653,2.207,2.207,0,0,0,0-.819Zm-2.544,1.587a1.166,1.166,0,1,1,1.182-1.182A1.184,1.184,0,0,1,70.964,72.329Zm0-1.731a.554.554,0,1,0,.573.55A.574.574,0,0,0,70.964,70.6Zm-1.715-3.009-.192.15a3.044,3.044,0,0,1-1.634.5h-.063q-.208,0-.416.02h-.005a4.4,4.4,0,0,0-3.992,4.361v.669h4.9a3.985,3.985,0,0,0,.478.782H62.551a.393.393,0,0,1-.4-.39v-1.06a5.142,5.142,0,0,1,3.279-4.794l.226-.089-.192-.15A3.017,3.017,0,0,1,64.292,65.2a3.067,3.067,0,0,1,6.133,0A3.022,3.022,0,0,1,69.249,67.589Zm-1.89-4.651A2.26,2.26,0,1,0,69.635,65.2,2.27,2.27,0,0,0,67.359,62.938Z" transform="translate(-62.156 -62.156)"/>
+</svg>

+ 3 - 0
src/icons/svg/icon-qp.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+  <path id="全屏" d="M183.792,170.667a.875.875,0,0,1,.875.875v12.25a.875.875,0,0,1-.875.875h-12.25a.875.875,0,0,1-.875-.875v-12.25a.875.875,0,0,1,.875-.875Zm0,.875h-12.25v12.25h12.25Zm-4.165,7.466,2.239,2.24v-1.568a.437.437,0,0,1,.875,0V182.3a.438.438,0,0,1-.437.438h-2.625a.437.437,0,0,1,0-.875h1.569l-2.24-2.24a.437.437,0,1,1,.618-.62Zm-3.973-6.416a.437.437,0,1,1,0,.875h-1.569l2.24,2.24a.437.437,0,1,1-.618.619l-2.241-2.241v1.569a.437.437,0,1,1-.875,0v-2.625a.437.437,0,0,1,.438-.438Z" transform="translate(-170.667 -170.667)"/>
+</svg>

+ 3 - 0
src/icons/svg/icon-sx.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+  <path id="路径_438" data-name="路径 438" d="M9.325,10.637H5.387a.438.438,0,0,0,0,.875H8.275L5.3,14.488l.613.612,2.975-2.975v2.887a.438.438,0,1,0,.875,0V11.075a.449.449,0,0,0-.438-.438Zm5.688-1.75H12.125L15.1,5.912,14.488,5.3,11.512,8.275V5.387a.438.438,0,0,0-.875,0V9.325a.449.449,0,0,0,.438.438h3.938a.413.413,0,0,0,.438-.438A.438.438,0,0,0,15.012,8.887ZM16.5,3.2H3.9a.7.7,0,0,0-.7.7V16.5a.7.7,0,0,0,.7.7H16.5a.7.7,0,0,0,.7-.7V3.9A.7.7,0,0,0,16.5,3.2Zm-.176.875v12.25H4.075V4.075Z" transform="translate(-3.2 -3.2)"/>
+</svg>

+ 8 - 0
src/icons/svg/setting.svg

@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="11" viewBox="0 0 12 11">
+  <defs>
+  </defs>
+  <g id="设置" transform="translate(-112 -128)">
+    <path id="路径_13151" data-name="路径 13151" class="cls-1" d="M120.141,139h-4.313a1.744,1.744,0,0,1-1.5-.874l-2.094-3.721a1.868,1.868,0,0,1,0-1.812l2.125-3.721a1.694,1.694,0,0,1,1.469-.874h4.313a1.744,1.744,0,0,1,1.5.874l2.125,3.721a1.868,1.868,0,0,1,0,1.812l-2.125,3.721A1.706,1.706,0,0,1,120.141,139Zm-4.313-10.029a.852.852,0,0,0-.687.388l-2.094,3.721a.813.813,0,0,0,0,.841l2.125,3.721a.778.778,0,0,0,.688.388h4.313a.852.852,0,0,0,.687-.388l2.125-3.721a.813.813,0,0,0,0-.841l-2.125-3.721a.958.958,0,0,0-.719-.388Z" transform="translate(0)"/>
+    <path id="路径_13152" data-name="路径 13152" class="cls-1" d="M398.888,347.644a2.089,2.089,0,0,1,0-4.177.5.5,0,1,1,0,.995,1.094,1.094,0,1,0,1.094,1.094.5.5,0,1,1,.995,0A2.123,2.123,0,0,1,398.888,347.644Z" transform="translate(-280.752 -212.246)"/>
+  </g>
+</svg>

+ 6 - 0
src/styles/PublicStyle/index.scss

@@ -74,6 +74,12 @@
   width: 85px;
 }
 // 任务状态控制
+.public_btn4 .el-input--suffix .el-input__inner { // 任务状态控制
+  padding-right: 10px;
+  padding-left: 10px;
+  width: 103px;
+}
+// 任务状态控制
 
 .status_color { // 迭代状态样式修改(颜色)
   /deep/ input {

+ 5 - 0
src/utils/global.js

@@ -51,3 +51,8 @@ export function formatHMS(data) {
   time = (hours < 10 ? ('0' + hours) : hours) + '小时' + (minutes < 10 ? ('0' + minutes) : minutes) + '分' + (seconds < 10 ? ('0' + seconds) : seconds) + '秒'
   return time
 }
+
+//  生成随机数字
+export function createRandomNumber() {
+  return Math.ceil(Math.random() * 10000)
+}

+ 11 - 1
src/utils/options.js

@@ -11,9 +11,19 @@ export function getBarOption(xAxis, data) {
       'left': '5%',
       'right': '5%',
       'top': '10%',
-      'bottom': '10%',
+      'bottom': data && data.length > 50 ? '20%' : '10%',
       'containLabel': true
     },
+    'dataZoom': [
+      {
+        'type': 'slider',
+        'show': data && data.length > 50,
+        'startValue': 0,
+        'endValue': 50,
+        'handleSize': 8,
+        'bottom': '10%'
+      }
+    ],
     'xAxis': [{
       'type': 'category',
       'data': xAxis,

+ 34 - 28
src/views/projectManage/bugList/bugindex.vue

@@ -225,21 +225,17 @@
               </el-row>
             </el-form>
           </el-col>
-          <el-row v-if="filterList.length && filterList.length>0" type="flex" justify="space-between" class="filter">
-            <el-col :span="2">
-              <span>我的过滤器:</span>
-            </el-col>
-            <el-col :span="20" class="mine-filter">
-              <span v-for="item in filterList" :key="item.id" class="filter-item" @click="getFilterItem(item.id)">
-                <el-tooltip class="item" effect="dark" :content="item.name" placement="bottom">
-                  <span>{{ item.name }}</span>
-                </el-tooltip>
-              </span>
-            </el-col>
-            <el-col :span="2" align="end">
+          <div v-if="filterList.length && filterList.length > 0" class="filter">
+            <div class="filterWrap">
+              <div class="title">我的过滤器:</div>
+              <div class="itemBox">
+                <el-tag v-for="item in filterList" :key="item.id" class="item" @click="getFilterItem(item.id)">{{ item.name }}</el-tag>
+              </div>
+            </div>
+            <div class="btn">
               <span @click.stop="showEditSearch = true">管理过滤器</span>
-            </el-col>
-          </el-row>
+            </div>
+          </div>
         </el-row>
       </el-header>
       <el-main style="padding: 10px">
@@ -608,22 +604,32 @@ export default {
 </script>
 <style scoped lang="scss">
 .filter {
-  font-size: 14px;
   width: 100%;
-  padding: 0 11px 15px 15px;
-  color: #606266;
-  cursor: pointer;
-  .mine-filter {
-    .filter-item {
-      display: inline-block;
-      width: 15%;
-      color: #409EFF;
-      margin-right: 15px;
-      overflow: hidden;
-      text-overflow:ellipsis;
-      white-space: nowrap;
-      margin-bottom: 5px;
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  margin-top: 15px;
+  .filterWrap {
+    display: flex;
+    align-items: baseline;
+    .title {
+      width: 100px;
     }
+    .itemBox {
+      .item {
+        display: inline-block;
+        margin-right: 20px;
+        margin-bottom: 10px;
+        cursor: pointer;
+      }
+    }
+  }
+  .btn {
+    font-size: 14px;
+    color: #00A0FF;
+    cursor: pointer;
+    min-width: 80px;
+    text-align: center;
   }
 }
 .belong-task {

+ 2 - 2
src/views/projectManage/bugList/details/bugTableDialog.vue

@@ -74,10 +74,10 @@
       :header-cell-style="{ color: '#4A4A4A', fontSize: '14px', fontWeight: '500' }"
       row-key="id"
     >
-      <el-table-column label="优先级" prop="priorityCode" min-width="100" sortable align="center">
+      <el-table-column label="优先级" prop="priorityLevelShortName" min-width="100" sortable align="center">
         <template slot-scope="scope" style="text-align: center;">
           <span class="div_priority" :class="[{'priority_color': scope.row.priorityLevel === 'High'},{'priority_color1': scope.row.priorityLevel === 'Medium'},{'priority_color3': scope.row.priorityLevel === 'Low'}]">
-            {{ scope.row.priorityLevel.substring(0, 1) }}
+            {{ scope.row.priorityLevelShortName }}
           </span>
         </template>
       </el-table-column>

+ 30 - 23
src/views/projectManage/bugList/details/index.vue

@@ -356,7 +356,12 @@
             </div>
           </el-tooltip>
           <div v-show="describeEditorVisible" style="margin-top:15px">
-            <editor v-model="text_content" class="tinymce" :init="configure" @blur="describeConfirm" />
+            <!-- <editor v-model="text_content" class="tinymce" :init="configure" @blur="describeConfirm" /> -->
+            <normal-area
+              id="buglist_tinymce"
+              :value.sync="text_content"
+              :height="500"
+            />
             <div style="margin-top:40px;float: right">
               <el-button @click="describeCancel()">取 消</el-button>
               <el-button type="primary" @click="describeConfirm()">确 认</el-button>
@@ -557,10 +562,12 @@ import createdBug from '@/views/projectManage/bugList/file/createdBug'
 import axios from 'axios'
 import { deepClone } from '@/utils/global'
 import searchPeople from '@/components/select/searchPeople' // 人员select
-import tinymce from 'tinymce/tinymce'
-import Editor from '@tinymce/tinymce-vue'
-import 'tinymce/themes/silver/theme'
-import 'tinymce/icons/default/icons'
+// import tinymce from 'tinymce/tinymce'
+// import Editor from '@tinymce/tinymce-vue'
+import normalArea from '@/components/input/normalArea' // 富文本
+import 'tinymce/plugins/table'// 插入表格插件
+// import 'tinymce/themes/silver/theme'
+// import 'tinymce/icons/default/icons'
 
 document.body.onpaste = function(event) {
   const data = (event.clipboardData || window.clipboardData)
@@ -584,7 +591,7 @@ export default {
     normalDialog,
     statusChange,
     searchPeople,
-    Editor
+    normalArea
   },
   props: {
     id: {
@@ -604,22 +611,22 @@ export default {
     return {
       bugId: -1, // 当前缺陷Id
       bizId: -1, // 当前缺陷BizId
-      configure: {
-        language_url: '/tinymce/langs/zh_CN.js',
-        language: 'zh_CN',
-        skin_url: '/tinymce/skins/ui/oxide', // 编辑器需要一个skin才能正常工作,所以要设置一个skin_url指向之前复制出来的skin文件
-        browser_spellcheck: true, // 拼写检查
-        branding: false, // 去水印
-        elementpath: false, // 禁用编辑器底部的状态栏
-        statusbar: false, // 隐藏编辑器底部的状态栏
-        paste_data_images: true, // 允许粘贴图像
-        menubar: false, // 隐藏最上方menu
-        fontsize_formats: '14px 16px 18px 20px 24px 26px 28px 30px 32px 36px', // 字体大小
-        file_picker_types: 'image',
-        images_upload_credentials: true,
-        plugins: 'lists table textcolor wordcount contextmenu', // 引入插件
-        toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect'
-      },
+      // configure: {
+      //   language_url: '/tinymce/langs/zh_CN.js',
+      //   language: 'zh_CN',
+      //   skin_url: '/tinymce/skins/ui/oxide', // 编辑器需要一个skin才能正常工作,所以要设置一个skin_url指向之前复制出来的skin文件
+      //   browser_spellcheck: true, // 拼写检查
+      //   branding: false, // 去水印
+      //   elementpath: false, // 禁用编辑器底部的状态栏
+      //   statusbar: false, // 隐藏编辑器底部的状态栏
+      //   paste_data_images: true, // 允许粘贴图像
+      //   menubar: false, // 隐藏最上方menu
+      //   fontsize_formats: '14px 16px 18px 20px 24px 26px 28px 30px 32px 36px', // 字体大小
+      //   file_picker_types: 'image',
+      //   images_upload_credentials: true,
+      //   plugins: 'lists table textcolor wordcount contextmenu', // 引入插件
+      //   toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect'
+      // },
       text_content: '',
       clielIcon: true, // 所属任务交互
       active: false,
@@ -735,7 +742,7 @@ export default {
     }
   },
   mounted() {
-    tinymce.init({ selector: '.tinymce', height: '100' })
+    // tinymce.init({ selector: '.tinymce', height: '100' })
     this.bugGetEnum()
     const id = this.id === -1 ? this.bugId : this.id
     this.bugGet(id, false).then(res => {

+ 0 - 1
src/views/projectManage/bugList/details/statusChange.vue

@@ -62,7 +62,6 @@
     </el-dialog>
   </div>
 </template>
-
 <script>
 import '@/styles/PublicStyle/index.scss'
 import { bugUpdate } from '@/api/defectManage'

+ 32 - 22
src/views/projectManage/bugList/file/createdBug.vue

@@ -131,8 +131,15 @@
               <el-form-item label="描述" style="width:100%;">
                 <el-row v-if="editr">
                   <el-col :span="24">
-                    <div id="wange" style="background-color: #FFF;" class="toolbar" />
-                    <div id="wange1" class="text" />
+                    <!-- <div id="wange" style="background-color: #FFF;" class="toolbar" />
+                    <div id="wange1" class="text" /> -->
+                    <!-- formInline.bugDescribe -->
+                    <normal-area
+                      id="buglist_file_tinymce"
+                      :value.sync="formInline.bugDescribe"
+                      :height="200"
+                      :full-position-style="{ left:'0', bottom: '30px' }"
+                    />
                   </el-col>
                 </el-row>
               </el-form-item>
@@ -183,7 +190,7 @@
 const _ = require('lodash')
 import { mapGetters } from 'vuex'
 import { analysisBizId_id } from '@/utils/crypto-js.js'
-import E from 'wangeditor'
+// import E from 'wangeditor'
 import {
   bugGetEnum,
   settingGetBizList,
@@ -196,6 +203,8 @@ import { memberQueryMemberInfoByIDAPorName } from '@/api/projectIndex'
 import normalDialog from '@/components/dialog/normalDialog'
 import '@/views/projectManage/bugList/css/index.css'
 import '@/styles/PublicStyle/index.scss'
+import normalArea from '@/components/input/normalArea' // 富文本
+import 'tinymce/plugins/table'// 插入表格插件
 import axios from 'axios'
 
 document.body.onpaste = function(event) {
@@ -216,7 +225,8 @@ document.body.onpaste = function(event) {
 export default {
   name: 'Createdbug',
   components: {
-    normalDialog
+    normalDialog,
+    normalArea
   },
   filters: {
     limit(e, limit) {
@@ -411,24 +421,24 @@ export default {
       )
     },
     getEcharts() {
-      setTimeout(() => {
-        this.$set(this.formInline, 'bugDescribe', '')
-        const editorRemark = new E('#wange', '#wange1')
-        editorRemark.customConfig.menus = [
-          'bold',
-          'italic',
-          'underline',
-          'link',
-          'list',
-          'justify',
-          'table',
-          'foreColor'
-        ]
-        editorRemark.customConfig.onchange = html => {
-          this.formInline.bugDescribe = html
-        }
-        editorRemark.create()
-      }, 100)
+      // setTimeout(() => {
+      //   this.$set(this.formInline, 'bugDescribe', '')
+      //   // const editorRemark = new E('#wange', '#wange1')
+      //   editorRemark.customConfig.menus = [
+      //     'bold',
+      //     'italic',
+      //     'underline',
+      //     'link',
+      //     'list',
+      //     'justify',
+      //     'table',
+      //     'foreColor'
+      //   ]
+      //   editorRemark.customConfig.onchange = html => {
+      //     this.formInline.bugDescribe = html
+      //   }
+      //   editorRemark.create()
+      // }, 100)
     },
     getcurrentHandler(e) {
       this.$set(this.formInline, 'currentHandler', e)

+ 7 - 2
src/views/projectManage/components/filterList.vue

@@ -78,6 +78,11 @@ export default {
       type: Boolean,
       default: false,
       required: true
+    },
+    filterType: {
+      type: Number,
+      default: 3,
+      required: false
     }
   },
   data() {
@@ -109,7 +114,7 @@ export default {
         pageSize: this.pageSize,
         curIndex: this.curIndex,
         bizId: Number(localStorage.getItem('bizId')),
-        filterType: 3
+        filterType: this.filterType
       }
       const res = await filtergetFilterList(params)
       if (res.code === 200) {
@@ -159,7 +164,7 @@ export default {
         this.$set(this.filterList[e.index], 'name', this.copyFilterList[e.index].name)
         return false
       }
-      const res = await filterUpdateFilter({ id: e.id, name: e.name, filterType: 3, creator: localStorage.getItem('username') })
+      const res = await filterUpdateFilter({ id: e.id, name: e.name, filterType: this.filterType, creator: localStorage.getItem('username') })
       if (res.code === 200) {
         this.$message({ showClose: true, message: '修改名称成功', type: 'success' })
         this.getFilterList()

+ 6 - 3
src/views/projectManage/onlineproblem/component/header/index.vue

@@ -27,9 +27,10 @@
   </div>
 </template>
 <script>
+const _ = require('lodash')
 import searchHeader from '@/components/searchHeader'
 import searchData from './searchData'
-import mainTitle from '../mainTitle'
+import mainTitle from '@/components/mainTitle'
 import chart from '../chart'
 export default {
   components: {
@@ -51,7 +52,7 @@ export default {
   },
   data() {
     return {
-      renderList: searchData,
+      renderList: _.cloneDeep(searchData),
       year: '',
       month: '',
       nowTab: 'list',
@@ -89,6 +90,7 @@ export default {
     },
     async search(key, value) {
       const data = {}
+      // 因为高级筛选不自动搜索,所以每次出发搜索都map renderList就好。
       this.renderList.default.map(t => t.map(g => {
         data[g.key] = g.value
       }))
@@ -97,7 +99,8 @@ export default {
           data[g.key] = g.value
         }))
       }
-      if (key) {
+      // 如果是年和月更新全局的变量
+      if (key === 'month' || key === 'year') {
         this[key] = value === '全部' ? '0' : value
       }
       data.year = '' + this.year

+ 3 - 3
src/views/projectManage/onlineproblem/create/index.vue

@@ -13,13 +13,13 @@
       </header>
       <div class="content">
         <!-- 复盘 -->
-        <div>
+        <div style="padding-top: 15px">
           <normal-area
             id="replay"
             :value.sync="replayDesc"
             :empty-text="'点击'"
             :input-button="'修改模板'"
-            :styles="{ padding: '15px 0px 0px 0px', maxHeight: '200px' }"
+            :styles="{ maxHeight: '200px' }"
           />
         </div>
       </div>
@@ -61,7 +61,7 @@
 </template>
 <script>
 import { create } from '@/api/onlineproblem'
-import mainTitle from '../component/mainTitle'
+import mainTitle from '@/components/mainTitle'
 import headTitle from '@/components/headTitle'
 import baseBox from './component/base'
 import makeBetterList from './component/makeBetterList'

+ 14 - 12
src/views/projectManage/projectList/components/modifySchedule.vue

@@ -9,7 +9,7 @@
     @confirm="confirmForm()"
     @cancel="cancel()"
   >
-    <article v-if="!isDeleteStatus">
+    <article v-if="!isDeleteStatus" class="pro_pro_com_modifySchedule">
       <el-form ref="form" :model="form" :rules="form_rules" label-width="100px" :label-position="'left'">
         <h2>排期内容</h2>
         <el-form-item label="排期类型" prop="type">
@@ -549,18 +549,18 @@ export default {
 }
 </script>
 <style scoped lang="scss">
-article::-webkit-scrollbar {
+.pro_pro_com_modifySchedule::-webkit-scrollbar {
   -webkit-appearance: none;
   width: 7px;
 }
 
-article::-webkit-scrollbar-thumb {
+.pro_pro_com_modifySchedule::-webkit-scrollbar-thumb {
   border-radius: 4px;
   background-color: rgba(0, 0, 0, .5);
   box-shadow: 0 0 1px rgba(255, 255, 255, .5);
 }
-article {
-  max-height: 450px;
+.pro_pro_com_modifySchedule {
+  max-height: 480px;
   overflow: scroll;
   .blue {
     color: #409EFF;
@@ -569,29 +569,31 @@ article {
     color: #333333;
     font-size: 18px;
     font-weight: bold;
-    margin-bottom: 20px;
-    padding-left: 10px;
+    margin-bottom: 10px;
   }
   .el-form-item  {
-    margin-bottom: 18px;
+    margin-bottom: 10px;
   }
 }
->>>.el-form {
+/deep/.el-dialog__body {
+  padding: 10px 20px;
+}
+/deep/.el-form {
   padding: 0 156px 0 60px;
 }
 .item-desc {
-  >>>.el-form-item__label {
+  /deep/.el-form-item__label {
     padding-left: 10px;
   }
 }
 .select-by {
-  >>>.el-input__inner {
+  /deep/.el-input__inner {
     border-top-right-radius: 0;
     border-bottom-right-radius: 0;
   }
 }
 .select-task {
-  >>>.el-input__inner {
+  /deep/.el-input__inner {
     border-top-left-radius: 0;
     border-bottom-left-radius: 0;
   }

+ 73 - 71
src/views/projectManage/projectList/components/taskList.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="pro_pro_com_taskList">
     <el-row v-if="!showHeader" class="select-main" type="flex" align="center">
       <el-col :span="2" class="flex-align-center">
         <el-checkbox v-model="planChecked" class="plan-checked" @change="changeCheck" />
@@ -542,84 +542,86 @@ export default {
 }
 </style>
 <style lang="scss">
-.btns .el-input--suffix .el-input__inner {
-  padding-right: 10px;
-  padding-left: 10px;
-  width: 73px;
-}
-.item{
-  /deep/ input {
-    color: rgb(126, 211, 33);
-    border: 1px solid rgb(126, 211, 33);
-     border-color: rgb(126, 211, 33) !important;
-         font-weight: 900;
-  }
-  /deep/ .el-input__suffix {
-    color: rgb(126, 211, 33) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-    color: rgb(126, 211, 33) !important;
-  }
-}
-.item1 {
-  /deep/ input {
-    color: rgb(255, 204, 102);
-     border: 1px solid rgb(255, 204, 102);
-     border-color: rgb(255, 204, 102) !important;
-         font-weight: 900;
+.pro_pro_com_taskList {
+  .btns .el-input--suffix .el-input__inner {
+    padding-right: 10px;
+    padding-left: 10px;
+    width: 73px;
   }
-  /deep/ .el-input__suffix {
-    color: rgb(255, 204, 102) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-    color: rgb(255, 204, 102) !important;
+  .item{
+    /deep/ input {
+      color: rgb(126, 211, 33);
+      border: 1px solid rgb(126, 211, 33);
+      border-color: rgb(126, 211, 33) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(126, 211, 33) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
+      color: rgb(126, 211, 33) !important;
+    }
   }
-}
-.item2 {
-  /deep/ input {
-    color: rgb(245, 108, 108);
-    border: 1px solid rgb(245, 108, 108);
-    border-color: rgb(245, 108, 108) !important;
-        font-weight: 900;
+  .item1 {
+    /deep/ input {
+      color: rgb(255, 204, 102);
+      border: 1px solid rgb(255, 204, 102);
+      border-color: rgb(255, 204, 102) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(255, 204, 102) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
+      color: rgb(255, 204, 102) !important;
+    }
   }
-   /deep/ .el-input__suffix {
+  .item2 {
+    /deep/ input {
+      color: rgb(245, 108, 108);
+      border: 1px solid rgb(245, 108, 108);
+      border-color: rgb(245, 108, 108) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(245, 108, 108) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: rgb(245, 108, 108) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-   color: rgb(245, 108, 108) !important;
-  }
-}
-.item3 {
-  /deep/ input {
-    color: #D675F0;
-    border: 1px solid #D675F0;
-    border-color: #D675F0 !important;
-        font-weight: 900;
+    }
   }
-    /deep/ .el-input__suffix {
+  .item3 {
+    /deep/ input {
+      color: #D675F0;
+      border: 1px solid #D675F0;
+      border-color: #D675F0 !important;
+          font-weight: 900;
+    }
+      /deep/ .el-input__suffix {
+      color: #D675F0 !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: #D675F0 !important;
-    right: 1px;
-  }
-   /deep/ .el-select__caret {
-   color: #D675F0 !important;
-  }
-}
-.item-color {
-  /deep/ input {
-    color: rgb(106, 180, 255);
-    border: 1px solid rgb(106, 180, 255);
-    border-color: rgb(106, 180, 255) !important;
-        font-weight: 900;
+    }
   }
-    /deep/ .el-input__suffix {
+  .item-color {
+    /deep/ input {
+      color: rgb(106, 180, 255);
+      border: 1px solid rgb(106, 180, 255);
+      border-color: rgb(106, 180, 255) !important;
+          font-weight: 900;
+    }
+      /deep/ .el-input__suffix {
+      color: rgb(106, 180, 255) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: rgb(106, 180, 255) !important;
-    right: 1px;
-  }
-   /deep/ .el-select__caret {
-   color: rgb(106, 180, 255) !important;
+    }
   }
 }
 </style>

+ 2 - 7
src/views/projectManage/projectList/projectIndex.vue

@@ -4,11 +4,7 @@
       <div class="stylus-title">
         <span style="font-size: 22px;letter-spacing: 1px;font-weight: 600;color: #333B4A;padding-left: 15px">项目</span>
         <div class="new-tab-open">
-          <el-switch
-            v-model="newTabOpen"
-            active-text="新标签页跳转"
-            @change="logHandle('switchJumpOpen')"
-          />
+          <!-- 这个可以放按钮 -->
         </div>
         <div>
           <el-button type="primary" size="mini" @click="home_created_project">新建项目</el-button>
@@ -340,7 +336,6 @@ import '@/views/projectManage/publicCss/index.css'
 export default {
   data() {
     return {
-      newTabOpen: true, // 是否新的tab页打开
       curIndex: 1,
       pageSize: 15,
       activeColor: 'red',
@@ -448,7 +443,7 @@ export default {
     },
     link_project(id) {
       const bizId_id = EncryptId(`${this.bizId}_${id}`)
-      if (this.newTabOpen) {
+      if (localStorage.getItem('openPageHandle') === 'blank') {
         const newTab = this.$router.resolve({ name: '项目详情', query: { bizId_id: bizId_id }})
         window.open(newTab.href, '_blank')
       } else {

+ 491 - 181
src/views/projectManage/requirement/list/index.vue

@@ -1,155 +1,205 @@
 <template>
   <div class="sos" style="background-color:#F2F3F6;min-height:calc(100vh - 80px);padding:0 10px 10px 10px">
     <div class="stylus-head">
-      <div class="stylus-title">
-        <span style="font-size: 22px;letter-spacing: 1px;font-weight: 600;color: #333B4A;padding-left: 15px">需求</span>
-        <div class="new-tab-open">
-          <el-switch
-            v-model="newTabOpen"
-            active-text="新标签页跳转"
-            @change="logHandle('switchJumpOpen')"
-          />
-        </div>
-        <el-button type="primary" size="mini" @click="createDialogVisible = true">新建需求</el-button>
-      </div>
-      <el-divider style="color: #EEF0F5;" />
-      <div class="Layout" style="padding-top: 5px">
-        <div>
-          <el-form :model="searchForm" class="Layout">
-            <div class="Layout_flex_end" style="padding-left:15px">
-              <div class="queryName">需求名称</div>
-              <el-input v-model="requirementName" size="small" clearable style="width:72% !important;" placeholder="请搜索标题或ID或望岳ID" @change="getTableData()" />
-            </div>
+      <mainTitle
+        title="需求"
+        btn-text="新建需求"
+        :tab-show="true"
+        @btn-handle="createDialogVisible = true"
+        @change-tab="changeTab"
+      />
+      <div v-if="nowTab === 'charts'" class="chartView">
+        <chartView
+          :data="chartData"
+          :type-option-list="typeOptionList"
+          :chart-search-data="searchForm"
+          @search="get_charts()"
+          @changeList="(code) => get_chartListDetial(code)"
+        >
+          <div slot="searchBox">
             <div class="Layout">
-              <div class="queryName marginLeft">需求状态</div>
-              <el-select v-model="searchForm.statusList" size="small" multiple clearable filterable placeholder="请选择" @change="getTableData()">
-                <el-option v-for="(item, index) in requiredStatus" :key="index" :label="item.msg" :value="item.code" />
-              </el-select>
-            </div>
-            <div class="Layout">
-              <div class="queryName marginLeft">需求方向</div>
-              <el-cascader v-model="searchForm.rqmtOrntIds" size="small" collapse-tags :props="props" :options="demandDirection" placeholder="请选择" style="width: 72%" @change="getTableData()" />
+              <div class="Layout">
+                <div class="queryName">需求方向</div>
+                <el-cascader v-model="searchForm.rqmtOrntIds" size="small" collapse-tags :props="props" :options="demandDirection" placeholder="请选择" style="width: 72%" @change="get_charts()" />
+              </div>
+              <span class="screen" style="text-align:right" @click="showChartModal = true">更多筛选</span>
             </div>
-          </el-form>
-        </div>
-        <span class="screen" @click="showSelect">{{ goodName }}</span>
+          </div>
+        </chartView>
       </div>
-      <div v-show="DetailedScreening" class="stylus-more">
-        <div>
-          <el-form :model="searchForm" class="flex_start">
-            <div class="Layout">
-              <div class="queryName">所属项目</div>
-              <el-select v-model="searchForm.belongingProject" size="small" clearable filterable placeholder="请选择">
-                <el-option v-for="item in AttributionItems" :key="item.id" :label="item.name" :value="item.id" />
-              </el-select>
-            </div>
-            <div class="Layout">
-              <div class="queryName marginLeft">PM</div>
-              <search-people :value.sync="searchForm.pm" :clearable="true" :multiple="false" style="width:72% !important;" />
-            </div>
-            <div class="Layout">
-              <div class="queryName marginLeft">需求类型</div>
-              <el-select v-model="searchForm.type" size="small" clearable filterable placeholder="请选择">
-                <el-option v-for="item in searchInfo.type" :key="item.code" :label="item.msg" :value="item.code" />
-              </el-select>
-            </div>
-          </el-form>
-          <el-form :model="searchForm" class="flex_start el-from-spacing">
-            <div class="Layout">
-              <div class="queryName">需求来源</div>
-              <el-select v-model="searchForm.sourceTypeList" size="small" multiple clearable filterable placeholder="请选择">
-                <el-option v-for="item in searchInfo.sourceType" :key="item.code" :label="item.msg" :value="item.code" />
-              </el-select>
-            </div>
-            <div class="Layout">
-              <div class="queryName marginLeft">优先级</div>
-              <el-select v-model="searchForm.priorityList" size="small" multiple clearable filterable placeholder="请选择">
-                <el-option v-for="item in searchInfo.priority" :key="item.code" :label="item.msg" :value="item.code" />
+      <div v-if="nowTab === 'list'" class="search_box">
+        <div class="Layout" style="padding: 5px 0 0 15px">
+          <div>
+            <el-form :model="searchForm" class="Layout">
+              <div class="Layout_flex_end item">
+                <div class="queryName">需求名称</div>
+                <el-input v-model="searchForm.name" size="small" clearable style="width:72% !important;" placeholder="请搜索标题或ID或望岳ID" @change="getTableData()" />
+              </div>
+              <div class="Layout item">
+                <div class="queryName">需求状态</div>
+                <el-select v-model="searchForm.statusList" size="small" multiple clearable filterable placeholder="请选择" @change="getTableData()">
+                  <el-option v-for="(item, index) in requiredStatus" :key="index" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+              <div class="Layout item">
+                <div class="queryName">需求方向</div>
+                <el-cascader v-model="searchForm.rqmtOrntIds" size="small" collapse-tags :props="props" :options="demandDirection" placeholder="请选择" style="width: 72%" @change="getTableData()" />
+              </div>
+            </el-form>
+          </div>
+          <span class="screen" @click="showSelect">{{ goodName }}</span>
+        </div>
+        <div v-show="DetailedScreening" class="stylus-more">
+          <div>
+            <el-form :model="searchForm" class="flex_start">
+              <div class="Layout item">
+                <div class="queryName">所属项目</div>
+                <el-select v-model="searchForm.belongingProject" size="small" clearable filterable placeholder="请选择">
+                  <el-option v-for="item in AttributionItems" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+              <div class="Layout item">
+                <div class="queryName">PM</div>
+                <!-- <search-people :value.sync="searchForm.pm" :clearable="true" :multiple="false" style="width:72% !important;" /> -->
+                <el-select
+                  v-model="searchForm.pm"
+                  clearable
+                  filterable
+                  remote
+                  placeholder="请输入姓名或邮箱前缀"
+                  :remote-method="remoteMethod"
+                  :loading="loading"
+                  size="small"
+                >
+                  <el-option v-for="item in options" :key="item.idap" :label="item.name" :value="item.idap">
+                    <div class="flex_start">
+                      <div class="deptName">{{ item.deptName }}</div>
+                      <div style="min-width:80px">{{ item.name }}</div>
+                      <div class="deptName">{{ item.idap }}</div>
+                    </div>
+                  </el-option>
+                </el-select>
+              </div>
+              <div class="Layout item">
+                <div class="queryName">需求类型</div>
+                <el-select v-model="searchForm.type" size="small" clearable filterable placeholder="请选择">
+                  <el-option v-for="item in searchInfo.type" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+            </el-form>
+            <el-form :model="searchForm" class="flex_start el-from-spacing">
+              <div class="Layout item">
+                <div class="queryName">需求来源</div>
+                <el-select v-model="searchForm.sourceTypeList" size="small" multiple clearable filterable placeholder="请选择">
+                  <el-option v-for="item in searchInfo.sourceType" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+              <div class="Layout item">
+                <div class="queryName">优先级</div>
+                <el-select v-model="searchForm.priorityList" size="small" multiple clearable filterable placeholder="请选择">
+                  <el-option v-for="item in searchInfo.priority" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+              <div class="Layout item">
+                <div class="queryName">需求提出人</div>
+                <!-- <search-people :value.sync="searchForm.rqmtProposer" :clearable="true" :multiple="false" style="width:72% !important;" /> -->
+                <el-select
+                  v-model="searchForm.rqmtProposer"
+                  clearable
+                  filterable
+                  remote
+                  placeholder="请输入姓名或邮箱前缀"
+                  :remote-method="remoteMethod"
+                  :loading="loading"
+                  size="small"
+                >
+                  <el-option v-for="item in options" :key="item.idap" :label="item.name" :value="item.idap">
+                    <div class="flex_start">
+                      <div class="deptName">{{ item.deptName }}</div>
+                      <div style="min-width:80px">{{ item.name }}</div>
+                      <div class="deptName">{{ item.idap }}</div>
+                    </div>
+                  </el-option>
+                </el-select>
+              </div>
+            </el-form>
+            <el-form :model="searchForm" class="flex_start el-from-spacing">
+              <div class="Layout item">
+                <div class="queryName">来自望岳</div>
+                <el-select v-model="searchForm.isFromDpm" size="small" clearable filterable placeholder="请选择">
+                  <el-option v-for="item in isFromDpmList" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </div>
+              <div class="Layout item">
+                <div class="queryName">创建时间</div>
+                <el-date-picker
+                  v-model="searchForm.date"
+                  type="daterange"
+                  align="right"
+                  unlink-panels
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  size="small"
+                  style="min-width: 476px"
+                  value-format="yyyy-MM-dd HH:mm:ss"
+                  :default-time="['00:00:00','23:59:59']"
+                  :picker-options="pickerOptions"
+                />
+              </div>
+            </el-form>
+            <div v-if="DemandStatus === true" style="color:#409EFF; cursor: pointer; margin-top: 15px;" @click="DemandSta"><i class="el-icon-circle-plus-outline" /> 添加需求状态停留时长条件</div>
+            <el-divider v-if="DemandStatus === false"> 且 </el-divider>
+            <div v-if="DemandStatus === false" style=" margin-top: 15px;">
+              <div class="DemandStatus">
+                <i style="color:#409EFF; cursor: pointer; margin-right: 5px;" class="el-icon-remove-outline" @click="DemandSta" />
+                <span> 需求状态包含:</span>
+              </div>
+              <el-checkbox-group v-model="searchForm.containStatus" class="allCheckbox">
+                <el-checkbox v-for="item in requiredStatus" :key="item.value" :value="item.value">{{ item.label }}</el-checkbox>
+              </el-checkbox-group>
+              <div class="DemandStatus">状态停留时长:</div>
+              <el-select v-model="searchForm.comparisonOperator" size="small" style="width: 80px; margin: 20px 20px 0 79px;" clearable filterable placeholder="请选择">
+                <el-option v-for="item in formula" :key="item.code" :label="item.msg" :value="item.msg" />
               </el-select>
-            </div>
-            <div class="Layout">
-              <div class="queryName marginLeft">需求提出人</div>
-              <search-people :value.sync="searchForm.rqmtProposer" :clearable="true" :multiple="false" style="width:72% !important;" />
-            </div>
-          </el-form>
-          <el-form :model="searchForm" class="flex_start el-from-spacing">
-            <div class="Layout">
-              <div class="queryName">来自望岳</div>
-              <el-select v-model="searchForm.isFromDpm" size="small" clearable filterable placeholder="请选择">
-                <el-option v-for="item in isFromDpmList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select v-model="searchForm.days" size="small" style="width: 80px;" clearable filterable placeholder="请选择">
+                <el-option v-for="item in getArrayList()" :key="item.code" :label="item.msg" :value="item.code" />
               </el-select>
             </div>
-            <div class="Layout">
-              <div class="queryName" style="margin-left: 2%;">创建时间</div>
-              <el-date-picker
-                v-model="searchForm.date"
-                type="daterange"
-                align="right"
-                unlink-panels
-                range-separator="至"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                size="small"
-                value-format="yyyy-MM-dd HH:mm:ss"
-                :default-time="['00:00:00','23:59:59']"
-                :picker-options="pickerOptions"
-              />
+
+            <div align="right">
+              <el-button type="text" @click="showSaveSearch = true">保存筛选项</el-button>
+              <el-button type="primary" size="mini" @click="getTableData">筛 选</el-button>
+              <el-button size="mini" @click="reset">重 置</el-button>
             </div>
-          </el-form>
-          <div v-if="DemandStatus === true" style="color:#409EFF; cursor: pointer; margin-top: 15px;" @click="DemandSta"><i class="el-icon-circle-plus-outline" /> 添加需求状态停留时长条件</div>
-          <el-divider v-if="DemandStatus === false"> 且 </el-divider>
-          <div v-if="DemandStatus === false" style=" margin-top: 15px;">
-            <div class="DemandStatus">
-              <i style="color:#409EFF; cursor: pointer; margin-right: 5px;" class="el-icon-remove-outline" @click="DemandSta" />
-              <span> 需求状态包含:</span>
+          </div>
+        </div>
+        <div v-if="filterList.length && filterList.length > 0" class="filter">
+          <div class="filterWrap">
+            <div class="title">我的过滤器:</div>
+            <div class="itemBox">
+              <el-tag v-for="item in filterList" :key="item.id" class="item" @click="getFilterItem(item.id)">{{ item.name }}</el-tag>
             </div>
-            <el-checkbox-group v-model="searchForm.containStatus" class="allCheckbox">
-              <el-checkbox v-for="item in requiredStatus" :key="item.code" :label="item.code">{{ item.msg }}</el-checkbox>
-            </el-checkbox-group>
-            <div class="DemandStatus">状态停留时长:</div>
-            <el-select v-model="searchForm.comparisonOperator" size="small" style="width: 80px; margin: 20px 20px 0 79px;" clearable filterable placeholder="请选择">
-              <el-option v-for="item in formula" :key="item.code" :label="item.msg" :value="item.msg" />
-            </el-select>
-            <el-select v-model="searchForm.days" size="small" style="width: 80px;" clearable filterable placeholder="请选择">
-              <el-option v-for="item in getArrayList()" :key="item.code" :label="item.msg" :value="item.code" />
-            </el-select>
           </div>
-
-          <div align="right">
-            <el-button type="text" @click="showSaveSearch = true">保存筛选项</el-button>
-            <el-button type="primary" size="mini" @click="getTableData">筛 选</el-button>
-            <el-button size="mini" @click="reset">重 置</el-button>
+          <div class="btn">
+            <span @click.stop="showEditSearch = true">管理过滤器</span>
           </div>
         </div>
       </div>
-      <el-row v-if="filterList.length && filterList.length>0" type="flex" justify="space-between" class="filter">
-        <el-col :span="2">
-          <span>我的过滤器:</span>
-        </el-col>
-        <el-col :span="20" class="mine-filter">
-          <span v-for="item in filterList" :key="item.id" class="filter-item" @click="getFilterItem(item.id)">
-            <el-tooltip class="item" effect="dark" :content="item.name" placement="bottom">
-              <span>{{ item.name }}</span>
-            </el-tooltip>
-          </span>
-        </el-col>
-        <el-col :span="2" align="end">
-          <span @click.stop="showEditSearch = true">管理过滤器</span>
-        </el-col>
-      </el-row>
     </div>
     <div class="stylus-content">
+      <div v-if="nowTab === 'charts'" class="subtitle">{{ tableTitle }}</div>
       <el-table
         v-loading="loading"
         :data="tableData"
         style="width: 100%"
         highlight-current-row
-        :header-cell-style="{ 'color':'rgba(74,74,74,1)','font-size':'14px','font-weight':'500' }"
+        :header-cell-style="{ 'background': nowTab === 'charts' ? '#F7F7F7' : '#fff', 'color':'rgba(74,74,74,1)','font-size':'14px','font-weight':'500' }"
         :cell-style="{ 'font-size':'14px','color':'rgba(102,102,102,1)' }"
         size="small"
         show-overflow-tooltip="true"
       >
-        <el-table-column label="优先级" fixed min-width="90" sortable align="left">
+        <el-table-column label="优先级" prop="priority" fixed min-width="90" sortable align="left">
           <template v-slot="scope">
             <div class="div_priority" :style="{background: priorityColors[scope.row.priority % priorityColors.length]}">{{ 'P'+scope.row.priority }}</div>
           </template>
@@ -169,7 +219,25 @@
             <span class="stylus-hover" @click="getToRequirementDetails(scope.row.id)">{{ scope.row.name }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="状态" prop="statusName" min-width="150" align="center" />
+        <el-table-column label="状态" prop="statusName" width="150" align="center">
+          <template slot-scope="scope">
+            <el-select
+              v-if="nowTab === 'charts'"
+              v-model="scope.row.status"
+              :class="{
+                'status0':scope.row.status===0,
+                'status1':scope.row.status > 0 && scope.row.status <100,
+                'status2':scope.row.status===100
+              }"
+              :size="size"
+              placeholder=""
+              @change="(e) => statusChange(e, scope.row.id)"
+            >
+              <el-option v-for="o in scope.row.availableStatusList" :key="o.code" :label="o.name" :value="o.code" />
+            </el-select>
+            <span v-else>{{ scope.row.statusName }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="sourceTypeName" label="需求来源" min-width="100" show-overflow-tooltip align="center" />
         <el-table-column label="PM" min-width="100" show-overflow-tooltip align="center">
           <template v-if="scope.row.pmMemberInfoResponse" slot-scope="scope">
@@ -220,10 +288,28 @@
     <normal-dialog :show-footer="false" :show-dialog="showEditSearch" :title="'管理过滤器'" :width="'65%'" @cancel="showEditSearch=false">
       <filter-list :show-filter="showEditSearch" @deleteFilter="deleteFilter" />
     </normal-dialog>
+    <filterModal
+      :show-dialog="showChartModal"
+      title="筛选项"
+      @reset="reset"
+      @cancel="showChartModal = false"
+      @confirm="filterModalConfirm"
+    >
+      <div>
+        <chartSearchForm
+          :data="chartSearchFormRenderData"
+          :loading="loading"
+          :styles="{ marginBottom: '15px', width: '380px' }"
+          @change="chartSearchFormChange"
+          @getOption="(key, q, utilName) => remoteMethod(q)"
+        />
+      </div>
+    </filterModal>
   </div>
 </template>
 
 <script>
+const _ = require('lodash')
 import { EncryptId } from '@/utils/crypto-js.js'
 import { mapGetters } from 'vuex'
 import {
@@ -234,13 +320,21 @@ import {
   settingQueryBizRqmtOrntList,
   filterCreateFilter,
   filtergetFilterList,
-  filterGetFilter
+  filterGetFilter,
+  getPerson,
+  getChartListData,
+  getChartData,
+  updateStatus
 } from '@/api/requirement.js'
 import { deepClone } from '@/utils/global'
 import RequirementCreate from './create'
+import mainTitle from '@/components/mainTitle'
+import chartView from '@/components/chartView'
+import filterModal from '@/components/filterModal'
+import chartSearchFormData from '../renderData/chartSearchForm'
+import chartSearchForm from '@/components/searchHeader/searchForm'
 import filterList from '@/views/projectManage/components/filterList'
 import extraUrgent from '@/assets/extraUrgent.png'
-import searchPeople from '@/components/select/searchPeople'
 import normalDialog from '@/components/dialog/normalDialog'
 import '@/views/projectManage/publicCss/index.css'
 import '@/styles/PublicStyle/index.scss'
@@ -248,12 +342,16 @@ import '@/styles/PublicStyle/index.scss'
 export default {
   components: {
     RequirementCreate,
-    searchPeople,
     normalDialog,
-    filterList
+    filterList,
+    mainTitle,
+    chartView,
+    filterModal,
+    chartSearchForm
   },
   data() {
     return {
+      size: 'small',
       pickerOptions: {
         shortcuts: [{
           text: '最近一周',
@@ -281,10 +379,10 @@ export default {
           }
         }]
       },
-      newTabOpen: true, // 是否新的tab页打开
+      // newTabOpen: true, // 是否新的tab页打开
       DemandStatus: true, // 筛选需求时长
       extraUrgent: extraUrgent,
-      isFromDpmList: [{ id: true, name: '是' }, { id: false, name: '否' }],
+      isFromDpmList: [{ value: true, label: '是' }, { value: false, label: '否' }],
       priorityColors: ['#F56C6C', '#FF8952', '#F5E300', '#7ED321', '#61D3B8', '#69B3FF', '#BDBDBD'],
       formula: [{ code: 0, msg: '>=' }, { code: 1, msg: '<=' }, { code: 2, msg: '>' }, { code: 3, msg: '<' }],
       // currentRow: null,
@@ -305,7 +403,6 @@ export default {
         bizType: [],
         priority: []
       },
-      requirementName: '',
       goodName: '更多筛选',
       DetailedScreening: false,
       searchFormRules: { name: [
@@ -318,6 +415,7 @@ export default {
       requiredStatus: [], // 需求状态option
       demandDirection: [], // 需求方向option
       searchForm: {
+        viewType: '0',
         containStatus: [] // 包含
       }, // 查询字段
       pageSize: 15,
@@ -326,7 +424,20 @@ export default {
       tableData: [], // 需求tableList
       createDialogVisible: false,
       total: 0,
-      data: ''
+      data: '',
+      options: [],
+      nowTab: 'list',
+      chartData: {},
+      typeOptionList: [
+        { value: '0', label: '需求状态' },
+        { value: '1', label: '需求等级' },
+        { value: '2', label: '需求类型' },
+        { value: '3', label: 'pm' },
+        { value: '4', label: '跟版客户端' }
+      ],
+      showChartModal: false,
+      tableTitle: '',
+      chartSearchFormRenderData: _.cloneDeep(chartSearchFormData)
     }
   },
   computed: {
@@ -346,25 +457,49 @@ export default {
   created() {
     this.$store.state.data.status = true
   },
+  mounted() {
+    this.updateChartSlectOption('isFromDpm', this.isFromDpmList)
+  },
   destroyed() {
     this.$store.state.data.status = false
   },
   methods: {
+    // 修改状态
+    async statusChange(e, id) {
+      console.log(e)
+      const res = await updateStatus({ status: e, id })
+      if (res.code === 200) {
+        this.get_charts()
+      }
+    },
+    filterModalConfirm() {
+      this.showChartModal = false
+      this.get_charts()
+    },
     logHandle(d) {
       window.log({ c: 'requirement', d })
     },
-    getTableData() { // 查询
+    changeTab(e) {
+      this.nowTab = e
+      if (this.nowTab === 'charts') {
+        this.get_charts()
+      } else {
+        this.chartData = {}
+        this.getTableData()
+      }
+    },
+    get_charts() {
+      this.updateChartSearchFormValue()
+      this.getSearchFormHandle()
+      this.get_chartList()
+    },
+    getSearchFormHandle() {
       if (this.bizId === -1) return
       for (const key in this.searchForm) { // 接口不接受空值的处理
         if (this.searchForm[key] === '' || this.searchForm[key] === null) {
           delete this.searchForm[key]
         }
       }
-      if (this.requirementName) { // 判断需求名称
-        this.searchForm.name = this.requirementName
-      } else {
-        this.searchForm.name = ''
-      }
       if (this.searchForm.date) {
         this.searchForm.createStartTime = this.searchForm.date[0]
         this.searchForm.createEndTime = this.searchForm.date[1]
@@ -377,25 +512,91 @@ export default {
 
       this.searchForm.pageSize = this.pageSize
       this.searchForm.curIndex = this.curIndex
+    },
+    getTableData() { // 查询
+      // if (this.bizId === -1) return
+      // for (const key in this.searchForm) { // 接口不接受空值的处理
+      //   if (this.searchForm[key] === '' || this.searchForm[key] === null) {
+      //     delete this.searchForm[key]
+      //   }
+      // }
+      // if (this.searchForm.date) {
+      //   this.searchForm.createStartTime = this.searchForm.date[0]
+      //   this.searchForm.createEndTime = this.searchForm.date[1]
+      // } else {
+      //   delete this.searchForm.createStartTime
+      //   delete this.searchForm.createEndTime
+      // }
+      // this.searchForm.bizId = this.bizId
+      // this.loading = true
 
+      // this.searchForm.pageSize = this.pageSize
+      // this.searchForm.curIndex = this.curIndex
+      this.getSearchFormHandle()
       getRequirement(this.searchForm).then(res => {
         this.tableData = res.data.list
         this.total = res.data.total
         this.loading = false
       })
     },
+    async get_chartList() {
+      this.loading = true
+      const res = await getChartData(this.searchForm)
+      this.chartData = res.data
+      this.get_chartListDetial(res.data.data[0].code)
+    },
+    async get_chartListDetial(code) {
+      if (code) {
+        this.searchForm.code = code
+      }
+      const dataList = await getChartListData(this.searchForm)
+      this.tableData = dataList.data.list
+      this.total = dataList.total
+      this.tableTitle = dataList.data.title
+      this.loading = false
+    },
     async showRequirementEnum() {
       const res = await showRequirementEnum()
       if (res.code === 200) {
+        // 类型
+        res.data.type.map(t => {
+          t.value = t.code
+          t.label = t.msg
+        })
+        // 来源
+        res.data.sourceType.map(t => {
+          t.value = t.code
+          t.label = t.msg
+        })
+        // 优先级
+        res.data.priority.map(t => {
+          t.value = t.code
+          t.label = t.msg
+        })
         this.searchInfo = res.data
+        this.updateChartSlectOption('type', res.data.type)
+        this.updateChartSlectOption('sourceTypeList', res.data.sourceType)
+        this.updateChartSlectOption('priorityList', res.data.priority)
       }
       const res1 = await projectListProject({ bizId: this.bizId })
       if (res1.code === 200) {
-        this.AttributionItems = res1.data
+        const AttributionItems = res1.data.map(t => ({
+          ...t,
+          label: t.name,
+          value: t.id
+        }))
+        this.AttributionItems = AttributionItems
+        this.updateChartSlectOption('belongingProject', AttributionItems)
       }
       const res2 = await configShowRequireStatusEnum(this.bizId)
       if (res2.code === 200) {
-        this.requiredStatus = res2.data.requirementStatus
+        const requiredStatus = res2.data.requirementStatus.map(t => ({
+          ...t,
+          label: t.msg,
+          value: t.code
+        }))
+        this.requiredStatus = requiredStatus
+        this.updateChartSlectOption('statusList', requiredStatus)
       }
       const res3 = await settingQueryBizRqmtOrntList(this.bizId)
       if (res3.code === 200) { // 需求方向
@@ -495,7 +696,7 @@ export default {
         // }
         // this.getClient(filter.appId)
         Object.assign(this.searchForm, filter)
-        this.requirementName = filter.name
+        // this.requirementName = filter.name
         this.curIndex = 1
         this.getTableData()
       }
@@ -516,42 +717,110 @@ export default {
       this.getFilterList()
     },
     reset() {
-      this.$set(this.searchForm, 'id', '')
-      this.$set(this.searchForm, 'pm', '')
-      this.$set(this.searchForm, 'priorityList', [])
-      this.$set(this.searchForm, 'belongingProject', '')
-      this.$set(this.searchForm, 'sourceType', '')
-      this.$set(this.searchForm, 'creator', '')
-      this.$set(this.searchForm, 'type', '')
-      this.$set(this.searchForm, 'containStatus', [])
-      this.$set(this.searchForm, 'comparisonOperator', '')
-      this.$set(this.searchForm, 'days', '')
-      this.$set(this.searchForm, 'rqmtProposer', '')
-      this.$set(this.searchForm, 'sourceTypeList', [])
-      this.$set(this.searchForm, 'isFromDpm', '')
-      this.$set(this.searchForm, 'date', [])
-      this.$message({
-        message: '已重置',
-        type: 'success',
-        duration: 1000,
-        offset: 150
-      })
-      this.getTableData()
+      // this.$set(this.searchForm, 'id', '')
+      // this.$set(this.searchForm, 'pm', '')
+      // this.$set(this.searchForm, 'priorityList', [])
+      // this.$set(this.searchForm, 'belongingProject', '')
+      // this.$set(this.searchForm, 'sourceType', '')
+      // this.$set(this.searchForm, 'creator', '')
+      // this.$set(this.searchForm, 'type', '')
+      // this.$set(this.searchForm, 'containStatus', [])
+      // this.$set(this.searchForm, 'comparisonOperator', '')
+      // this.$set(this.searchForm, 'days', '')
+      // this.$set(this.searchForm, 'rqmtProposer', '')
+      // this.$set(this.searchForm, 'sourceTypeList', [])
+      // this.$set(this.searchForm, 'isFromDpm', '')
+      // this.$set(this.searchForm, 'date', [])
+      // this.$message({
+      //   message: '已重置',
+      //   type: 'success',
+      //   duration: 1000,
+      //   offset: 150
+      // })
+      // 重置
+      this.searchForm = {
+        ...this.searchForm,
+        id: '',
+        pm: '',
+        priorityList: [],
+        belongingProject: '',
+        sourceType: '',
+        creator: '',
+        type: '',
+        containStatus: [],
+        comparisonOperator: '',
+        days: '',
+        rqmtProposer: '',
+        sourceTypeList: [],
+        isFromDpm: '',
+        date: []
+      }
+      if (this.nowTab === 'charts') {
+        this.searchForm = { ...this.searchForm, rqmtOrntIds: [], name: '', statusList: [] }
+      }
+      if (this.nowTab === 'charts') {
+        this.get_charts()
+      } else {
+        this.getTableData()
+      }
+    },
+    async remoteMethod(query) {
+      // 人员查询
+      if (query !== '') {
+        // this.loading = true
+        const res = await getPerson({ memberIDAP: query })
+        const obj = {}
+        this.options = res.data.reduce((cur, next) => {
+          obj[next.idap] ? '' : obj[next.idap] = true && cur.push(next)
+          return cur
+        }, [])
+        // this.loading = false
+      } else {
+        this.options = []
+      }
+      this.updateChartSlectOption('pm', this.options)
+      this.updateChartSlectOption('rqmtProposer', this.options)
     },
     getToRequirementDetails(id) { // table点击跳转
       const bizId_id = EncryptId(`${this.bizId}_${id}`)
-      if (this.newTabOpen) {
+      if (localStorage.getItem('openPageHandle') === 'blank') {
         const newTab = this.$router.resolve({ name: '需求详情', query: { bizId_id: bizId_id }})
         window.open(newTab.href, '_blank')
       } else {
         this.$router.push({ name: '需求详情', query: { bizId_id: bizId_id }})
       }
+    },
+    chartSearchFormChange(key, value) {
+      console.log(key, value, this.chartSearchFormRenderData)
+      this.searchForm[key] = value
+    },
+    updateChartSlectOption(key, option) {
+      this.chartSearchFormRenderData.map(t => {
+        if (t.key === key) {
+          t.option = option
+        }
+      })
+    },
+    updateChartSearchFormValue() {
+      this.chartSearchFormRenderData.map(t => {
+        t.value = this.searchForm[t.key]
+      })
+      console.log(this.searchForm, this.chartSearchFormRenderData)
     }
   }
 }
 </script>
 
 <style scoped lang="scss">
+.search_box {
+  .item {
+    width: 270px;
+    margin-right: 15px;
+    .queryName {
+      min-width: 80px;
+    }
+  }
+}
 .new-tab-open {
   position: absolute;
   left: 120px;
@@ -613,6 +882,13 @@ export default {
   background: rgba(245,108,108,0.17);
   color: rgba(245,108,108,1);
 }
+.subtitle {
+  color: #333;
+  font-size: 16px;
+  background: #fff;
+  font-weight: 700;
+  padding: 16px 8px;
+}
 </style>
 
 <style>
@@ -646,26 +922,60 @@ export default {
 
 </style>
 <style scoped lang="scss">
+@mixin setStatus($color) {
+  input {
+    color:$color;
+    border: 1px solid $color;
+  }
+  /deep/.el-select__caret{
+    color:$color;
+  }
+  /deep/.el-input__inner{
+    color:$color;
+    border-color: $color;
+  }
+  /deep/.el-input__inner:focus {
+    border-color: $color;
+  }
+}
+.status0 {
+	@include setStatus(#409EFF)
+}
+.status1{
+	@include setStatus(#FF8952)
+}
+.status2 {
+	@include setStatus(#7ED321)
+}
 .stylus-head {
   position: relative;
 }
 .filter {
-  font-size: 14px;
-  width: 100%;
-  padding: 15px 11px 0px 15px;
-  color: #606266;
-  cursor: pointer;
-  .mine-filter {
-    .filter-item {
-      display: inline-block;
-      width: 15%;
-      color: #409EFF;
-      margin-right: 15px;
-      overflow: hidden;
-      text-overflow:ellipsis;
-      white-space: nowrap;
-      // margin-bottom: 5px;
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  margin-top: 15px;
+  .filterWrap {
+    display: flex;
+    align-items: baseline;
+    .title {
+      width: 100px;
     }
+    .itemBox {
+      .item {
+        display: inline-block;
+        margin-right: 20px;
+        margin-bottom: 10px;
+        cursor: pointer;
+      }
+    }
+  }
+  .btn {
+    font-size: 14px;
+    color: #00A0FF;
+    cursor: pointer;
+    min-width: 80px;
+    text-align: center;
   }
 }
 </style>

+ 92 - 0
src/views/projectManage/requirement/renderData/chartSearchForm.js

@@ -0,0 +1,92 @@
+const data = [
+  {
+    name: '需求名称',
+    key: 'name',
+    value: '',
+    placeholder: '请输入标题或ID或望岳ID',
+    type: 'input'
+  },
+  {
+    name: '需求状态',
+    key: 'statusList',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: true,
+    value: [],
+    option: [] // label===msg  value ===code
+  },
+  {
+    name: '所属项目',
+    key: 'belongingProject',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: [] // label===name  value ===id
+  },
+  {
+    name: 'PM',
+    key: 'pm',
+    type: 'remoteSelect',
+    multiple: false,
+    hasSlot: true,
+    utilName: 'getPerson',
+    placeholder: '请输入姓名或邮箱前缀',
+    value: '',
+    option: []
+  },
+  {
+    name: '需求类型',
+    key: 'type',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: [] // label===name  value ===id
+  },
+  {
+    name: '需求来源',
+    key: 'sourceTypeList',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: true,
+    value: [],
+    option: []
+  },
+  {
+    name: '优先级',
+    key: 'priorityList',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: true,
+    value: [],
+    option: [] // label===msg  value ===code
+  },
+  {
+    name: '需求提出人',
+    key: 'rqmtProposer',
+    type: 'remoteSelect',
+    multiple: false,
+    hasSlot: true,
+    utilName: 'getPerson',
+    placeholder: '请输入姓名或邮箱前缀',
+    value: '',
+    option: []
+  },
+  {
+    name: '来自望岳',
+    key: 'isFromDpm',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: null,
+    option: []
+  },
+  {
+    name: '创建日期',
+    key: 'date',
+    type: 'dateStartAndEnd',
+    value: []
+  }
+]
+export default data

+ 92 - 0
src/views/projectManage/taskList/renderData/chartSearchForm.js

@@ -0,0 +1,92 @@
+const data = [
+  {
+    name: '任务名称',
+    key: 'name',
+    value: '',
+    placeholder: '请输入标题或ID或望岳ID',
+    type: 'input'
+  },
+  {
+    name: '状态',
+    key: 'statusList',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: true,
+    value: '',
+    option: [] // label===msg  value ===code
+  },
+  {
+    name: '所属项目',
+    key: 'projectId',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: [] // label===name  value ===id
+  },
+  {
+    name: '所属需求',
+    key: 'requireId',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: [] // label===name  value ===id
+  },
+  {
+    name: '优先级',
+    key: 'priority',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: []
+  },
+  {
+    name: '负责人',
+    key: 'PersonInCharge',
+    type: 'remoteSelect',
+    multiple: false,
+    hasSlot: true,
+    utilName: 'getPerson',
+    placeholder: '请输入姓名或邮箱前缀',
+    value: '',
+    option: []
+  },
+  {
+    name: '健康状态',
+    key: 'stage',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: [] // label===msg  value ===code
+  },
+  {
+    name: '创建人',
+    key: 'creater',
+    type: 'remoteSelect',
+    multiple: false,
+    hasSlot: true,
+    utilName: 'getPerson',
+    placeholder: '请输入姓名或邮箱前缀',
+    value: '',
+    option: []
+  },
+  {
+    name: '来自望岳',
+    key: 'isFromDpm',
+    placeholder: '请选择',
+    type: 'select',
+    multiple: false,
+    value: '',
+    option: []
+  },
+  {
+    name: '创建日期',
+    key: 'date',
+    type: 'dateStartAndEnd',
+    value: []
+  }
+]
+export default data

+ 535 - 179
src/views/projectManage/taskList/taskIndex.vue

@@ -1,163 +1,189 @@
 <template>
   <div class="bgborder" style="background-color:#F2F3F6;min-height:calc(100vh - 80px);padding:0 10px 10px 10px">
     <div class="stylus-head">
-      <div class="stylus-title">
-        <span style="font-size: 22px;letter-spacing: 1px;font-weight: 600;color: #333B4A;padding-left: 15px">任务</span>
-        <div class="new-tab-open">
-          <el-switch
-            v-model="newTabOpen"
-            active-text="新标签页跳转"
-            @change="logHandle('switchJumpOpen')"
-          />
-        </div>
-        <div>
-          <el-button
-            type="primary"
-            size="mini"
-            @click="open_created"
-          >新建任务</el-button>
-        </div>
-      </div>
-      <el-divider style="color: #EEF0F5;" />
-      <div class="Layout" style="padding: 5px 0 0 15px">
-        <div>
-          <el-form :model="form_task" class="Layout">
-            <div class="Layout_flex_end">
-              <div class="queryName">任务名称</div>
-              <el-input v-model="form_task.name" size="small" clearable style="width:72% !important;" placeholder="请输入标题或ID或望岳ID" @change="get_taskList()" />
-            </div>
-            <div class="Layout">
-              <div class="queryName marginLeft">负责人</div>
-              <el-select
-                v-model="form_task.PersonInCharge"
-                clearable
-                filterable
-                remote
-                placeholder="请输入姓名或邮箱前缀"
-                :remote-method="remoteMethod"
-                :loading="loading"
-                size="small"
-                @change="get_taskList()"
-              >
-                <el-option v-for="item in options" :key="item.idap" :label="item.name" :value="test2(item, 0)">
-                  <div class="flex_start">
-                    <div class="deptName">{{ item.deptName }}</div>
-                    <div style="min-width:80px">{{ item.name }}</div>
-                    <div class="deptName">{{ item.idap }}</div>
-                  </div>
-                </el-option>
-              </el-select>
-            </div>
+      <mainTitle
+        title="任务"
+        btn-text="新建任务"
+        :tab-show="true"
+        @btn-handle="open_created"
+        @change-tab="changeTab"
+      />
+      <div v-if="nowTab === 'charts'" class="chartView">
+        <chartView
+          :data="chartData"
+          :type-option-list="typeOptionList"
+          :chart-search-data="form_task"
+          @search="get_charts()"
+          @changeList="(code) => get_chartListDetial(code)"
+        >
+          <div slot="searchBox">
             <div class="Layout">
-              <div class="queryName marginLeft">优先级</div>
-              <el-select v-model="form_task.priority" size="small" clearable filterable placeholder="请选择" @change="get_taskList()">
-                <el-option v-for="item in arr_priority" :key="item.value" :label="item.name" :value="item.value" />
-              </el-select>
-            </div>
-          </el-form>
-        </div>
-        <span class="screen" @click="showSelect">{{ goodName }}</span>
-      </div>
-      <div v-show="DetailedScreening" class="stylus-more">
-        <div>
-          <div class="Layout">
-            <el-form :model="form_task" class="flex_start">
               <div class="Layout">
-                <div class="queryName">所属项目</div>
-                <el-select v-model="form_task.projectId" size="small" clearable filterable placeholder="请选择">
-                  <el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id" />
-                </el-select>
-              </div>
-              <div class="Layout marginLeft">
-                <div class="queryName">所属需求</div>
-                <el-select v-model="form_task.requireId" size="small" clearable filterable placeholder="请选择">
-                  <el-option v-for="item in demandList" :key="item.id" :label="item.name" :value="item.id" />
-                </el-select>
+                <div class="chartSearchTitle">模块</div>
+                <el-cascader v-model="form_task.moduleIds" size="small" clearable collapse-tags :props="props" :options="business_platform_Modular" placeholder="请选择" style="width:77% !important;" @change="get_charts()" />
               </div>
-              <div class="Layout marginLeft">
-                <div class="queryName">来自望岳</div>
-                <el-select v-model="form_task.isFromDpm" size="small" clearable filterable placeholder="请选择">
-                  <el-option v-for="item in isFromDpmList" :key="item.id" :label="item.name" :value="item.id" />
-                </el-select>
-              </div>
-            </el-form>
+              <span class="screen" style="text-align:right; width: auto" @click="showChartModal = true">更多筛选</span>
+            </div>
           </div>
-          <div class="Layout" style="margin: 15px 0;">
-            <el-form :model="form_task" class="flex_start">
-              <div class="Layout">
-                <div class="queryName">模块</div>
-                <el-cascader v-model="form_task.moduleIds" size="small" clearable collapse-tags :props="props" :options="business_platform_Modular" placeholder="请选择" style="width:77% !important;" />
+        </chartView>
+      </div>
+      <div v-if="nowTab === 'list'" class="search_box">
+        <div class="Layout" style="padding: 5px 0 0 15px">
+          <div>
+            <el-form :model="form_task" class="Layout">
+              <div class="Layout_flex_end item">
+                <div class="queryName">任务名称</div>
+                <el-input v-model="form_task.name" size="small" clearable class="input" placeholder="请输入标题或ID或望岳ID" @change="get_taskList()" />
               </div>
-              <div class="Layout marginLeft">
+              <div class="Layout item">
                 <div class="queryName">状态</div>
-                <el-select v-model="form_task.statusList" size="small" multiple clearable filterable placeholder="请选择">
-                  <el-option v-for="item in daStatus" :key="item.code" :label="item.msg" :value="item.code" />
+                <el-select v-model="form_task.statusList" size="small" class="input" multiple clearable filterable placeholder="请选择" @change="get_taskList()">
+                  <el-option v-for="item in daStatus" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
               </div>
-              <div class="Layout marginLeft">
-                <div class="queryName">健康状态</div>
-                <el-select v-model="form_task.stage" size="small" clearable filterable placeholder="请选择">
-                  <el-option v-for="item in healthStage" :key="item.code" :label="item.msg" :value="item.code" />
-                </el-select>
+              <div class="Layout item">
+                <div class="queryName">模块</div>
+                <el-cascader v-model="form_task.moduleIds" size="small" class="input" clearable collapse-tags :props="props" :options="business_platform_Modular" placeholder="请选择" @change="get_taskList()" />
               </div>
             </el-form>
           </div>
-          <div class="Layout" style="margin: 15px 0;">
-            <el-form :model="form_task" class="flex_start">
-              <div class="Layout">
-                <div class="queryName" style="width:86px;">创建人</div>
-                <el-select
-                  v-model="form_task.creater"
-                  clearable
-                  filterable
-                  remote
-                  placeholder="请输入姓名或邮箱前缀"
-                  :remote-method="remoteMethod"
-                  :loading="loading"
-                  size="small"
-                  style="width: 82%;"
-                >
-                  <el-option v-for="item in options" :key="item.idap" :label="item.name" :value="test2(item, 0)">
-                    <div class="flex_start">
-                      <div class="deptName">{{ item.deptName }}</div>
-                      <div style="min-width:80px">{{ item.name }}</div>
-                      <div class="deptName">{{ item.idap }}</div>
-                    </div>
-                  </el-option>
-                </el-select>
-              </div>
-              <div class="Layout marginLeft">
-                <div class="queryName">创建日期</div>
-                <el-date-picker
-                  v-model="form_task.date"
-                  type="daterange"
-                  align="right"
-                  unlink-panels
-                  range-separator="至"
-                  start-placeholder="开始日期"
-                  end-placeholder="结束日期"
-                  size="small"
-                  value-format="yyyy-MM-dd HH:mm:ss"
-                  :default-time="['00:00:00','23:59:59']"
-                  :picker-options="pickerOptions"
-                />
-              </div>
-            </el-form>
+          <span class="screen" @click="showSelect">{{ goodName }}</span>
+        </div>
+        <div v-show="DetailedScreening" class="stylus-more">
+          <div>
+            <div class="Layout">
+              <el-form :model="form_task" class="flex_start">
+                <div class="Layout item">
+                  <div class="queryName">所属项目</div>
+                  <el-select v-model="form_task.projectId" size="small" class="input" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in projectList" :key="item.value" :label="item.label" :value="item.value" />
+                  </el-select>
+                </div>
+                <div class="Layout item">
+                  <div class="queryName">所属需求</div>
+                  <el-select v-model="form_task.requireId" size="small" class="input" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in demandList" :key="item.value" :label="item.label" :value="item.value" />
+                  </el-select>
+                </div>
+                <div class="Layout item">
+                  <div class="queryName">来自望岳</div>
+                  <el-select v-model="form_task.isFromDpm" size="small" class="input" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in isFromDpmList" :key="item.value" :label="item.label" :value="item.value" />
+                  </el-select>
+                </div>
+              </el-form>
+            </div>
+            <div class="Layout" style="margin: 15px 0;">
+              <el-form :model="form_task" class="flex_start">
+                <div class="Layout item">
+                  <div class="queryName">优先级</div>
+                  <el-select v-model="form_task.priority" size="small" class="input" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in arr_priority" :key="item.value" :label="item.label" :value="item.value" />
+                  </el-select>
+                </div>
+                <div class="Layout item">
+                  <div class="queryName">负责人</div>
+                  <el-select
+                    v-model="form_task.PersonInCharge"
+                    class="input"
+                    clearable
+                    filterable
+                    remote
+                    placeholder="请输入姓名或邮箱前缀"
+                    :remote-method="remoteMethod"
+                    :loading="loading"
+                    size="small"
+                  >
+                    <el-option v-for="item in options" :key="item.idap" :label="item.name" :value="test2(item, 0)">
+                      <div class="flex_start">
+                        <div class="deptName">{{ item.deptName }}</div>
+                        <div style="min-width:80px">{{ item.name }}</div>
+                        <div class="deptName">{{ item.idap }}</div>
+                      </div>
+                    </el-option>
+                  </el-select>
+                </div>
+                <div class="Layout item">
+                  <div class="queryName">健康状态</div>
+                  <el-select v-model="form_task.stage" size="small" class="input" clearable filterable placeholder="请选择">
+                    <el-option v-for="item in healthStage" :key="item.value" :label="item.label" :value="item.value" />
+                  </el-select>
+                </div>
+              </el-form>
+            </div>
+            <div class="Layout" style="margin: 15px 0;">
+              <el-form :model="form_task" class="flex_start">
+                <div class="Layout item">
+                  <div class="queryName" style="width:86px;">创建人</div>
+                  <el-select
+                    v-model="form_task.creater"
+                    class="input"
+                    clearable
+                    filterable
+                    remote
+                    placeholder="请输入姓名或邮箱前缀"
+                    :remote-method="remoteMethod"
+                    :loading="loading"
+                    size="small"
+                    style="width: 82%;"
+                  >
+                    <el-option v-for="item in options" :key="item.idap" :label="item.name" :value="test2(item, 0)">
+                      <div class="flex_start">
+                        <div class="deptName">{{ item.deptName }}</div>
+                        <div style="min-width:80px">{{ item.name }}</div>
+                        <div class="deptName">{{ item.idap }}</div>
+                      </div>
+                    </el-option>
+                  </el-select>
+                </div>
+                <div class="Layout item">
+                  <div class="queryName">创建日期</div>
+                  <el-date-picker
+                    v-model="form_task.date"
+                    type="daterange"
+                    align="right"
+                    unlink-panels
+                    range-separator="至"
+                    start-placeholder="开始日期"
+                    end-placeholder="结束日期"
+                    size="small"
+                    class="input"
+                    style="min-width: 476px"
+                    value-format="yyyy-MM-dd HH:mm:ss"
+                    :default-time="['00:00:00','23:59:59']"
+                    :picker-options="pickerOptions"
+                  />
+                </div>
+              </el-form>
+            </div>
+            <div align="right">
+              <el-button type="text" @click="showSaveSearch = true">保存筛选项</el-button>
+              <el-button type="primary" size="mini" @click="get_taskList(form_task)">筛 选</el-button>
+              <el-button size="mini" @click="query_Reset">重 置</el-button>
+            </div>
+          </div>
+        </div>
+        <div v-if="filterList.length && filterList.length > 0" class="filter">
+          <div class="filterWrap">
+            <div class="title">我的过滤器:</div>
+            <div class="itemBox">
+              <el-tag v-for="item in filterList" :key="item.id" class="item" @click="getFilterItem(item.id)">{{ item.name }}</el-tag>
+            </div>
           </div>
-          <div align="right">
-            <el-button type="primary" size="mini" @click="get_taskList(form_task)">筛 选</el-button>
-            <el-button size="mini" @click="query_Reset">重 置</el-button>
+          <div class="btn">
+            <span @click.stop="showEditSearch = true">管理过滤器</span>
           </div>
         </div>
       </div>
     </div>
     <div class="stylus-content">
+      <div v-if="nowTab === 'charts'" class="subtitle">{{ tableTitle }}</div>
       <el-table
         v-loading="table_loading"
         :data="task_table"
         style="width: 100%;"
         highlight-current-row
-        :header-cell-style="{ 'color':'rgba(74,74,74,1)','font-size':'14px','font-weight':'500' }"
+        :header-cell-style="{ 'background': nowTab === 'charts' ? '#F7F7F7' : '#fff', 'color':'rgba(74,74,74,1)','font-size':'14px','font-weight':'500' }"
         :cell-style="{ 'font-size':'14px','color':'rgba(102,102,102,1)' }"
         size="small"
         show-overflow-tooltip="true"
@@ -186,7 +212,18 @@
           </template>
         </el-table-column>
         <el-table-column label="状态" min-width="150" align="center" show-overflow-tooltip>
-          <template slot-scope="scope">{{ scope.row.statusString }}</template>
+          <template slot-scope="scope">
+            <el-select
+              v-if="nowTab === 'charts'"
+              v-model="scope.row.status"
+              :size="size"
+              placeholder=""
+              @change="(e) => statusChange(e, scope.row.id)"
+            >
+              <el-option v-for="o in scope.row.availableStatusList" :key="o.code" :label="o.name" :value="o.code" />
+            </el-select>
+            <span v-else>{{ scope.row.statusString }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="健康状态" width="150" align="center" show-overflow-tooltip>
           <template slot-scope="scope">{{ scope.row.stageString }}</template>
@@ -228,7 +265,7 @@
           background
           :current-page="currentPage"
           :page-sizes="[15,30,45,total]"
-          :page-size="15"
+          :page-size="pageSize"
           layout="total, sizes, prev, pager, next, jumper"
           :total="total"
           @size-change="handleSizeChange"
@@ -238,10 +275,40 @@
     </div>
     <!-- 弹窗 -->
     <openDialog v-if="dialog_open" ref="task_createdUpdata" />
+    <normal-dialog :show-dialog="showSaveSearch" :title="'保存筛选项'" :width="'35%'" @confirm="saveSearch('searchForm')" @cancel="showSaveSearch=false">
+      <div v-if="showSaveSearch" class="file-dialog">
+        <el-form ref="searchForm" :model="searchForm" :rules="searchFormRules" label-width="100px">
+          <el-form-item label="过滤器名称" prop="name">
+            <el-input v-model="searchForm.name" placeholder="不超过50个字符" />
+          </el-form-item>
+        </el-form>
+      </div>
+    </normal-dialog>
+    <normal-dialog :show-footer="false" :show-dialog="showEditSearch" :title="'管理过滤器'" :width="'65%'" @cancel="showEditSearch=false">
+      <filter-list :show-filter="showEditSearch" :filter-type="2" @deleteFilter="deleteFilter" />
+    </normal-dialog>
+    <filterModal
+      title="筛选项"
+      :show-dialog="showChartModal"
+      @reset="query_Reset"
+      @cancel="showChartModal = false"
+      @confirm="filterModalConfirm"
+    >
+      <div>
+        <chartSearchForm
+          :data="chartSearchFormRenderData"
+          :loading="loading"
+          :styles="{ marginBottom: '15px', width: '380px' }"
+          @change="chartSearchFormChange"
+          @getOption="(key, q, utilName) => remoteMethod(q)"
+        />
+      </div>
+    </filterModal>
   </div>
 </template>
 
 <script>
+const _ = require('lodash')
 import { EncryptId } from '@/utils/crypto-js.js'
 import { mapGetters } from 'vuex'
 import {
@@ -250,18 +317,39 @@ import {
   memberQueryMemberInfoByIDAPorName,
   configShowRequirementVersionEnum,
   projectListProject,
-  configShowTaskStatusEnum
+  getFilterList,
+  configShowTaskStatusEnum,
+  createFilter,
+  filterGetFilter,
+  getChartListData,
+  getChartData,
+  updateStatus
 } from '@/api/taskIndex' // ajax
+import filterModal from '@/components/filterModal'
 import { settingQueryBizModuleList } from '@/api/defectManage'
 import openDialog from '@/views/projectManage/dialog_vue'
+// 过滤器
+import filterList from '@/views/projectManage/components/filterList'
+import normalDialog from '@/components/dialog/normalDialog'
+import mainTitle from '@/components/mainTitle'
+import chartView from '@/components/chartView'
+import chartSearchFormData from './renderData/chartSearchForm'
+import chartSearchForm from '@/components/searchHeader/searchForm'
 import '@/views/projectManage/publicCss/index.css'
 import '@/styles/PublicStyle/index.scss'
 export default {
   components: {
-    openDialog
+    openDialog,
+    filterList,
+    normalDialog,
+    mainTitle,
+    chartView,
+    filterModal,
+    chartSearchForm
   },
   data() {
     return {
+      size: 'small',
       pickerOptions: {
         shortcuts: [{
           text: '最近一周',
@@ -289,7 +377,6 @@ export default {
           }
         }]
       },
-      newTabOpen: true, // 是否新的tab页打开
       header_show: true,
       props: {
         value: 'id',
@@ -297,9 +384,9 @@ export default {
         children: 'childModules',
         multiple: true
       },
-      isFromDpmList: [{ id: true, name: '是' }, { id: false, name: '否' }],
+      isFromDpmList: [{ value: true, label: '是' }, { value: false, label: '否' }],
       priorityColors: ['#F56C6C', '#FF8952', '#F5E300', '#7ED321', '#61D3B8', '#69B3FF', '#BDBDBD'],
-      arr_priority: [{ value: 0, name: 'P0' }, { value: 1, name: 'P1' }, { value: 2, name: 'P2' }, { value: 3, name: 'P3' }],
+      arr_priority: [{ value: 0, label: 'P0' }, { value: 1, label: 'P1' }, { value: 2, label: 'P2' }, { value: 3, label: 'P3' }],
       dialog_open: false,
       curIndex: 1,
       pageSize: 15,
@@ -310,7 +397,9 @@ export default {
       list: [],
       userInformation: localStorage.getItem('username'),
       userNames: localStorage.getItem('realname'),
-      form_task: {},
+      form_task: {
+        viewType: '0'
+      },
       noTest: [], // 是否免测
       BusinessLine: [], // 业务线
       appClient: [], // 涉及业务线
@@ -330,7 +419,28 @@ export default {
       test: {},
       task_table: [],
       form: {},
-      arry: []
+      arry: [],
+      filterList: [],
+      showEditSearch: false, // 显示管理过滤器
+      searchForm: { name: null }, // 筛选项obj
+      searchFormRules: { name: [
+        { required: true, message: '请输入筛选项名称', trigger: 'blur' },
+        { min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
+      ] },
+      showSaveSearch: false, // 显示保存筛选项对话框
+      nowTab: 'list',
+      chartData: {},
+      typeOptionList: [
+        { value: '0', label: '任务状态' },
+        { value: '1', label: '任务等级' },
+        { value: '2', label: '开发负责人' },
+        { value: '3', label: '测试负责人' },
+        { value: '4', label: '跟版客户端' },
+        { value: '5', label: '直接归属' }
+      ],
+      showChartModal: false,
+      tableTitle: '',
+      chartSearchFormRenderData: _.cloneDeep(chartSearchFormData)
     }
   },
   computed: {
@@ -340,6 +450,7 @@ export default {
     bizId() {
       this.get_taskList()
       this.get_taskSelect()
+      this.getFilterList() // 筛选项保存
     }
   },
   created() {
@@ -351,15 +462,59 @@ export default {
   mounted() {
     this.$nextTick(() => {
       this.bugDataGet()
+      this.getFilterList() // 筛选项保存
     })
+    this.updateChartSlectOption('isFromDpm', this.isFromDpmList)
+    this.updateChartSlectOption('priority', this.arr_priority)
   },
   destroyed() {
     this.$store.state.data.status = false
   },
   methods: {
+    filterModalConfirm() {
+      this.showChartModal = false
+      this.get_charts()
+    },
     logHandle(d) {
       window.log({ c: 'task', d })
     },
+    changeTab(e) {
+      this.nowTab = e
+      if (this.nowTab === 'charts') {
+        this.get_charts()
+      } else {
+        this.chartData = {}
+        this.get_taskList()
+      }
+    },
+    async statusChange(e, id) {
+      console.log(e)
+      const res = await updateStatus({ status: e, id })
+      if (res.code === 200) {
+        this.get_charts()
+      }
+    },
+    get_charts() {
+      this.updateChartSearchFormValue()
+      this.form_taskHandle()
+      this.get_chartList()
+    },
+    async get_chartList() {
+      this.table_loading = true
+      const res = await getChartData(this.form_task)
+      this.chartData = res.data
+      this.get_chartListDetial(res.data.data[0].code)
+    },
+    async get_chartListDetial(code) {
+      if (code) {
+        this.form_task.code = code
+      }
+      const dataList = await getChartListData(this.form_task)
+      this.task_table = dataList.data.list
+      this.total = dataList.total
+      this.tableTitle = dataList.data.title
+      this.table_loading = false
+    },
     test2(item, e) {
       // 获取团队人员信息
       if (typeof this.test[item.idap] === 'undefined') {
@@ -368,7 +523,58 @@ export default {
       }
       return item.idap
     },
-    get_taskList(e) {
+    // 保存筛选项
+    saveSearch(formName) { // 保存筛选项
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.stratAndEnd = this.stratAndEnd ? this.stratAndEnd : []
+          this.form_task.createStartTime = this.stratAndEnd[0] || null
+          this.form_task.createEndTime = this.stratAndEnd[1] || null
+          const isExistName = this.filterList.some(item => {
+            return item.name === this.searchForm.name
+          })
+          if (isExistName) {
+            this.$message({ showClose: true, message: '筛选项名称重名', type: 'error' })
+          } else {
+            this.toSave()
+          }
+        } else {
+          this.$message({ showClose: true, message: '筛选项名称不能为空', type: 'error' })
+          return false
+        }
+      })
+    },
+    // 保存过滤器
+    async toSave() {
+      const saveObj = _.cloneDeep(this.form_task)
+      delete saveObj.curIndex
+      delete saveObj.pageSize
+      const res = await createFilter({
+        name: this.searchForm.name,
+        content: JSON.stringify(saveObj),
+        bizId: this.bizId,
+        filterType: 2
+      })
+      if (res.code === 200) {
+        this.$message({ showClose: true, message: '保存成功', type: 'success' })
+        this.showSaveSearch = false
+        this.getFilterList()
+        this.searchForm.name = null
+      }
+    },
+    async getFilterList() { // 获取过滤器列表
+      const params = {
+        bizId: this.bizId,
+        filterType: 2
+      }
+      const res = await getFilterList(params)
+      this.filterList = res.data
+    },
+    deleteFilter() {
+      this.$router.push({ path: this.$route.path })
+      this.getFilterList()
+    },
+    form_taskHandle() {
       if (this.bizId === -1) return
       // 查询
       if (this.isToOne) {
@@ -391,6 +597,31 @@ export default {
         delete this.form_task.createTimeBegin
         delete this.form_task.createTimeEnd
       }
+    },
+    get_taskList(e) {
+      // if (this.bizId === -1) return
+      // // 查询
+      // if (this.isToOne) {
+      //   this.curIndex = 1
+      //   this.currentPage = 1
+      // }
+      // this.table_loading = true
+      // this.form_task.bizId = this.bizId
+      // this.form_task.pageSize = this.pageSize
+      // this.form_task.curIndex = this.curIndex
+      // for (const key in this.form_task) { // 接口不接受空值的处理
+      //   if (this.form_task[key] === '') {
+      //     delete this.form_task[key]
+      //   }
+      // }
+      // if (this.form_task.date) {
+      //   this.form_task.createTimeBegin = this.form_task.date[0]
+      //   this.form_task.createTimeEnd = this.form_task.date[1]
+      // } else {
+      //   delete this.form_task.createTimeBegin
+      //   delete this.form_task.createTimeEnd
+      // }
+      this.form_taskHandle()
       taskList(this.form_task).then(res => {
         this.task_table = res.data
         this.total = res.total
@@ -398,27 +629,32 @@ export default {
       })
       configShowRequirementVersionEnum({ bizId: this.bizId }).then(res => {
         // 获取需求(查询)
-        this.demandList = res.data
+        const demandList = res.data.map(t => ({
+          ...t,
+          label: t.name,
+          value: t.id
+        }))
+        this.demandList = demandList
+        this.updateChartSlectOption('requireId', demandList)
       })
       this.isToOne = true
     },
-    remoteMethod(query) {
+    async remoteMethod(query) {
       // 人员查询
       if (query !== '') {
         this.loading = true
-        setTimeout(() => {
-          this.loading = false
-          memberQueryMemberInfoByIDAPorName({ memberIDAP: query }).then(res => {
-            const obj = {}
-            this.options = res.data.reduce((cur, next) => {
-              obj[next.idap] ? '' : obj[next.idap] = true && cur.push(next)
-              return cur
-            }, [])
-          })
-        }, 200)
+        const res = await memberQueryMemberInfoByIDAPorName({ memberIDAP: query })
+        const obj = {}
+        this.options = res.data.reduce((cur, next) => {
+          obj[next.idap] ? '' : obj[next.idap] = true && cur.push(next)
+          return cur
+        }, [])
+        this.loading = false
       } else {
         this.options = []
       }
+      this.updateChartSlectOption('PersonInCharge', this.options)
+      this.updateChartSlectOption('creater', this.options)
     },
     showSelect() {
       this.DetailedScreening = !this.DetailedScreening
@@ -443,7 +679,7 @@ export default {
     },
     link_task(id) {
       const bizId_id = EncryptId(`${this.bizId}_${id}`)
-      if (this.newTabOpen) {
+      if (localStorage.getItem('openPageHandle') === 'blank') {
         const newTab = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id }})
         window.open(newTab.href, '_blank')
       } else {
@@ -452,28 +688,46 @@ export default {
     },
     query_Reset() {
       // 重置
-      this.$set(this.form_task, 'bizId', '')
-      this.$set(this.form_task, 'status', '')
-      this.$set(this.form_task, 'stage', '')
-      this.$set(this.form_task, 'id', '')
-      this.$set(this.form_task, 'projectId', '')
-      this.$set(this.form_task, 'requireId', '')
-      this.$set(this.form_task, 'PersonInCharge', '')
-      this.$set(this.form_task, 'Participant', '')
-      this.$set(this.form_task, 'creater', '')
-      this.$set(this.form_task, 'isFromDpm', '')
-      this.$set(this.form_task, 'date', [])
-      this.$message({
-        message: '已重置',
-        type: 'success',
-        duration: 1000,
-        offset: 150
-      })
+      this.form_task = {
+        ...this.form_task,
+        bizId: '',
+        status: '',
+        stage: '',
+        id: '',
+        projectId: '',
+        requireId: '',
+        PersonInCharge: '',
+        Participant: '',
+        creater: '',
+        isFromDpm: '',
+        priority: '',
+        date: []
+      }
+      if (this.nowTab === 'charts') {
+        this.form_task = { ...this.form_task, moduleIds: [], name: '', statusList: [] }
+      }
+      this.updateChartSearchFormValue()
+      if (this.nowTab === 'charts') {
+        this.get_charts()
+      } else {
+        this.get_taskList()
+      }
+      // this.$message({
+      //   message: '已重置',
+      //   type: 'success',
+      //   duration: 1000,
+      //   offset: 150
+      // })
     },
     handleSizeChange(size) {
       //  分页
       this.pageSize = size
       this.isToOne = false
+      this.form_taskHandle()
+      if (this.nowTab === 'charts') {
+        this.get_chartListDetial()
+        return
+      }
       this.get_taskList(1)
     },
     handleCurrentChange(curIndex) {
@@ -481,6 +735,11 @@ export default {
       this.curIndex = curIndex
       this.currentPage = curIndex
       this.isToOne = false
+      this.form_taskHandle()
+      if (this.nowTab === 'charts') {
+        this.get_chartListDetial()
+        return
+      }
       this.get_taskList()
     },
     async get_taskSelect() {
@@ -488,18 +747,36 @@ export default {
       // 下拉菜单数据
       const res = await configShowTaskEnum()
       if (res.code === 200) {
-        this.healthStage = res.data.taskStage
+        const healthStage = res.data.taskStage.map(t => ({
+          ...t,
+          label: t.msg,
+          value: t.code
+        }))
+        this.healthStage = healthStage
+        this.updateChartSlectOption('stage', healthStage)
         this.noTest = res.data.noTest // 是否免测
         this.taskSource = res.data.taskSource // 归属需求
         this.appClient = res.data.appClient // 涉及客户端
       }
       const res1 = await configShowTaskStatusEnum(this.bizId)
       if (res1.code === 200) {
-        this.daStatus = res1.data.taskStatus
+        const daStatus = res1.data.taskStatus.map(t => ({
+          ...t,
+          label: t.msg,
+          value: t.code
+        }))
+        this.daStatus = daStatus
+        this.updateChartSlectOption('statusList', daStatus)
       }
       const res2 = await projectListProject({ bizId: this.bizId })
       if (res2.code === 200) {
-        this.projectList = res2.data
+        const projectList = res2.data.map(t => ({
+          ...t,
+          label: t.name,
+          value: t.id
+        }))
+        this.projectList = projectList
+        this.updateChartSlectOption('projectId', projectList)
       }
     },
     bugDataGet() { // 所属模块
@@ -516,11 +793,46 @@ export default {
         data[i].childModules && data[i].childModules.length < 1 ? delete data[i].childModules : this.getRequireData(data[i].childModules)
       }
       return data
+    },
+    async getFilterItem(filterId) { // 获取单个过滤器
+      const res = await filterGetFilter(filterId)
+      if (res.code === 200) {
+        const filter = JSON.parse(res.data.content)
+        Object.assign(this.form_task, filter)
+        this.curIndex = 1
+        this.get_taskList()
+      }
+    },
+    chartSearchFormChange(key, value) {
+      console.log(key, value, this.chartSearchFormRenderData)
+      this.form_task[key] = value
+    },
+    updateChartSlectOption(key, option) {
+      this.chartSearchFormRenderData.map(t => {
+        if (t.key === key) {
+          t.option = option
+        }
+      })
+    },
+    updateChartSearchFormValue() {
+      this.chartSearchFormRenderData.map(t => {
+        t.value = this.form_task[t.key]
+      })
     }
   }
 }
 </script>
 <style lang="scss" scoped>
+.chartView {
+  .chartSearchTitle {
+    width: 50px;
+    color: #333333;
+    font-size: 14px;
+  }
+  .screen {
+    margin-left: 20px;
+  }
+}
 .stylus-head {
   position: relative;
 }
@@ -528,6 +840,50 @@ export default {
   position: absolute;
   left: 120px;
 }
+.filter {
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  margin-top: 15px;
+  .filterWrap {
+    display: flex;
+    align-items: baseline;
+    .title {
+      width: 100px;
+    }
+    .itemBox {
+      .item {
+        display: inline-block;
+        margin-right: 20px;
+        margin-bottom: 10px;
+        cursor: pointer;
+      }
+    }
+  }
+  .btn {
+    font-size: 14px;
+    color: #00A0FF;
+    cursor: pointer;
+    min-width: 80px;
+    text-align: center;
+  }
+}
+.subtitle {
+  color: #333;
+  font-size: 16px;
+  background: #fff;
+  font-weight: 700;
+  padding: 16px 8px;
+}
+.search_box {
+  .item {
+    width: 270px;
+    margin-right: 15px;
+    .queryName {
+      min-width: 80px;
+    }
+  }
+}
 </style>
 <style>
 .el-loading-mask {
@@ -631,7 +987,7 @@ export default {
     margin:0 auto
     background-color white
     border-radius 4px
-    min-height: calc(100vh - 143px);
+    // min-height: calc(100vh - 143px);
     .stylus-hover:hover
       color #409EFF !important
       cursor pointer

+ 69 - 67
src/views/projectManage/version/components/taskList.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="pro_version_com_taskList">
     <el-row v-if="!showHeader" class="select-main" type="flex" align="center">
       <el-col :span="2" class="flex-align-center">
         <el-checkbox v-model="planChecked" class="plan-checked" @change="changeCheck" />
@@ -522,79 +522,81 @@ export default {
 }
 </style>
 <style lang="scss">
-.item{
-  /deep/ input {
-    color: rgb(126, 211, 33);
-    border: 1px solid rgb(126, 211, 33);
-     border-color: rgb(126, 211, 33) !important;
-         font-weight: 900;
-  }
-  /deep/ .el-input__suffix {
-    color: rgb(126, 211, 33) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-    color: rgb(126, 211, 33) !important;
-  }
-}
-.item1 {
-  /deep/ input {
-    color: rgb(255, 204, 102);
-     border: 1px solid rgb(255, 204, 102);
-     border-color: rgb(255, 204, 102) !important;
-         font-weight: 900;
-  }
-  /deep/ .el-input__suffix {
-    color: rgb(255, 204, 102) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-    color: rgb(255, 204, 102) !important;
+.pro_version_com_taskList {
+  .item{
+    /deep/ input {
+      color: rgb(126, 211, 33);
+      border: 1px solid rgb(126, 211, 33);
+      border-color: rgb(126, 211, 33) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(126, 211, 33) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
+      color: rgb(126, 211, 33) !important;
+    }
   }
-}
-.item2 {
-  /deep/ input {
-    color: rgb(245, 108, 108);
-    border: 1px solid rgb(245, 108, 108);
-    border-color: rgb(245, 108, 108) !important;
-        font-weight: 900;
+  .item1 {
+    /deep/ input {
+      color: rgb(255, 204, 102);
+      border: 1px solid rgb(255, 204, 102);
+      border-color: rgb(255, 204, 102) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(255, 204, 102) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
+      color: rgb(255, 204, 102) !important;
+    }
   }
-   /deep/ .el-input__suffix {
+  .item2 {
+    /deep/ input {
+      color: rgb(245, 108, 108);
+      border: 1px solid rgb(245, 108, 108);
+      border-color: rgb(245, 108, 108) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(245, 108, 108) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: rgb(245, 108, 108) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-   color: rgb(245, 108, 108) !important;
-  }
-}
-.item3 {
-  /deep/ input {
-    color: #D675F0;
-    border: 1px solid #D675F0;
-    border-color: #D675F0 !important;
-        font-weight: 900;
+    }
   }
-    /deep/ .el-input__suffix {
+  .item3 {
+    /deep/ input {
+      color: #D675F0;
+      border: 1px solid #D675F0;
+      border-color: #D675F0 !important;
+          font-weight: 900;
+    }
+      /deep/ .el-input__suffix {
+      color: #D675F0 !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: #D675F0 !important;
-    right: 1px;
-  }
-   /deep/ .el-select__caret {
-   color: #D675F0 !important;
-  }
-}
-.item-color {
-  /deep/ input {
-    color: rgb(106, 180, 255);
-    border: 1px solid rgb(106, 180, 255);
-    border-color: rgb(106, 180, 255) !important;
-        font-weight: 900;
+    }
   }
-    /deep/ .el-input__suffix {
+  .item-color {
+    /deep/ input {
+      color: rgb(106, 180, 255);
+      border: 1px solid rgb(106, 180, 255);
+      border-color: rgb(106, 180, 255) !important;
+          font-weight: 900;
+    }
+      /deep/ .el-input__suffix {
+      color: rgb(106, 180, 255) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: rgb(106, 180, 255) !important;
-    right: 1px;
-  }
-   /deep/ .el-select__caret {
-   color: rgb(106, 180, 255) !important;
+    }
   }
 }
 </style>

+ 6 - 2
src/views/reportManagement/ReleaseReport/newReleaeTemplate.vue

@@ -12,7 +12,6 @@
       <div v-if="!releaseType" style=" margin-bottom: 10px;">
         <span style="color: #f56b6c">*</span>
         <span class="backStyle"> 关联任务</span><br>
-
         <el-select v-model="from.taskIds" filterable remote reserve-keyword placeholder="🔍 请输入任务名称或ID" :remote-method="remoteMethod" style="width: 30%;margin-top: 10px;" size="small" @change="colseSelect">
           <el-option v-for="item in tasksOptions" :key="item.id" :label="item.name" :value="item.id" @click.native="tasksChange(item)">
             <div class="Layout_space_between"><span>{{ item.name }}</span></div>
@@ -99,7 +98,12 @@
           <!-- <searchTeam :value.sync="from.tester" :clearable="true" :multiple="true" :disabled="releaseType" :placeholder="'请输入姓名或邮箱前缀'" :size="'small'" style="width: 100%;" /> -->
         </el-col>
       </el-row>
-      <normal-area id="report-template" :value.sync="fromData.content" :height="500" />
+      <normal-area
+        id="report-template-1"
+        :value.sync="fromData.content"
+        :height="500"
+        :full-position-style="{ top:'20px',left:'14.5%', right: '15.5%' }"
+      />
     </el-form>
     <div class="backStyle">缺陷统计</div>
     <iconDisplay :task-ids="taskId" :release-type="releaseType" />

+ 6 - 1
src/views/reportManagement/Testing/newTestingTemplate.vue

@@ -123,7 +123,12 @@
       <el-table-column prop="referredClientTypeName" label="跟版客户端" min-width="300" />
     </el-table>
 
-    <normal-area id="report-template" :value.sync="fromCreateData.content" :height="500" />
+    <normal-area
+      id="report-template-2"
+      :value.sync="fromCreateData.content"
+      :height="500"
+      :full-position-style="{ top:'20px',left:'14.5%', right: '15.5%' }"
+    />
   </div>
 </template>
 

+ 6 - 1
src/views/reportManagement/daily/dailyTemplate.vue

@@ -27,7 +27,12 @@
       </el-form-item>
 
       <el-form-item label="报告内容" style="margin-top: 20px;"><br>
-        <normal-area id="report-template" :value.sync="fromCreateData.content" :height="500" />
+        <normal-area
+          id="report-template-4"
+          :value.sync="fromCreateData.content"
+          :height="500"
+          :full-position-style="{ top:'20px',left:'14.5%', right: '15.5%' }"
+        />
       </el-form-item>
     </el-form>
     <icon-display :details="taskid_arr" />

+ 6 - 1
src/views/reportManagement/daily/newReportTemplate.vue

@@ -10,7 +10,12 @@
         <el-input v-model="fromCreateData.moduleName" size="small" style="width:100%;" placeholder="请输入模版名称(不可与现有模版重名)" />
       </el-form-item>
       <el-form-item label="模版内容"><br>
-        <normal-area id="report-template" :value.sync="fromCreateData.content" :height="500" />
+        <normal-area
+          id="report-template-3"
+          :value.sync="fromCreateData.content"
+          :height="500"
+          :full-position-style="{ top:'20px',left:'14.5%', right: '15.5%' }"
+        />
       </el-form-item>
     </el-form>
     <div class="backStyle">缺陷统计</div>

+ 2 - 2
src/views/workbench/team/components/needsList.vue

@@ -224,10 +224,10 @@ export default {
     color:$color;
     border: 1px solid $color;
   }
-  >>> .el-select__caret{
+  >>> .el-select__caret {
     color:$color;
   }
-  >>> .el-input__inner{
+  >>> .el-input__inner {
     color:$color;
     border-color: $color;
   }

+ 73 - 71
src/views/workbench/team/components/taskList.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="pro_workbench_team_com_taskList">
     <div class="table-top">
       <label>{{ name }}的任务</label>
       <!-- <span class="new-tab-open">
@@ -561,84 +561,86 @@ export default {
 }
 </style>
 <style lang="scss">
-.btns .el-input--suffix .el-input__inner {
-  padding-right: 10px;
-  padding-left: 10px;
-  width: 73px;
-}
-.item{
-  /deep/ input {
-    color: rgb(126, 211, 33);
-    border: 1px solid rgb(126, 211, 33);
-     border-color: rgb(126, 211, 33) !important;
-         font-weight: 900;
+.pro_workbench_team_com_taskList {
+  .btns .el-input--suffix .el-input__inner {
+    padding-right: 10px;
+    padding-left: 10px;
+    width: 73px;
   }
-  /deep/ .el-input__suffix {
-    color: rgb(126, 211, 33) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-    color: rgb(126, 211, 33) !important;
-  }
-}
-.item1 {
-  /deep/ input {
-    color: rgb(255, 204, 102);
-     border: 1px solid rgb(255, 204, 102);
-     border-color: rgb(255, 204, 102) !important;
-         font-weight: 900;
-  }
-  /deep/ .el-input__suffix {
-    color: rgb(255, 204, 102) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-    color: rgb(255, 204, 102) !important;
+  .item{
+    /deep/ input {
+      color: rgb(126, 211, 33);
+      border: 1px solid rgb(126, 211, 33);
+      border-color: rgb(126, 211, 33) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(126, 211, 33) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
+      color: rgb(126, 211, 33) !important;
+    }
   }
-}
-.item2 {
-  /deep/ input {
-    color: rgb(245, 108, 108);
-    border: 1px solid rgb(245, 108, 108);
-    border-color: rgb(245, 108, 108) !important;
-        font-weight: 900;
+  .item1 {
+    /deep/ input {
+      color: rgb(255, 204, 102);
+      border: 1px solid rgb(255, 204, 102);
+      border-color: rgb(255, 204, 102) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(255, 204, 102) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
+      color: rgb(255, 204, 102) !important;
+    }
   }
-   /deep/ .el-input__suffix {
+  .item2 {
+    /deep/ input {
+      color: rgb(245, 108, 108);
+      border: 1px solid rgb(245, 108, 108);
+      border-color: rgb(245, 108, 108) !important;
+          font-weight: 900;
+    }
+    /deep/ .el-input__suffix {
+      color: rgb(245, 108, 108) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: rgb(245, 108, 108) !important;
-    right: 1px;
-  }
-  /deep/ .el-select__caret {
-   color: rgb(245, 108, 108) !important;
-  }
-}
-.item3 {
-  /deep/ input {
-    color: #D675F0;
-    border: 1px solid #D675F0;
-    border-color: #D675F0 !important;
-        font-weight: 900;
+    }
   }
-    /deep/ .el-input__suffix {
+  .item3 {
+    /deep/ input {
+      color: #D675F0;
+      border: 1px solid #D675F0;
+      border-color: #D675F0 !important;
+          font-weight: 900;
+    }
+      /deep/ .el-input__suffix {
+      color: #D675F0 !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: #D675F0 !important;
-    right: 1px;
-  }
-   /deep/ .el-select__caret {
-   color: #D675F0 !important;
-  }
-}
-.item-color {
-  /deep/ input {
-    color: rgb(106, 180, 255);
-    border: 1px solid rgb(106, 180, 255);
-    border-color: rgb(106, 180, 255) !important;
-        font-weight: 900;
+    }
   }
-    /deep/ .el-input__suffix {
+  .item-color {
+    /deep/ input {
+      color: rgb(106, 180, 255);
+      border: 1px solid rgb(106, 180, 255);
+      border-color: rgb(106, 180, 255) !important;
+          font-weight: 900;
+    }
+      /deep/ .el-input__suffix {
+      color: rgb(106, 180, 255) !important;
+      right: 1px;
+    }
+    /deep/ .el-select__caret {
     color: rgb(106, 180, 255) !important;
-    right: 1px;
-  }
-   /deep/ .el-select__caret {
-   color: rgb(106, 180, 255) !important;
+    }
   }
 }
 </style>