wenbobowen 4 năm trước cách đây
mục cha
commit
7a3400ded4

+ 33 - 1
src/api/onlineproblem.js

@@ -2,10 +2,42 @@ import request from '@/utils/request'
 import { TeamManagement } from '@/apiConfig/api'
 
 // 获取团队信息
+// const TeamManagement = "http://172.23.156.16:8990/project-management"
 export function teamQueryTeamInfo(data) {
   return request({
-    url: TeamManagement + `/team/queryTeamInfo`,
+    url: TeamManagement + `/team/queryTeamAndMemberInfoList`,
     method: 'post',
     data
   })
 }
+
+export function getPerson(data) {
+  return request({
+    url: TeamManagement + '/member/queryMemberInfoByIDAPorName',
+    method: 'post',
+    data
+  })
+}
+
+export function create(data) {
+  return request({
+    url: TeamManagement + '/onlineProblem/create',
+    method: 'post',
+    data
+  })
+}
+
+export function getlist(data) {
+  return request({
+    url: TeamManagement + '/onlineProblem/list',
+    method: 'post',
+    data
+  })
+}
+
+export function getDetial(data) {
+  return request({
+    url: TeamManagement + '/onlineProblem/get?id=' + data.id,
+    method: 'get'
+  })
+}

+ 36 - 22
src/components/formInput/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="formInput Layout">
-    <span class="title">
-      <span>*</span>
+    <span class="title" :style="!requried && { ...styles, paddingLeft: '12px' }">
+      <span v-if="requried" class="mustInput">*</span>
       {{ title }}
     </span>
     <!-- 输入框 -->
@@ -10,24 +10,16 @@
       v-model="val"
       :size="size"
       clearable
-      :placeholder="`placeholderinput`"
+      :placeholder="placeholder"
       @change="(e) => $emit('onChange', e)"
     />
     <!-- number -->
-    <!-- <el-input
-      v-else-if="type === 'number'"
-      v-model="val"
-      :size="size"
-      type="number"
-      :placeholder="`placeholdernumber`"
-      @change="(e) => $emit('onChange', e)"
-    /> -->
     <el-input-number
       v-else-if="type === 'number'"
       v-model="val"
       :size="size"
       style="width:194px"
-      :placeholder="`placeholdernumber`"
+      :placeholder="placeholder"
       @change="(e) => $emit('onChange', e)"
     />
     <!-- textarea -->
@@ -36,7 +28,7 @@
       v-model="val"
       :size="size"
       type="textarea"
-      :placeholder="`placeholdertextarea`"
+      :placeholder="placeholder"
       @change="(e) => $emit('onChange', e)"
     />
     <!-- 静态下啦选择 -->
@@ -47,7 +39,7 @@
       :multiple="multiple"
       clearable
       filterable
-      :placeholder="`placeholderselect`"
+      :placeholder="placeholder"
       @change="(e) => $emit('onChange', e)"
     >
       <el-option v-for="o in option" :key="o.value" :label="o.label" :value="o.value" />
@@ -59,13 +51,15 @@
       filterable
       remote
       clearable
-      :placeholder="`placeholderremoteSelect`"
+      :placeholder="placeholder"
+      :multiple="multiple"
       :remote-method="(q) => $emit('remoteMethod', q)"
       :loading="loading"
       :size="size"
       @change="(e) => $emit('onChange', e)"
     >
-      <el-option v-for="o in option" :key="o.value" :label="o.label" :value="o.value" />
+      <slot v-if="hasSlot" name="option" />
+      <el-option v-for="o in option" v-else :key="o.value" :label="o.label" :value="o.value" />
     </el-select>
     <!-- 日期 -->
     <el-date-picker
@@ -74,7 +68,7 @@
       :size="size"
       value-format="yyyy-MM-dd hh:mm:ss"
       type="datetime"
-      placeholder="选择日期时间"
+      :placeholder="placeholder"
       style="width:194px"
       @change="(e) => $emit('onChange', e)"
     />
@@ -108,12 +102,27 @@ export default {
       type: Array,
       default: () => [],
       required: false
+    },
+    requried: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    hasSlot: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    styles: {
+      type: Object,
+      default: () => {},
+      required: false
+    },
+    placeholder: {
+      type: String,
+      default: '',
+      required: false
     }
-    // data: {
-    //   type: Object,
-    //   default: () => {},
-    //   required: true
-    // }
   },
   data() {
     return {
@@ -128,6 +137,11 @@ export default {
   .title {
     // display: inline-block;
     min-width: 153px;
+    .mustInput {
+      display: inline-block;
+      width: 10px;
+      color: #F56C6C;
+    }
   }
 }
 </style>

+ 90 - 14
src/components/searchHeader/index.vue

@@ -2,22 +2,50 @@
   <div class="searchHeader">
     <div class="defaultBox Layout">
       <div class="content">
-        <searchBox :list="data.default" />
+        <searchBox
+          :list="data.default"
+          @change="$emit('search')"
+          @getOption="(key, q, utilName) => getOption(key, q, utilName, 'default')"
+        />
       </div>
-      <div class="btn" @click="showMore">{{ goodName }}</div>
+      <div class="dateSelected">
+        <el-select
+          v-model="year"
+          size="small"
+          filterable
+          style="margin-right: 8px; width: 110px"
+          @change="$emit('search', 'year', year)"
+        >
+          <el-option v-for="(y, index) in yearList" :key="index" :label="y" :value="y" />
+        </el-select>
+        <el-select
+          v-model="month"
+          size="small"
+          filterable
+          style="margin-right: 8px; width: 100px"
+          @change="$emit('search', 'month', month)"
+        >
+          <el-option v-for="(m, index) in monthList" :key="index" :label="m" :value="m" />
+        </el-select>
+      </div>
+      <div class="btn" @click="showMoreHandle">{{ goodName }}</div>
     </div>
-    <div v-show="!DetailedScreening" class="advBox">
+    <div v-show="showMore" class="advBox">
       <div class="content">
-        <searchBox :list="data.adv" />
+        <searchBox
+          :list="data.adv"
+          @getOption="(key, q, utilName) => getOption(key, q, utilName, 'adv')"
+        />
       </div>
       <div class="btnWrap">
-        <el-button type="primary" size="mini" @click="search(form_all)">筛 选</el-button>
+        <el-button type="primary" size="mini" @click="$emit('search')">筛 选</el-button>
         <el-button size="mini" @click="moreReset">重 置</el-button>
       </div>
     </div>
   </div>
 </template>
 <script>
+import { getPerson, teamQueryTeamInfo } from '@/api/onlineproblem'
 import searchBox from './searchBox'
 import '@/views/projectManage/publicCss/index.css'
 export default {
@@ -37,22 +65,57 @@ export default {
       options: [],
       goodName: '更多筛选',
       loading: false,
-      DetailedScreening: false,
-      renderList: this.list || {}
+      showMore: false,
+      renderList: this.list || {},
+      yearList: [],
+      monthList: ['全部', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],
+      year: new Date().getFullYear(),
+      month: new Date().getMonth() + 1
     }
   },
   mounted() {
-    console.log(this.data)
+    const d = new Date()
+    const nowYear = d.getFullYear()
+    const nowMonth = d.getMonth() + 1
+    for (let i = 0; i <= nowYear - 2020; i++) {
+      this.yearList.unshift(2020 + i)
+    }
+    this.year = nowYear
+    this.month = nowMonth < 10 ? `0${nowMonth}` : nowMonth
   },
   methods: {
-    create() {
-      console.log('新建')
-    },
-    showMore() {
-      console.log('showMore')
-    },
     moreReset() {
       console.log('moreReset')
+    },
+    showMoreHandle() {
+      this.showMore = !this.showMore
+      this.$emit('changeShowMore', this.showMore)
+    },
+    async getOption(key, q, utilName, type) {
+      console.log(key, q, utilName)
+      if (utilName === 'getPerson') {
+        const res = await getPerson({ memberIDAP: q })
+        this.data[type].map(t => t.map(g => {
+          if (g.key === key) {
+            g.option = res.data.map(t => ({
+              ...t,
+              value: t.idap,
+              label: t.name
+            }))
+          }
+        }))
+      } else if (utilName === 'getTeam') {
+        const res = await teamQueryTeamInfo({ teamName: q, bizId: this.$store.state.global.bizId })
+        this.data[type].map(t => t.map(g => {
+          if (g.key === key) {
+            g.option = res.data.map(t => ({
+              ...t,
+              value: t.teamId,
+              label: t.teamName
+            }))
+          }
+        }))
+      }
     }
   }
 }
@@ -71,6 +134,19 @@ export default {
       cursor: pointer;
       width: 80px;
       text-align: center;
+      line-height: 30px;
+    }
+    .dateSelected {
+      position: absolute;
+      bottom: 16px;
+      right: 80px;
+      font-size: 14px;
+      // color: #00A0FF;
+      cursor: pointer;
+      width: 170px;
+      text-align: center;
+      display: flex;
+
     }
   }
   .advBox {

+ 33 - 19
src/components/searchHeader/searchBox.vue

@@ -5,38 +5,48 @@
         <div class="name">{{ l.name }}</div>
         <el-select
           v-if="l.type === 'select'"
-          v-model="l.default"
+          v-model="l.value"
           size="small"
           :multiple="l.multiple"
           clearable
           filterable
           :placeholder="l.placeholder"
-          @change="change(l.key)"
+          @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.default"
+          v-model="l.value"
           filterable
           remote
           clearable
           :placeholder="l.placeholder"
-          :remote-method="(q) => remoteMethod(l.key, q)"
+          :remote-method="(q) => $emit('getOption', l.key, q, l.utilName)"
           :loading="loading"
           size="small"
-          @change="change(l.key)"
+          @change="$emit('change')"
         >
-          <el-option v-for="o in l.option" :key="o.value" :label="o.label" :value="o.value" />
+          <!-- <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.default"
+          v-model="l.value"
           style="width: 72% !important"
           size="small"
           clearable
           :placeholder="l.placeholder"
-          @change="change(l.key)"
+          @change="$emit('change')"
         />
       </div>
     </div>
@@ -49,23 +59,17 @@ export default {
       type: Array,
       required: false,
       default: () => []
+    },
+    hasSlot: {
+      type: Boolean,
+      default: false,
+      required: false
     }
   },
   data() {
     return {
       loading: false
     }
-  },
-  mounted() {
-    console.log(this.list)
-  },
-  methods: {
-    change(key) {
-      console.log(key)
-    },
-    remoteMethod(key, q) {
-      console.log('remoteMethod', q, key)
-    }
   }
 }
 </script>
@@ -80,4 +84,14 @@ export default {
     width: 80px;
   }
 }
+.item-style {
+  display: flex;
+  justify-content: flex-start;
+  .item-detail {
+    min-width:100px;
+    color: #8492a6;
+    font-size: 13px;
+    overflow:hidden
+  }
+}
 </style>

+ 4 - 0
src/components/select/redme.md

@@ -0,0 +1,4 @@
+<searchPerson
+  :value="data.pm"
+  @onChange="(e) => onChange(e)"
+/>

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

@@ -82,7 +82,9 @@ export default {
         } else {
           this.searchValue = newV
         }
+        console.log(this.searchValue)
         const type = Object.prototype.toString.call(this.searchValue)
+        console.log(type)
         if (type.indexOf('Array') < 0) {
           this.remoteMethod(this.searchValue)
         } else if (type.indexOf('Array') > 0 && this.searchValue.length > 0 && this.firstGetArr) {
@@ -98,6 +100,7 @@ export default {
   },
   methods: {
     remoteMethod(query) {
+      console.log(query)
       query !== '' ? this.getMember(query) : this.options = []
     },
     initMore(arr) { // 当多人时候,对数组每一个人员进行搜索
@@ -117,7 +120,17 @@ export default {
           weakMap.set(item.idap, item)
         }
       }
-      initMore ? this.options = [...this.options, ...weakMap.values()] : this.options = [...weakMap.values()]
+      // 去重
+      let op = null
+      const hash = {}
+      const item = []
+      initMore ? op = [...this.options, ...weakMap.values()] : op = [...weakMap.values()]
+      op.map(t => {
+        if (!hash[t.deptid]) {
+          hash[t.deptid] = true && item.push(t)
+        }
+      })
+      this.options = item
     },
     changeSelect(e) {
       if (this.searchValue === [] || this.searchValue === '') {

+ 131 - 0
src/components/select/selectPerson.vue

@@ -0,0 +1,131 @@
+<template>
+  <el-select
+    v-model="val"
+    filterable
+    remote
+    class="wb-selectInput"
+    :class="borderEdit ? 'borderEdit': ''"
+    :clearable="clearable"
+    :placeholder="placeholder"
+    :multiple="multiple"
+    :remote-method="remoteMethod"
+    :loading="loading"
+    :size="size"
+    @change="(e) => $emit('onChange', e)"
+  >
+    <el-option
+      v-for="o in options"
+      :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>
+  </el-select>
+</template>
+<script>
+import { getPerson } from '@/api/onlineproblem'
+export default {
+  props: {
+    value: defaultStatus,
+    size: {
+      type: String,
+      default: 'small',
+      requried: false
+    },
+    multiple: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    loading: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    // 隐藏边框hover时显示
+    borderEdit: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    option: {
+      type: Array,
+      default: () => [],
+      required: false
+    },
+    requried: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    hasSlot: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    styles: {
+      type: Object,
+      default: () => {},
+      required: false
+    },
+    placeholder: {
+      type: String,
+      default: '',
+      required: false
+    },
+    clearable: { // 是否支持清空
+      type: Boolean,
+      default: true,
+      required: false
+    }
+  },
+  data() {
+    return {
+      searchValue: this.value,
+      loadStatus: this.loading,
+      options: [],
+      val: this.value
+    }
+  },
+
+  mounted() {
+    this.remoteMethod()
+  },
+  methods: {
+    async remoteMethod(q = this.searchValue) {
+      const res = await getPerson({ memberIDAP: q })
+      this.options = res.data
+    }
+  }
+
+}
+</script>
+<style lang="scss">
+.wb-selectInput {
+  &.borderEdit {
+    .el-input__inner {
+      border-color: transparent;
+      &:hover {
+        border-color: #DCDFE6;
+      }
+    }
+  }
+}
+</style>
+<style scope lang="scss">
+.item-style {
+  display: flex;
+  justify-content: flex-start;
+  .item-detail {
+    min-width:100px;
+    color: #8492a6;
+    font-size: 13px;
+    overflow:hidden
+  }
+}
+</style>

+ 126 - 0
src/components/select/selectTeam.vue

@@ -0,0 +1,126 @@
+<template>
+  <el-select
+    v-model="val"
+    filterable
+    remote
+    class="wb-selectInput"
+    :class="borderEdit ? 'borderEdit': ''"
+    :clearable="clearable"
+    :placeholder="placeholder"
+    :multiple="multiple"
+    :remote-method="remoteMethod"
+    :loading="loading"
+    :size="size"
+    @change="(e) => $emit('onChange', e)"
+  >
+    <el-option
+      v-for="o in options"
+      :key="o.teamId"
+      :label="o.teamName"
+      :value="o.teamId"
+    />
+  </el-select>
+</template>
+<script>
+import { teamQueryTeamInfo } from '@/api/onlineproblem'
+export default {
+  props: {
+    value: defaultStatus,
+    size: {
+      type: String,
+      default: 'small',
+      requried: false
+    },
+    multiple: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    loading: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    // 隐藏边框hover时显示
+    borderEdit: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    option: {
+      type: Array,
+      default: () => [],
+      required: false
+    },
+    requried: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    hasSlot: {
+      type: Boolean,
+      default: false,
+      required: false
+    },
+    styles: {
+      type: Object,
+      default: () => {},
+      required: false
+    },
+    placeholder: {
+      type: String,
+      default: '',
+      required: false
+    },
+    clearable: { // 是否支持清空
+      type: Boolean,
+      default: true,
+      required: false
+    }
+  },
+  data() {
+    return {
+      searchValue: this.value,
+      loadStatus: this.loading,
+      options: [],
+      val: this.value
+    }
+  },
+
+  mounted() {
+    this.remoteMethod()
+  },
+  methods: {
+    async remoteMethod(q = this.searchValue) {
+      const res = await teamQueryTeamInfo({ teamName: q, bizId: this.$store.state.global.bizId })
+      this.options = res.data
+      console.log(res.data)
+    }
+  }
+
+}
+</script>
+<style lang="scss">
+.wb-selectInput {
+  &.borderEdit {
+    .el-input__inner {
+      border-color: transparent;
+      &:hover {
+        border-color: #DCDFE6;
+      }
+    }
+  }
+}
+</style>
+<style scope lang="scss">
+.item-style {
+  display: flex;
+  justify-content: flex-start;
+  .item-detail {
+    min-width:100px;
+    color: #8492a6;
+    font-size: 13px;
+    overflow:hidden
+  }
+}
+</style>

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

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12.599" height="12.599"><defs></defs><g id="统计_6_" data-name="统计 (6)" transform="translate(-156.739 -134.246)"><path id="路径_13058" data-name="路径 13058" class="cls-1" d="M168.9 145.977h-11.258a.037.037 0 01-.036-.036V134.68a.433.433 0 10-.867 0v11.262a.9.9 0 00.9.9H168.9a.434.434 0 000-.867z"/><path id="路径_13059" data-name="路径 13059" class="cls-1" d="M261.617 257.966a.434.434 0 00.433-.434v-2.346a.433.433 0 10-.867 0v2.346a.434.434 0 00.434.434zm2.215-3.249v2.816a.433.433 0 10.867 0v-2.816a.433.433 0 10-.867 0zm2.826-.7v3.519a.433.433 0 10.867 0v-3.519a.433.433 0 10-.867 0zm3.081-1.841a.434.434 0 00-.433.434v4.927a.433.433 0 10.867 0v-4.927a.434.434 0 00-.434-.438zm-8 1.978a.432.432 0 00.237-.071l2.383-1.563 2.586.157h.032l3.107-2.78a.434.434 0 10-.578-.647l-2.837 2.539-2.544-.154-2.623 1.721a.434.434 0 00.238.8z" transform="translate(-102.732 -113.006)"/></g></svg>

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

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="11.776" height="11.208"><path d="M3.977 1.682h7.238a.561.561 0 100-1.121H3.977a.561.561 0 100 1.121zm0 4.472h7.212a.561.561 0 100-1.121H3.977a.561.561 0 100 1.121zm7.239 3.375H3.978a.561.561 0 100 1.121h7.238a.561.561 0 100-1.121zM0 1.122A1.121 1.121 0 101.121.001 1.121 1.121 0 000 1.121zm0 4.465a1.121 1.121 0 101.121-1.121A1.121 1.121 0 000 5.586zm0 4.5a1.121 1.121 0 101.121-1.121A1.121 1.121 0 000 10.086z"/></svg>

+ 7 - 0
src/router/newRouter.js

@@ -208,6 +208,13 @@ const layout = [
         component: () => import('@/views/projectManage/onlineproblem/create'),
         meta: { title: '质惠新建线上问题' }
       },
+      {
+        path: '/onlineProblem/detial',
+        name: '质惠线上问题详情',
+        hidden: true,
+        component: () => import('@/views/projectManage/onlineproblem/detial'),
+        meta: { title: '质惠线上问题详情' }
+      },
       // ---end---
       {
         path: 'useCasePage',

+ 122 - 0
src/views/projectManage/onlineproblem/component/chart.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="op-chart">
+    <!-- 按月份 等级 影响面  -->
+    <div class="chartSearchbar">
+      <el-select
+        v-model="type"
+        size="small"
+        filterable
+        style="width: 100px"
+        @change="$emit('search', 'type', type)"
+      >
+        <el-option v-for="(t, index) in dataListType" :key="index" :label="t.label" :value="t.value" />
+      </el-select>
+      <el-select
+        v-model="year"
+        size="small"
+        filterable
+        style="width: 80px"
+        @change="$emit('search', 'year', year)"
+      >
+        <el-option v-for="(y, index) in yearList" :key="index" :label="y" :value="y" />
+      </el-select>
+    </div>
+    <normal-echart :chart-id="'chartThird'" :option="echartsOption3" @onClick="changeList" />
+  </div>
+</template>
+<script>
+import normalEchart from '@/components/chart/normalEchart'
+export default {
+  components: {
+    normalEchart
+  },
+  data() {
+    return {
+      dataListType: [
+        { value: '0', label: '按月份' },
+        { value: '1', label: '按等级' },
+        { value: '2', label: '按影响面' }
+      ],
+      yearList: [],
+      year: '',
+      type: '0'
+      // echartsOption3:{
+      //   "color": ["#3AA1FF"],
+      //   "tooltip": {
+      //     "trigger": "axis",
+      //     "axisPointer": {
+      //       "type": "line"
+      //     }
+      //   },
+      //   "grid": {
+      //     "left": "5%",
+      //     "right": "5%",
+      //     "top": "10%",
+      //     "bottom": "10%",
+      //     "containLabel": true
+      //   },
+      //   "xAxis": [{
+      //     "type": "category",
+      //     "data": ["待修复", "待测试", "未完成", "已完成", "Reopen", "Hold"],
+      //     "axisLabel": {
+      //       "interval": 0,
+      //       "rotate": 40
+      //     },
+      //     "axisTick": {
+      //       "alignWithLabel": true
+      //     }
+      //   }],
+      //   "yAxis": [{
+      //     "type": "value",
+      //     "axisLine": {
+      //       "show": false
+      //     },
+      //     "splitLine": {
+      //       "lineStyle": {
+      //         "type": "dashed"
+      //       }
+      //     }
+      //   }],
+      //   "series": [{
+      //     "name": null,
+      //     "type": "bar",
+      //     "barWidth": "20px",
+      //     "data": [1, 0, 0, 0, 0, 0],
+      //     "itemStyle": {
+      //       "normal": {
+      //         "label": {
+      //           "show": true,
+      //           "formatter": "{c}",
+      //           "position": "top"
+      //         }
+      //       }
+      //     }
+      //   }]
+      // }
+    }
+  },
+  mounted() {
+    const d = new Date()
+    const nowYear = d.getFullYear()
+    for (let i = 0; i <= nowYear - 2020; i++) {
+      this.yearList.unshift(2020 + i)
+    }
+    this.year = nowYear
+  },
+  methods: {
+    changeList(data) {
+      console.log(data)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.op-chart {
+  height: 324px;
+  .chartSearchbar {
+    display: flex;
+    justify-content: space-between;
+    padding: 0 5%;
+  }
+}
+</style>

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

@@ -1,29 +1,85 @@
 <template>
   <div class="header">
     <div class="stylus-head">
-      <mainTitle title="线上问题" btn-text="新建问题" @btn-handle="create" />
-      <searchHeader :data="renderList" />
+      <mainTitle
+        title="线上问题"
+        btn-text="新建问题"
+        @btn-handle="create"
+        @change-tab="changeTab"
+      />
+      <searchHeader
+        v-if="nowTab === 'list'"
+        :data="renderList"
+        @search="search"
+        @changeShowMore="changeShowMore"
+      />
+      <div v-if="nowTab === 'charts'" style="height:324px;">
+        <chart />
+      </div>
     </div>
   </div>
 </template>
 <script>
+import { getlist } from '@/api/onlineproblem'
+
 import searchHeader from '@/components/searchHeader'
 import searchData from './searchData'
 import mainTitle from '../mainTitle'
+import chart from '../chart'
 export default {
   components: {
     searchHeader,
-    mainTitle
+    mainTitle,
+    chart
   },
   data() {
     return {
-      renderList: searchData
+      renderList: searchData,
+      year: '',
+      month: '',
+      nowTab: 'list',
+      showMore: false
     }
   },
+  mounted() {
+    const d = new Date()
+    const nowYear = d.getFullYear()
+    const nowMonth = d.getMonth() + 1
+    this.year = nowYear
+    this.month = nowMonth < 10 ? `0${nowMonth}` : nowMonth
+    this.search()
+  },
   methods: {
+    changeTab(e) {
+      this.nowTab = e
+      this.$emit('change-tab', e)
+    },
+    changeShowMore(e) {
+      console.log(e)
+      this.showMore = e
+    },
     create() {
-      console.log('新建')
-      this.$router.push({ name: '质惠新建线上问题', query: { id: 111 }})
+      this.$router.push({ name: '质惠新建线上问题' })
+    },
+    async search(key, value) {
+      console.log(this.renderList, this.showMore)
+      const data = {}
+      this.renderList.default.map(t => t.map(g => {
+        data[g.key] = g.value
+      }))
+      if (this.showMore) {
+        this.renderList.adv.map(t => t.map(g => {
+          data[g.key] = g.value
+        }))
+      }
+      if (key) {
+        this[key] = value === '全部' ? '0' : value
+      }
+      data.year = '' + this.year
+      data.month = this.month
+      console.log(data)
+      const res = await getlist(data)
+      this.$emit('listChange', res.data)
     }
   }
 }

+ 18 - 14
src/views/projectManage/onlineproblem/component/header/searchData.js

@@ -3,7 +3,7 @@ const data = {
     [
       {
         name: '问题名称',
-        default: '',
+        value: '',
         key: 'title',
         type: 'input',
         placeholder: '请输入问题名称或ID'
@@ -17,16 +17,17 @@ const data = {
       type: 'select',
       multiple: false,
       placeholder: '',
-      default: 'p6',
+      value: '6',
+      requried: true,
       option: [
-        { value: 0, label: 'P0' },
-        { value: 1, label: 'P1' },
-        { value: 2, label: 'P2' },
-        { value: 3, label: 'P3' },
-        { value: 4, label: 'P4' },
-        { value: 5, label: 'P5' },
-        { value: 6, label: 'P6' },
-        { value: 7, label: '未定级' }
+        { value: '0', label: 'P0' },
+        { value: '1', label: 'P1' },
+        { value: '2', label: 'P2' },
+        { value: '3', label: 'P3' },
+        { value: '4', label: 'P4' },
+        { value: '5', label: 'P5' },
+        { value: '6', label: 'P6' },
+        { value: '7', label: '未定级' }
       ]
     },
     {
@@ -35,7 +36,8 @@ const data = {
       type: 'remoteSelect',
       multiple: false,
       placeholder: '请选择责任团队',
-      default: '',
+      value: '',
+      utilName: 'getTeam',
       option: []
     },
     {
@@ -44,7 +46,7 @@ const data = {
       type: 'select',
       multiple: false,
       placeholder: '',
-      default: false,
+      value: false,
       option: [
         { value: false, label: '否' },
         { value: true, label: '是' }
@@ -56,7 +58,7 @@ const data = {
       type: 'select',
       multiple: true,
       placeholder: '',
-      default: '',
+      value: '',
       option: [
         { value: 0, label: '用户体验' },
         { value: 1, label: '客服进线' },
@@ -70,8 +72,10 @@ const data = {
       key: 'creator',
       type: 'remoteSelect',
       multiple: false,
+      hasSlot: true,
+      utilName: 'getPerson',
       placeholder: '请选择创建人',
-      default: '',
+      value: '',
       option: []
     }]
   ]

+ 80 - 68
src/views/projectManage/onlineproblem/component/list.vue

@@ -1,71 +1,52 @@
 <template>
-  <div class="list">
-    <div class="time">2020.12</div>
-    <el-table
-      v-loading="table_loading"
-      :data="dataList"
-      style="width: 100%;"
-      highlight-current-row
-      :header-cell-style="{ 'background':'#F7F7F7', 'color':'#4a4a4a','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="优先级" min-width="100" prop="priority" sortable align="left" fixed>
-        <template slot-scope="scope">
-          <div class="div_priority" :style="{background: priorityColors[scope.row.priority]}">{{ scope.row.priorityString }}</div>
-        </template>
-      </el-table-column>
-      <el-table-column label="标题" min-width="250" show-overflow-tooltip align="left">
-        <template slot-scope="scope">
-          <span style="font-size: 12px;color: rgba(167,174,188,1);">
-            {{ scope.row.taskIdSting }}
-            <span
-              v-if="scope.row.tagNotification !== null && scope.row.status !== -2"
-              :class="{
-                'tagNotification': scope.row.tagType === 0,
-                'tagNotification1': scope.row.tagType === 1
-              }"
-            >
-              {{ scope.row.tagNotification }}
-            </span>
-            <span v-if="scope.row.status === -2" class="tagNotification1"> {{ 'hold' }} </span>
-          </span><br>
-          <span class="stylus-hover" @click="link_task(scope.row.id)">{{ scope.row.name }}</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="责任团队" min-width="150" align="center" show-overflow-tooltip>
-        <template slot-scope="scope">{{ scope.row.statusString }}</template>
-      </el-table-column>
-      <el-table-column label="复盘链接" width="150" align="center" show-overflow-tooltip>
-        <template slot-scope="scope">{{ scope.row.stageString }}</template>
-      </el-table-column>
-      <el-table-column min-width="130" align="center">
-        <template slot="header">
-          改进项已完成
-          <el-tooltip effect="dark" content="已完成改进项条数/总改进项条数" placement="top-start">
-            <i class="el-icon-info" />
-          </el-tooltip>
-        </template>
-        <template
-          slot-scope="scope"
-        >{{ scope.row.rdObject !== null? scope.row.rdObject.name: '' }}</template>
-      </el-table-column>
-      <el-table-column label="是否星辰花定级" min-width="150" align="center">
-        <template
-          slot-scope="scope"
-        >{{ scope.row.qaObject !== null?scope.row.qaObject.name: '' }}</template>
-      </el-table-column>
-      <el-table-column label="形象面" width="150" align="center" show-overflow-tooltip>
-        <template slot-scope="scope">{{ scope.row.moduleInfoName }}</template>
-      </el-table-column>
-      <el-table-column label="发生时间" min-width="120" align="center">
-        <template slot-scope="scope">{{ scope.row.noTestString }}</template>
-      </el-table-column>
-      <el-table-column label="创建人" width="120" align="center" show-overflow-tooltip>
-        <template slot-scope="scope">{{ scope.row.bugCount }}</template>
-      </el-table-column>
-    </el-table>
+  <div>
+    <div v-for="item in data" :key="item.date" class="list">
+      <div class="time">{{ item.date }}</div>
+      <el-table
+        v-loading="table_loading"
+        :data="item.data"
+        style="width: 100%;"
+        highlight-current-row
+        :header-cell-style="{ 'background':'#F7F7F7', 'color':'#4a4a4a','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="优先级" width="100" prop="priority" sortable align="center" fixed>
+          <template slot-scope="scope">
+            <div class="div_priority" :style="{background: priorityColors[scope.row.priority]}">{{ scope.row.priorityName }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="标题" min-width="230" prop="title" show-overflow-tooltip align="center">
+          <template slot-scope="scope">
+            <div class="title" @click.stop="gotoDetail(scope.row)">
+              {{ scope.row.title }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="责任团队" min-width="180" prop="teamName" show-overflow-tooltip align="center" />
+        <el-table-column label="复盘链接" show-overflow-tooltip align="center">
+          <template slot-scope="scope">{{ scope.row.replayUrl }}</template>
+        </el-table-column>
+        <el-table-column label="改进项已完成" min-width="130" show-overflow-tooltip align="center">
+          <template slot="header">
+            改进项已完成
+            <el-tooltip effect="dark" content="已完成改进项条数/总改进项条数" placement="top-start">
+              <i class="el-icon-info" />
+            </el-tooltip>
+          </template>
+          <template slot-scope="scope">{{ scope.row.finishImpr }}/{{ scope.row.imprTotal }}</template>
+        </el-table-column>
+        <el-table-column label="是否星辰花定级" min-width="130" show-overflow-tooltip align="center">
+          <template slot-scope="scope">{{ scope.row.isGrading ? '是' : '否' }}</template>
+        </el-table-column>
+        <el-table-column label="影响面" min-width="150" show-overflow-tooltip align="center">
+          <template slot-scope="scope">{{ scope.row.influenceSurfaceName }}</template>
+        </el-table-column>
+        <el-table-column label="发生时间" min-width="150" prop="happenDate" show-overflow-tooltip align="center" />
+        <el-table-column label="创建人" min-width="130" prop="creatorName" show-overflow-tooltip align="center" />
+      </el-table>
+    </div>
   </div>
 </template>
 <script>
@@ -73,16 +54,33 @@ export default {
   components: {
     // searchHeader
   },
+  props: {
+    data: {
+      type: Array,
+      default: () => [],
+      required: true
+    }
+  },
   data() {
     return {
       table_loading: false,
-      dataList: [],
       priorityColors: ['#F56C6C', '#FF8952', '#F5E300', '#7ED321', '#61D3B8', '#69B3FF', '#BDBDBD']
     }
   },
   methods: {
     create() {
       console.log('新建')
+    },
+    gotoDetail(data) {
+      console.log(data)
+      // this.$router.push({ name: '质惠线上问题详情', query: { id: data.id }})
+      const { href } = this.$router.resolve({
+        name: '质惠线上问题详情',
+        query: {
+          id: data.id
+        }
+      })
+      window.open(href, '_blank')
     }
   }
 }
@@ -95,6 +93,20 @@ export default {
     padding: 16px 10px;
     background: #fff;
   }
+  .title {
+    &:hover {
+      color: #409eff;
+      cursor: pointer;
+    }
+  }
+  .div_priority {
+    width: 38px;
+    height: 24px;
+    line-height: 24px;
+    font-size: 14px;
+    color: #fff;
+    border-radius: 4px;
+  }
 }
 </style>
 

+ 38 - 1
src/views/projectManage/onlineproblem/component/mainTitle.vue

@@ -1,8 +1,24 @@
 <template>
   <div class="mainTitle">
     <div class="stylus-title">
-      <div>
+      <div class="titleBox">
         <span style="font-size: 22px;letter-spacing: 1px;font-weight: 600;color: #333b4a;padding-left: 15px;">{{ title }}</span>
+        <div class="radio">
+          <el-radio-group v-model="tabPosition" size="small" @change="changeTab">
+            <el-radio-button label="list" class="list">
+              <svg-icon
+                icon-class="list"
+                class="icon"
+                :style="nowTab === 'list' ? { color: '#fff' } : { 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' }" />
+              统计视图
+            </el-radio-button>
+          </el-radio-group>
+        </div>
       </div>
       <div v-if="btnText">
         <el-button type="primary" size="mini" @click="$emit('btn-handle')">{{ btnText }}</el-button>
@@ -24,11 +40,32 @@ export default {
       default: '',
       required: true
     }
+  },
+  data() {
+    return {
+      tabPosition: 'list',
+      nowTab: 'list'
+    }
+  },
+  methods: {
+    changeTab(e) {
+      this.nowTab = e
+      this.$emit('change-tab', e)
+    }
   }
 }
 </script>
 <style scoped lang="scss">
 .mainTitle {
+  .titleBox {
+    display: flex;
+    .radio {
+      margin-left: 18px;
+      :global(.el-radio-button__inner:hover) {
+        color: none;
+      }
+    }
+  }
   .dividerLine {
     margin: 10px 0;
     color: #eef0f5;

+ 19 - 35
src/views/projectManage/onlineproblem/create/component/base.vue

@@ -8,29 +8,11 @@
         :type="d.type"
         :option="d.option"
         :value="data[d.key]"
-        @onChange="(e) => onChange(d.key, e)"
-        @remoteMethod="(e) => remoteMethod(d.key, e)"
+        :requried="d.requried"
+        @onChange="(e) => $emit('onChange', d.key, e )"
+        @remoteMethod="(e) => remoteMethod(d.key, e, d.utilName)"
       />
     </div>
-    <!-- <div class="formLine Layout">
-      <formInput title="等级" :value="data.priority" @onChange="(e) => onChange('priority', e)" />
-      <formInput title="是否星辰花定级" :value="data.isGrading" @onChange="(e) => onChange('isGrading', e)" />
-    </div>
-    <div class="formLine Layout">
-      <formInput title="发生日期" type="date" :value="data.happenDate" @onChange="(e) => onChange('happenDate', e)" />
-      <formInput title="责任团队" :value="data.teamId" @onChange="(e) => onChange('teamId', e)" />
-    </div>
-    <div class="formLine Layout">
-      <formInput title="影响面" :value="data.influenceSurface" @onChange="(e) => onChange('influenceSurface', e)" />
-      <formInput title="影响描述" :value="data.influenceDesc" @onChange="(e) => onChange('influenceDesc', e)" />
-    </div>
-    <div class="formLine Layout">
-      <formInput title="闭环时长(分)" :value="data.closedLoopTime" @onChange="(e) => onChange('closedLoopTime', e)" />
-      <formInput title="SLA不可用时长(分)" :value="data.slaNotAvailableTime" @onChange="(e) => onChange('slaNotAvailableTime', e)" />
-    </div>
-    <div class="formLine">
-      <formInput title="描述" :value="data.desc" @onChange="(e) => onChange('desc', e)" />
-    </div> -->
   </div>
 </template>
 <script>
@@ -55,20 +37,22 @@ export default {
     }
   },
   methods: {
-    onChange(key, value) {
-      console.log('onChange:', key, value)
-      this.$emit('onChange', { [key]: value })
-    },
-    async remoteMethod(key, q) {
-      console.log(key, q)
-      const res = await teamQueryTeamInfo({ teamName: q })
-      console.log(res)
-      this.renderBaseData.map(t => t.map(g => {
-        if (g.key === key) {
-          g.option = res.data
-        }
-      }))
-      console.log(this.renderBaseData)
+    // onChange(key, value) {
+    //   this.$emit('onChange', { [key]: value })
+    // },
+    async remoteMethod(key, q, utilName) {
+      if (utilName === 'getTeam') {
+        const res = await teamQueryTeamInfo({ teamName: q, bizId: this.$store.state.global.bizId })
+        this.renderBaseData.map(t => t.map(g => {
+          if (g.key === key) {
+            g.option = res.data.map(t => ({
+              ...t,
+              value: t.teamId,
+              label: t.teamName
+            }))
+          }
+        }))
+      }
     }
   }
 }

+ 198 - 2
src/views/projectManage/onlineproblem/create/component/makeBetterList.vue

@@ -1,3 +1,199 @@
 <template>
-  <span>11111</span>
-</template>
+  <div class="makeBetterWrap">
+    <div v-for="(item, index) in list" :key="index" class="list">
+      <div class="desc">
+        <span class="NO">{{ index + 1 }}</span>
+        <el-input
+          v-model="item.name"
+          class="input"
+          :size="size"
+          type="textarea"
+          :placeholder="`placeholdertextarea`"
+        />
+      </div>
+      <div class="formWrap">
+        <div v-for="(r, idx) in renderFromData" :key="idx" class="formLine" :class="r.length > 1 && 'Layout'">
+          <formInput
+            v-for="d in r"
+            :key="d.key"
+            :title="d.name"
+            :type="d.type"
+            :option="d.option"
+            :value="item[d.key]"
+            :requried="false"
+            :has-slot="d.hasSlot"
+            :styles="{ minWidth: '110px' }"
+            @onChange="(e) => onChange(d.key, e, index)"
+            @remoteMethod="(e) => remoteMethod(d.key, e, d.utilName)"
+          >
+            <div v-if="d.hasSlot" slot="option">
+              <el-option v-for="o in d.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>
+          </formInput>
+        </div>
+        <div class="progress formLine">
+          <span class="title">
+            进度
+          </span>
+          <input v-model="item.progress" class="number" type="number">
+          %
+          <span class="brandColor pointer" @click="item.progress='100'">
+            <i class="icon" :class="item.progress === '100' ? 'el-icon-success': 'el-icon-circle-check'" />
+            标记为已完成
+          </span>
+        </div>
+      </div>
+      <div class="delBtn">
+        <span class="brandColor pointer" @click="$emit('delHandle', index)">
+          <svg-icon icon-class="del" class="icon" />
+        </span>
+      </div>
+    </div>
+    <div class="addBtn">
+      <span class="brandColor pointer" @click="$emit('addHandle')">
+        <svg-icon icon-class="add" class="icon" />
+        新增改进项
+      </span>
+    </div>
+  </div>
+</template>
+<script>
+import formInput from '@/components/formInput'
+import { getPerson } from '@/api/onlineproblem'
+export default {
+  components: {
+    formInput
+  },
+  props: {
+    list: {
+      type: Array,
+      default: () => [{}],
+      requried: false
+    }
+  },
+  data() {
+    return {
+      size: 'small',
+      val: '',
+      data: {},
+      renderFromData: [
+        [{
+          name: '责任人',
+          key: 'leader',
+          type: 'remoteSelect',
+          utilName: 'getPerson',
+          multiple: false,
+          placeholder: '请选择责任人',
+          hasSlot: true,
+          default: '',
+          option: []
+        }, {
+          name: '计划完成时间',
+          key: 'finishTime',
+          type: 'date'
+        }]
+      ]
+    }
+  },
+  methods: {
+    async remoteMethod(key, q, utilName) {
+      if (utilName === 'getPerson') {
+        const res = await getPerson({ memberIDAP: q })
+        this.renderFromData.map(t => t.map(g => {
+          if (g.key === key) {
+            g.option = res.data.map(t => ({
+              ...t,
+              value: t.idap,
+              label: t.name
+            }))
+          }
+        }))
+      }
+    },
+    onChange(key, value, index) {
+      this.$emit('onChange', key, value, index)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.makeBetterWrap {
+  .brandColor {
+    color: #1890FF;
+  }
+  .pointer {
+    cursor: pointer;
+  }
+  .list{
+    position: relative;
+    margin-bottom: 18px;
+    .delBtn {
+      position: absolute;
+      top: 16px;
+      right: -30px;
+    }
+    .desc {
+      padding-left: 12px;
+      display: flex;
+      .NO {
+        display: inline-block;
+        width: 14px;
+        height: 14px;
+        line-height: 12px;
+        font-size: 12px;
+        text-align: center;
+        border: 1px solid #1890FF;
+        background: #1890FF;
+        border-radius: 50%;
+        margin-right: 5px;
+        color: #fff;
+      }
+      .input {
+        display: inline-block;
+      }
+    }
+    .formWrap {
+      padding-left: 16px;
+      .formLine {
+        margin-top: 20px;
+      }
+      .progress {
+        .title {
+          display: inline-block;
+          min-width: 110px;
+          padding-left: 12px;
+        }
+        .icon {
+          font-size: 12px;
+        }
+        .number {
+          background-color: #FFF;
+          border-radius: 4px;
+          border: 1px solid #DCDFE6;
+          color: #606266;
+          height: 20px;
+          line-height: 20px;
+          padding: 0 0 0 5px;
+          width: 44px;
+        }
+      }
+    }
+  }
+}
+.item-style {
+  display: flex;
+  justify-content: flex-start;
+  .item-detail {
+    min-width:100px;
+    color: #8492a6;
+    font-size: 13px;
+    overflow:hidden
+  }
+}
+</style>

+ 6 - 3
src/views/projectManage/onlineproblem/create/component/renderBase.js

@@ -4,7 +4,8 @@ const data = [
   [{
     name: '名称',
     key: 'title',
-    type: 'input'
+    type: 'input',
+    requried: true
   }],
   [{
     ...d.adv[0][0]
@@ -14,7 +15,8 @@ const data = [
     type: 'select',
     multiple: false,
     placeholder: '',
-    default: false,
+    value: false,
+    requried: true,
     option: [
       { value: false, label: '否' },
       { value: true, label: '是' }
@@ -23,7 +25,8 @@ const data = [
   [{
     name: '发生日期',
     key: 'happenDate',
-    type: 'date'
+    type: 'date',
+    requried: true
   }, {
     ...d.adv[0][1]
   }],

+ 45 - 10
src/views/projectManage/onlineproblem/create/index.vue

@@ -6,7 +6,7 @@
         <headTitle title="基础信息" />
       </header>
       <div class="content">
-        <baseBox :data="baseData" @onChange="(d) => change('baseData', d)" />
+        <baseBox :data="baseData" @onChange="(key, value) => change('baseData', key, value)" />
       </div>
       <header class="header">
         <headTitle title="复盘" icon="el-icon-link" :open-btn="true" @handle="linkHandle" />
@@ -27,20 +27,26 @@
         <headTitle title="改进项" />
       </header>
       <div class="content">
-        <makeBetterList />
+        <makeBetterList
+          :list="improvements"
+          @addHandle="addMakeBetterList"
+          @delHandle="delMakeBetterList"
+          @onChange="(key, value, index) => change('improvements', key, value, index)"
+        />
       </div>
     </div>
     <div class="control">
       <el-button size="small" @click="back">取消</el-button>
-      <el-button type="primary" size="small" @click="create()">
+      <el-button type="primary" size="small" @click="createHandle()">
         创建
       </el-button>
     </div>
-    <!-- 111111111create0
-    <span @click="back">{{ $route.query.id }}</span> -->
   </div>
 </template>
 <script>
+import {
+  create
+} from '@/api/onlineproblem'
 import mainTitle from '../component/mainTitle'
 import headTitle from '@/components/headTitle'
 import baseBox from './component/base'
@@ -59,7 +65,17 @@ export default {
     return {
       baseData: {},
       replayDesc: '',
-      improvements: [1, 2, 3]
+      improvements: [{
+        finishTime: '2020-01-12 11:11:11',
+        leader: 'renwu',
+        name: 'mingzi',
+        progress: 30
+      }, {
+        finishTime: '2020-01-12 11:11:11',
+        leader: 'renwu',
+        name: 'mingzi',
+        progress: 30
+      }]
     }
   },
   methods: {
@@ -67,15 +83,34 @@ export default {
       console.log('back')
       this.$router.push({ name: '线上问题 ', query: { id: 111 }})
     },
-    create() {
+    async createHandle() {
       console.log('create:', { ...this.baseData, replayDesc: this.replayDesc, improvements: this.improvements })
+      const res = await create({
+        ...this.baseData,
+        bizId: this.$store.state.global.bizId,
+        replayDesc: this.replayDesc,
+        improvements: this.improvements
+      })
+      console.log(res)
+      this.$router.push({ name: '线上问题 ' })
     },
     linkHandle() {
       console.log('link')
     },
-    change(type, data) {
-      this[type] = { ...this[type], ...data }
-      console.log(this[type])
+    addMakeBetterList() {
+      this.improvements.push({})
+    },
+    delMakeBetterList(index) {
+      this.improvements.splice(index, 1)
+    },
+    change(type, key, value, index) {
+      if (index !== undefined) {
+        const data = [...this[type]]
+        data[index][key] = value
+        this[type] = [...data]
+      } else {
+        this[type] = { ...this[type], ...{ [key]: value }}
+      }
     }
   }
 }

+ 243 - 0
src/views/projectManage/onlineproblem/detial/component/base.vue

@@ -0,0 +1,243 @@
+<template>
+  <div class="wb-base">
+    <el-form :inline="true" :model="data" class="demo-form-inline" label-position="left" label-width="150px">
+      <el-form-item label="等级:">
+        <over-click id="priority-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-select
+              v-model="data.priority"
+              :size="size"
+              clearable
+              filterable
+              placeholder="请选择等级"
+              @change="(e) => onChange('priority', e)"
+            >
+              <el-option v-for="o in priorityOption" :key="o.value" :label="o.label" :value="o.value" />
+            </el-select>
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.priorityName }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="是否星辰花定级:">
+        <over-click id="isGrading-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-select
+              v-model="data.isGrading"
+              :size="size"
+              clearable
+              filterable
+              placeholder="请选择"
+              @change="(e) => onChange('isGrading', e)"
+            >
+              <el-option label="是" :value="true" />
+              <el-option label="否" :value="false" />
+            </el-select>
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.isGrading ? '是' : '否' }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="发生日期:">
+        <over-click id="happenDate-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-date-picker
+              v-model="form_data.happenDate"
+              :size="size"
+              value-format="yyyy-MM-dd hh:mm:ss"
+              type="datetime"
+              placeholder="请选择日期"
+              style="width:194px"
+              @change="(e) => onChange('happenDate', e)"
+            />
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.happenDate }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="责任团队:">
+        <over-click id="teamId-select" @overMouse="changeArea">
+          <template slot="active">
+            <selectTeam
+              :value="data.teamName"
+              :model="form_data.teamName"
+              @onChange="(e) => onChange('teamId', e)"
+            />
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.teamName }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="影响面:">
+        <over-click id="influenceSurface-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-select
+              v-model="form_data.influenceSurface"
+              :size="size"
+              :multiple="true"
+              clearable
+              filterable
+              placeholder="请选择等级"
+              @change="(e) => onChange('influenceSurface', e)"
+            >
+              <el-option v-for="o in influenceSurfaceOption" :key="o.value" :label="o.label" :value="o.value" />
+            </el-select>
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.influenceSurface }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="影响面描述:">
+        <over-click id="influenceDesc-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-input
+              v-model="form_data.influenceDesc"
+              size="small"
+              clearable
+              style="width:100% !important;"
+              placeholder="请输入"
+              @change="(e) => onChange('influenceDesc', e)"
+            />
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.influenceDesc }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="闭环时常(分):">
+        <over-click id="closedLoopTime-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-input-number
+              v-model="form_data.closedLoopTime"
+              :size="size"
+              style="width:194px"
+              placeholder="请填写闭环时长"
+              @change="(e) => onChange('closedLoopTime', e)"
+            />
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.closedLoopTime }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="SLA不可用时长(分):">
+        <over-click id="slaNotAvailableTime-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-input-number
+              v-model="form_data.slaNotAvailableTime"
+              :size="size"
+              style="width:194px"
+              placeholder="请填写闭环时长"
+              @change="(e) => onChange('slaNotAvailableTime', e)"
+            />
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.slaNotAvailableTime }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+      <el-form-item label="描述:" class="width100">
+        <over-click id="desc-select" @overMouse="changeArea">
+          <template slot="active">
+            <el-input
+              v-model="form_data.desc"
+              :size="size"
+              type="textarea"
+              placeholder="请填写描述"
+              @change="(e) => onChange('desc', e)"
+            />
+          </template>
+          <template slot="overMouse">
+            <span>{{ data.desc }}</span>
+          </template>
+        </over-click>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+<script>
+import selectTeam from '@/components/select/selectTeam'
+import overClick from '@/components/click/overClick'
+export default {
+  components: {
+    overClick,
+    selectTeam
+  },
+  props: {
+    data: {
+      type: Object,
+      default: () => {},
+      required: true
+    }
+  },
+  data() {
+    return {
+      size: 'small',
+      form_data: this.data,
+      // data: this.data,
+      priorityOption: [
+        { value: '0', label: 'P0' },
+        { value: '1', label: 'P1' },
+        { value: '2', label: 'P2' },
+        { value: '3', label: 'P3' },
+        { value: '4', label: 'P4' },
+        { value: '5', label: 'P5' },
+        { value: '6', label: 'P6' },
+        { value: '7', label: '未定级' }
+      ],
+      // 影响面
+      influenceSurfaceOption: [
+        { value: 0, label: '用户体验' },
+        { value: 1, label: '客服进线' },
+        { value: 2, label: '资损' },
+        { value: 3, label: '订单' },
+        { value: 4, label: '其他' }
+      ]
+    }
+  },
+  mounted() {
+  },
+  methods: {
+    onChange(key, value) {
+      console.log(value)
+      console.log(this.form_data, this.data)
+      if (key === 'teamId') {
+        this.form_data[key] = value
+      }
+      // fromdata更新上去在换新的data
+      this.data[key] = value
+    },
+    changeArea() {
+      // 发送请求
+      console.log(this.form_data)
+    }
+  }
+}
+</script>
+<style lang="scss">
+.wb-base {
+  .demo-form-inline {
+    .el-form-item {
+      width: 50%;
+      margin-right: 0;
+      margin-bottom: 1px;
+    }
+    .width100 {
+      width: 100%;
+      .el-form-item__content {
+        width: calc(100% - 150px);
+      }
+    }
+    >>>.el-form-item__content {
+      width: calc(100% - 125px);
+      color: #333333;
+      font-size: 14px;
+    }
+  }
+}
+</style>

+ 92 - 0
src/views/projectManage/onlineproblem/detial/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <div class="op-detial">
+    <div class="content headerH1">
+      <div>
+        {{ form_data.title }}
+      </div>
+      <i class="el-icon-delete icon" />
+    </div>
+    <div class="content base">
+      <baseContent :data="form_data" />
+    </div>
+    <div class="content replay">
+      <header class="headerH2">
+        <headTitle title="复盘" icon="el-icon-link" :open-btn="true" @handle="linkHandle" />
+      </header>
+      <div>
+        <text-area
+          :id="'pro-desc'"
+          :value.sync="form_data.replayDesc"
+          :empty-text="'点击'"
+          :input-button="'添加复盘内容'"
+          :styles="{ padding: '12px 0 20px 0' }"
+          @change="changeReplay"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { getDetial } from '@/api/onlineproblem'
+import baseContent from './component/base'
+import headTitle from '@/components/headTitle'
+import textArea from '@/components/input/textArea' // 富文本
+import 'tinymce/plugins/table'// 插入表格插件
+export default {
+  components: {
+    baseContent,
+    textArea,
+    headTitle
+  },
+  data() {
+    return {
+      id: this.$route.query.id,
+      // data: '',
+      form_data: { pm: 'wenbobowen', replayDesc: '' }
+    }
+  },
+  mounted() {
+    this.search()
+  },
+  methods: {
+    async search() {
+      const res = await getDetial({ id: this.id })
+      console.log(res)
+      this.form_data = res.data
+    },
+    linkHandle() {
+
+    },
+    changeReplay() {
+
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.op-detial {
+  padding: 0 10px 10px 10px;
+  .content {
+    background-color: #fff;
+    border-radius: 4px;
+    overflow: hidden;
+    margin-bottom: 10px;
+    padding: 16px 20px;
+  }
+  .headerH1 {
+    color: #444;
+    font-size: 22px;
+    font-weight: 600;
+    display: flex;
+    justify-content: space-between;
+    .icon {
+      font-size: 20px;
+      color: #6f7c93;
+      line-height: 33px;
+    }
+  }
+  .headerH2 {
+    margin-top: 5px;
+  }
+}
+</style>

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

@@ -1,8 +1,8 @@
 <template>
   <div class="onlineproblem">
-    <Header />
+    <Header @change-tab="changeTab" @listChange="listChange" />
     <div class="content">
-      <list />
+      <list :data="dataList" />
     </div>
   </div>
 </template>
@@ -13,6 +13,21 @@ export default {
   components: {
     Header,
     list
+  },
+  data() {
+    return {
+      nowTab: 'list',
+      dataList: []
+    }
+  },
+  methods: {
+    changeTab(e) {
+      console.log(e)
+      this.nowTab = e
+    },
+    listChange(data) {
+      this.dataList = data.list || []
+    }
   }
 }
 </script>
@@ -20,7 +35,9 @@ export default {
 .onlineproblem {
   padding: 0 10px 10px 10px;
   .content {
-    // margin: 0 10px 10px 10px;
+    background-color: #fff;
+    border-radius: 4px;
+    overflow: hidden;
   }
 }
 </style>

+ 0 - 1
src/views/projectManage/taskList/taskIndex.vue

@@ -382,7 +382,6 @@ export default {
       }
       taskList(this.form_task).then(res => {
         this.task_table = res.data
-        console.log(JSON.stringify(res.data))
         this.total = res.total
         this.table_loading = false
       })