فهرست منبع

Merge branch 'http_mock' of git.xiaojukeji.com:pu_qa_tool/thoth-frontend into http_mock

qinzhipeng_v@didiglobal.com 4 سال پیش
والد
کامیت
0a127d91e6
37فایلهای تغییر یافته به همراه2632 افزوده شده و 1177 حذف شده
  1. 0 0
      public/tinymce/skins/ui/oxide-dark/content.inline.min.css
  2. 0 0
      public/tinymce/skins/ui/oxide-dark/content.min.css
  3. 0 0
      public/tinymce/skins/ui/oxide/content.inline.min.css
  4. 0 0
      public/tinymce/skins/ui/oxide/content.min.css
  5. 0 0
      public/tinymce/skins/ui/oxide/skin.min.css
  6. 8 0
      src/api/dataMarket.js
  7. 11 0
      src/api/qualityMonthlyReport/index.js
  8. 1 1
      src/apiConfig/requestIP.js
  9. 6 0
      src/components/input/normalArea.vue
  10. 3 3
      src/components/newLayout/components/baseData.js
  11. 2 2
      src/components/newLayout/components/menu.vue
  12. 6 3
      src/components/select/searchPeople.vue
  13. 2 2
      src/components/select/selectTeam.vue
  14. 7 0
      src/router/newRouter.js
  15. 2 0
      src/store/index.js
  16. 510 0
      src/store/modules/monthlyReport/baseMixin/actions.js
  17. 544 0
      src/store/modules/monthlyReport/baseMixin/mutations.js
  18. 44 0
      src/store/modules/monthlyReport/baseMixin/state.js
  19. 6 1063
      src/store/modules/monthlyReport/edit/index.js
  20. 17 0
      src/store/modules/monthlyReport/read/index.js
  21. 19 6
      src/store/modules/monthlyReport/utils/index.js
  22. 62 0
      src/views/dataBigManage/components/drawerModal/drawerModalData.js
  23. 41 5
      src/views/dataBigManage/components/drawerModal/index.vue
  24. 52 10
      src/views/dataBigManage/components/efficiencyModule/index.vue
  25. 3 2
      src/views/dataBigManage/index.vue
  26. 1 1
      src/views/home/index.vue
  27. 234 44
      src/views/monthlyReport/childrenPage/editReport/components/MrTable/Analysis.vue
  28. 4 1
      src/views/monthlyReport/childrenPage/editReport/components/MrTable/Hold.vue
  29. 10 0
      src/views/monthlyReport/childrenPage/editReport/components/MrTable/TableExpandRow.vue
  30. 394 0
      src/views/monthlyReport/childrenPage/editReport/components/MrTable/TableExpandRowList.vue
  31. 77 15
      src/views/monthlyReport/childrenPage/editReport/components/MrTable/index.vue
  32. 3 1
      src/views/monthlyReport/childrenPage/editReport/components/VarText.vue
  33. 0 1
      src/views/monthlyReport/childrenPage/editReport/components/core.vue
  34. 12 9
      src/views/monthlyReport/childrenPage/editReport/index.vue
  35. 466 0
      src/views/monthlyReport/childrenPage/readReport/index.vue
  36. 70 8
      src/views/monthlyReport/index.vue
  37. 15 0
      src/views/monthlyReport/style.less

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
public/tinymce/skins/ui/oxide-dark/content.inline.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
public/tinymce/skins/ui/oxide-dark/content.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
public/tinymce/skins/ui/oxide/content.inline.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
public/tinymce/skins/ui/oxide/content.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
public/tinymce/skins/ui/oxide/skin.min.css


+ 8 - 0
src/api/dataMarket.js

@@ -126,6 +126,14 @@ export function getRequireAvgData(data) {
     data
   })
 }
+// 需求平均交付周期:/dataMarket/efficiency/getRequireAvgData
+export function getTaskPeopleData(data) {
+  return request({
+    url: TeamManagement + '/dataMarket/efficiency/getTaskPeopleDataDetail',
+    method: 'post',
+    data
+  })
+}
 // 任务平均交付周期:/dataMarket/efficiency/getTaskData
 export function getTaskData(data) {
   return request({

+ 11 - 0
src/api/qualityMonthlyReport/index.js

@@ -194,3 +194,14 @@ export function getMonthlyReportVersion(id) {
   })
 }
 /* E 月报v2 */
+
+// 下载月报pdf
+export function downloadMonthlyReport(params) {
+  return request({
+    url: TeamManagement + `/monthlyReport/downloadMonthlyReport`,
+    timeout: '100000',
+    method: 'get',
+    responseType: 'blob',
+    params
+  })
+}

+ 1 - 1
src/apiConfig/requestIP.js

@@ -21,7 +21,7 @@ if (location.host.indexOf('localhost') < 0) {
     envTag = 'online'
     envUrl = 'http://zhihui.xiaojukeji.com/zhihui_env/'
     toolsUrl = 'http://zhihui.xiaojukeji.com/tools/'
-    playBackUrl = 'http://zhihui-pre.intra.xiaojukeji.com/playback/'
+    playBackUrl = 'http://zhihui.xiaojukeji.com/playback/'
   }
 }
 

+ 6 - 0
src/components/input/normalArea.vue

@@ -50,6 +50,11 @@ export default {
       default: '',
       required: false
     },
+    defaultPlaceholder: {
+      type: String,
+      default: '',
+      required: false
+    },
     height: {
       type: Number,
       default: 200,
@@ -94,6 +99,7 @@ export default {
         menubar: false, // 隐藏最上方menu
         fontsize_formats: '14px 16px 18px 20px 24px 26px 28px 30px 32px 36px', // 字体大小
         file_picker_types: 'image',
+        placeholder: this.defaultPlaceholder,
         images_upload_credentials: true,
         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',

+ 3 - 3
src/components/newLayout/components/baseData.js

@@ -145,9 +145,9 @@ export const envUrl = {
   playback: {
     name: '流量回放',
     path: {
-      dev: 'http://zhihui-test.intra.xiaojukeji.com/zhihui_playback/',
-      pre: 'http://zhihui-pre.intra.xiaojukeji.com/zhihui_playback/',
-      prod: 'http://zhihui.xiaojukeji.com/zhihui_playback/'
+      dev: 'http://zhihui-test.intra.xiaojukeji.com/playback/',
+      pre: 'http://zhihui-pre.intra.xiaojukeji.com/playback/',
+      prod: 'http://zhihui.xiaojukeji.com/playback/'
     }
   },
   tools: {

+ 2 - 2
src/components/newLayout/components/menu.vue

@@ -3,9 +3,9 @@
     <el-popover placement="right-end" trigger="hover" width="400" :open-delay="200">
       <div class="menu-wrapper">
         <div class="children-menu-wrapper borderBottom normal">
-          <div v-for="(elm, index) in [...menuBaseData].splice(0, 3)" :key="elm.key">
+          <div v-for="(elm, index) in menuBaseData" :key="elm.key">
             <div
-              v-if="index < 2"
+              v-if="index < 3"
               class="title"
               :class="{ active: active === elm.key }"
               @click="switchProjects(elm)"

+ 6 - 3
src/components/select/searchPeople.vue

@@ -104,9 +104,8 @@ export default {
   methods: {
     remoteMethod: _.debounce(function(query, initMore = false) {
       query !== '' ? this.getMember(query, initMore) : this.options = []
-    }, 2000),
+    }, 1500),
     searchPeople(query, initMore = false) {
-      this.loading = true
       this.remoteMethod(query, initMore)
     },
     initMore(arr) { // 当多人时候,对数组每一个人员进行搜索
@@ -117,6 +116,7 @@ export default {
       }
     },
     async getMember(query, initMore = false) {
+      this.loading = true
       let res = null
       if (typeof query === 'string') {
         res = await memberQueryMemberInfoByIDAPorName({ memberIDAP: query })
@@ -126,7 +126,9 @@ export default {
       if (res.data === null) {
         return
       }
-      this.loading = false
+      setTimeout(() => {
+        this.loading = false
+      }, 300)
       // 去重
       this.arrayNonRepeatfy(res.data, initMore)
       // this.options = res.data
@@ -139,6 +141,7 @@ export default {
     arrayNonRepeatfy(data, initMore = false) {
       // this.options = initMore ? data.map(e => e) : Array.from(new Set([...this.options, ...data]))
       this.options = data.map(e => e)
+      this.loading = false
       // console.log(this.options, data, 139)
       // const weakMap = new Map()
       // for (const item of data) {

+ 2 - 2
src/components/select/selectTeam.vue

@@ -27,12 +27,12 @@ export default {
   props: {
     value: {
       type: [String, Number, Array, Object],
-      default: '123',
+      default: '',
       requried: false
     },
     name: {
       type: [String, Number, Array, Object],
-      default: '232',
+      default: '',
       requried: false
     },
     bizIdFlag: {

+ 7 - 0
src/router/newRouter.js

@@ -391,6 +391,13 @@ const layout = [
         component: () => import('@/views/monthlyReport/childrenPage/editReport/index'),
         meta: { title: '质量月报编辑' }
       },
+      // 归档月报
+      {
+        path: 'read',
+        name: '质量月报归档',
+        component: () => import('@/views/monthlyReport/childrenPage/readReport/index'),
+        meta: { title: '质量月报归档' }
+      },
       {
         path: 'set',
         name: '质量月报设置',

+ 2 - 0
src/store/index.js

@@ -7,6 +7,7 @@ import data from './modules/data'
 import global from './modules/global'
 import project from './modules/project'
 import monthlyReportEdit from './modules/monthlyReport/edit'
+import monthlyReportRead from './modules/monthlyReport/read'
 import monthlyReportSeting from './modules/monthlyReport/setting'
 
 Vue.use(Vuex)
@@ -19,6 +20,7 @@ const store = new Vuex.Store({
     global,
     project,
     monthlyReportEdit,
+    monthlyReportRead,
     monthlyReportSeting
   },
   getters

+ 510 - 0
src/store/modules/monthlyReport/baseMixin/actions.js

@@ -0,0 +1,510 @@
+import {
+  getMonthlyReport,
+  updateMonthlyReport,
+  delMonthlyReport,
+  getAllSubReportCatalog,
+  getSubReport,
+  // getReportDependence,
+  getDeptArch,
+  sendConfirm,
+  returnReport,
+  sendSubConfirm,
+  publishReport,
+  getSubReportInfo,
+  updateSubReport,
+  pullDataAgain,
+  pullSubTitle
+} from '@/api/qualityMonthlyReport/edit'
+// import { memberQueryMemberInfoByIDAPorName } from '@/api/projectIndex'
+import { getAvaliableInfo, getMonthlyReportVersion } from '@/api/qualityMonthlyReport'
+import {
+  reportDataBack,
+  setTabActive,
+  readOnlyTableArrToObj,
+  arrToObj,
+  objToArr,
+  setTableHeader
+} from '../utils/index.js'
+import { uuid10 } from '@/utils'
+import { message } from '@/utils/mesDebounce'
+import _ from 'lodash'
+import { getListPerson } from '@/api/onlineproblem'
+
+export default {
+  // 月报数据获取
+  async initPageData(
+    { commit, state, dispatch },
+    { id, subReportId, subActive }
+  ) {
+    dispatch('setSubReportInfo', id)
+    const { pageType } = state
+    if (
+      pageType === 'readAll' ||
+      pageType === 'read' ||
+      pageType === 'edit'
+    ) {
+      commit('INIT_PAGE_DATA')
+      dispatch('getSubReportData', {
+        id,
+        subReportId,
+        tabsActive: `tab_${subActive || '上月问题跟进'}`
+      })
+    } else {
+      const res = await getMonthlyReport(id)
+      // 设置月报子标题
+      commit('SET_SUB_TITLE', {
+        id: id
+      })
+      if (res.code === 200 && res.data) {
+        commit('INIT_PAGE_DATA', { ...res.data })
+        commit('INIT_TAB_PAGE_DATA', subActive && `tab_${subActive}`)
+        commit('SET_LOADING', false)
+        dispatch('initPeople')
+      }
+    }
+  },
+  // 页面切换 TAB_ACTIVE_CHANGE
+  tabActiveChange({ commit, state, dispatch }, { id, tabsActive }) {
+    const { pageType } = state
+    if (pageType === 'editAll') {
+      return commit('TAB_ACTIVE_CHANGE', tabsActive)
+    }
+    if (pageType === 'readAll') {
+      dispatch('getSubReportData', { id, tabsActive })
+    }
+  },
+  // 获取查看月报数据
+  async getSubReportData({ dispatch, commit, state }, { id, subReportId, tabsActive }) {
+    const { pageType } = state
+    let params = {}
+    const method =
+      pageType === 'readAll' ? getAllSubReportCatalog : getSubReport
+    if (pageType === 'read' || pageType === 'edit') {
+      params = {
+        subReportId
+      }
+    }
+    if (pageType === 'readAll') {
+      // state.pageDate = {
+      //   status: 10
+      // }
+      params = {
+        reportId: id,
+        catalogTitle: setTabActive('tab_', tabsActive)
+      }
+    }
+    const res = await method(params)
+    if (res.code === 200) {
+      // 单个月报与完整月报数据梳理
+      if (pageType === 'read' || pageType === 'edit') {
+        commit('SET_CLIENT_TYPE_LIST', res.data.dependence.clientType)
+        // commit('SET_SELECT_ENUM', res.data.dependence.deptArch.children)
+        commit('SET_PAGE_DATA', res.data)
+      }
+      // console.log(res)
+      if (pageType === 'readAll' && params.catalogTitle.search(/服务端详情|客户端详情/) > -1) {
+        res.data.splice(0, 0, { depth: 1, fromUser: false, hiddenAncestor: null, isVisible: true, subTitles: null, title: '整体概览', type: 'Head1', content: [{ type: 'overallOverviewo' }] })
+        // console.log(params)
+      }
+      commit('SET_TAB_PAGE_DATA', {
+        data:
+          pageType === 'readAll' ? res.data : res.data.reportCatalog.children,
+        id,
+        tabsActive
+      })
+      commit('SET_LOADING', false)
+      // 设置月报子标题
+      setTimeout(() => {
+        commit('SET_SUB_TITLE', {
+          id: pageType.search(/All/) > -1 ? `${id}` : `${res.data.parentId}`,
+          name: pageType.search(/All/) > -1 ? '' : res.data.reportName
+        })
+        dispatch('initPeople')
+      }, 700)
+    }
+  },
+  // 子月报更新
+  async upDateSubReport({ state }, callback) {
+    const params = _.cloneDeep(state.pageDate)
+    params.reportCatalog = {
+      children: _.cloneDeep(state.tabPageData.children),
+      content: [],
+      depth: 0,
+      fromUser: false,
+      hiddenAncestor: null,
+      isVisible: true,
+      subTitles: null,
+      title: params.reportName,
+      type: 'Tag'
+    }
+    params.reportCatalog = reportDataBack(params.reportCatalog)
+    if (state.saveAsTargetList.length) {
+      params.saveAsTargetList = _.cloneDeep(state.saveAsTargetList)
+    }
+    params.dependence = null
+    const res = await updateSubReport(params)
+    if (res.code === 200) {
+      callback()
+    }
+  },
+  // 月报更新
+  async upDateReport({ dispatch, state }, callback) {
+    const params = _.cloneDeep(state.pageDate)
+    const tabPageData = _.cloneDeep(state.tabPageData)
+    const tabsActive = setTabActive('tab_', state.tabsActive)
+    params.subReports = state.reportData.map((elm) => {
+      // 将上一个被选中的页签数据赋值给源数据(reportData)
+      if (`${elm.id}` === tabsActive) {
+        return {
+          ...elm,
+          dependence: null,
+          reportCatalog: { ...reportDataBack({ ...tabPageData }) }
+        }
+      }
+      return elm
+    })
+    // 转换数据结构
+    const res = await updateMonthlyReport(params)
+    if (res.code === 200) {
+      state.pageDate.isDelete = false
+      callback()
+    }
+  },
+  // 获取部门数据
+  async setSelectEnum({ commit }, key) {
+    const depth = JSON.parse(window.localStorage.getItem('depth'))
+    if (!depth || key === 'init') {
+      const res = await getDeptArch()
+      if (res.code === 200) {
+        window.localStorage.setItem('depth', JSON.stringify(res.data.children))
+        commit('SET_SELECT_ENUM', res.data.children)
+      }
+    } else {
+      commit('SET_SELECT_ENUM', depth)
+    }
+  },
+  // 删除月报
+  async deleteReport(
+    { commit, state, context },
+    { key, callback, isMsg = true }
+  ) {
+    const res = await delMonthlyReport(state.pageDate.id)
+    if (res.code === 200) {
+      if (isMsg) {
+        message.success('删除成功!')
+      }
+      callback && callback()
+    }
+  },
+  // 月报发送确认
+  async sendReport({ commit, state, context }, { id, callback }) {
+    const params = _.cloneDeep(state.pageDate)
+    const tabPageData = _.cloneDeep(state.tabPageData)
+    const tabsActive = setTabActive('tab_', state.tabsActive)
+    params.subReports = state.reportData.map((elm) => {
+      // 将上一个被选中的页签数据赋值给源数据(reportData)
+      if (`${elm.id}` === tabsActive) {
+        return {
+          ...elm,
+          dependence: null,
+          reportCatalog: { ...reportDataBack({ ...tabPageData }) }
+        }
+      }
+      return elm
+    })
+    const res = await sendConfirm({
+      ...params,
+      id
+    })
+    if (res.code === 200) {
+      message.success('发送成功!')
+      callback()
+    }
+  },
+  // 月报发布
+  async publishAllReport({ commit, state, context }, { id, callback }) {
+    const res = await publishReport({
+      id
+    })
+    if (res.code === 200) {
+      message.success('发布成功!')
+      callback()
+    }
+  },
+  // 月报确认
+  async confirmReport({ state }, { id, callback }) {
+    const res = await sendSubConfirm({
+      subReportId: id
+    })
+    if (res.code === 200) {
+      callback()
+    }
+  },
+  // 月报回退
+  async returnReport({ commit, state, context }, { data, callback }) {
+    const res = await returnReport(data)
+    if (res.code === 200) {
+      callback()
+    }
+  },
+  // 获取用户月报操作区域权限
+  async getUserPermission({ commit }) {
+    const res = await getAvaliableInfo()
+    if (res.code === 200) {
+      commit('GET_USER_PERMISSION', res.data)
+    }
+  },
+  // 获取子月报列表数据
+  async setSubReportInfo({ commit }, id) {
+    const res = await getSubReportInfo(id)
+    if (res.code === 200) {
+      commit('SET_REPORT_INFO', res.data)
+    }
+  },
+  // 重新拉取数据
+  async refreshReport(
+    { commit, state },
+    { domKey, title, subReportId, callback, errorback }
+  ) {
+    const tabPageData = _.cloneDeep(state.tabPageData)
+    // console.log('refreshReport', domKey, title)
+    const [tabKey, subTabKey] = state.subTabsActive
+    const tabDataObj = {
+      tabKey: '',
+      subTabKey: ''
+    }
+    const setValue = (item, key, value) => {
+      if (item.domKey === value) {
+        tabDataObj[key] = item
+      }
+    }
+    const find = (arr) => {
+      arr &&
+        arr.length &&
+        arr.forEach((elm) => {
+          setValue(elm, 'tabKey', tabKey)
+          setValue(elm, 'subTabKey', subTabKey)
+          if (elm.content && elm.content.length) {
+            elm.content.forEach((item) => {
+              setValue(elm, 'tabKey', tabKey)
+              setValue(elm, 'subTabKey', subTabKey)
+            })
+          }
+          if (elm.children && elm.children.length) {
+            find(elm.children)
+          }
+        })
+    }
+    const params = {
+      subReportId: '',
+      catalogTitle: title,
+      isServer: true,
+      clientType: ''
+    }
+    if (title !== '上月问题跟进') {
+      find(tabPageData.children)
+      if (tabDataObj.tabKey.title) {
+        params.isServer = tabDataObj.tabKey.title === '服务端'
+      }
+      if (!params.isServer) {
+        params.clientType = tabDataObj.subTabKey.title
+      }
+    }
+    if (state.pageType.search(/All/) > -1) {
+      // console.log(state, setTabActive('tab_', state.tabsActive))
+      params.subReportId = setTabActive('tab_', state.tabsActive)
+    }
+    if (state.pageType === 'edit') {
+      params.subReportId = subReportId
+    }
+    // console.log(params)
+    /**
+     * 线上问题、
+     */
+    const res = await pullDataAgain(params)
+    // console.log(res)
+    if (res.code === 200 && res.data) {
+      if (title !== '上月问题跟进' && title !== '线上问题') {
+        if (res.data.type.search(/Table|TableAndRichText/) > -1) {
+          setTableHeader(res.data.tableHeaders)
+          res.data.tableRows = arrToObj(
+            res.data.tableRows,
+            res.data.tableHeaders
+          )
+        }
+      }
+      if (title.search(/线下缺陷/) > -1) {
+        setTableHeader(res.data.content[0].tableHeaders)
+        res.data.content[0].tableRows = readOnlyTableArrToObj(
+          res.data.content[0].tableRows,
+          res.data.content[0].tableHeaders
+        )
+      }
+      if (title.search(/上月问题跟进|发布&回滚|线上问题|延期|提测打回\/发版撤回|提测打回\/准出不通过/) > -1) {
+        const contentIndex = title === '线上问题' ? 1 : 0
+        // console.log(res.data.content, 926)
+        setTableHeader(res.data.content[contentIndex].tableHeaders)
+        res.data.content[contentIndex].tableRows = arrToObj(
+          res.data.content[contentIndex].tableRows,
+          res.data.content[contentIndex].tableHeaders
+        ).newObj
+      }
+      const setDomData = (arr) => {
+        arr &&
+        arr.length &&
+        arr.forEach((elm) => {
+          const newDomKey = uuid10(4)
+          if (elm.domKey === domKey) {
+            if (title.search(/上月问题跟进/) > -1) {
+              elm.content = [{ ...res.data.content[0], domKey: newDomKey }]
+            } else if (title.search(/线上问题/) > -1) {
+              const value = `${elm.content[0].value || ''}`
+              elm.subTitles = _.cloneDeep(res.data.subTitles)
+              elm.content = _.cloneDeep(res.data.content)
+              elm.content[0].value = value
+              elm.content[1].domKey = newDomKey
+            } else if (title.search(/线下缺陷/) > -1) {
+              elm.content[0] = _.cloneDeep(res.data.content[0])
+              elm.content[0].domKey = newDomKey
+              elm.subTitles = [...res.data.subTitles]
+            } else if (title.search(/发布&回滚/) > -1) {
+              const value = `${elm.content[0].value || ''}`
+              elm.content = [{ ...res.data.content[0], value, domKey: newDomKey }]
+              elm.subTitles = [...res.data.subTitles]
+            } else {
+              elm.content = [{ ...res.data.content[0], domKey: newDomKey }]
+            }
+            state.isLoading = [newDomKey]
+          }
+          if (elm.children && elm.children.length) {
+            setDomData(elm.children)
+          }
+        })
+      }
+      setDomData(tabPageData.children)
+      state.tabPageData = tabPageData
+      if (res.code === 200) {
+        callback && callback()
+      }
+    } else {
+      errorback && errorback()
+    }
+  },
+  // 根据月报版本,调整页面执行逻辑
+  async  setMonthlyReportPageVersion({ commit, state }, { self }) {
+    const { query, path } = self.$route
+    if (query && JSON.stringify(query) !== '{}') {
+      const res = await getMonthlyReportVersion(self.$route.query.reportId)
+      if (res.code === 200 && res.data) {
+        const { version } = res.data
+        if (version && version !== 'v1' && path.indexOf(`_${version}`) < 0) {
+          self.$router.push({ path: `${self.$route.path.replace(/_.*$/, '')}_${version}`, query })
+        }
+      }
+    }
+  },
+  // 人员数据初始化
+  initPeople({ commit, state }) {
+    if (state.timeout !== null) {
+      clearTimeout(state.timeout)
+    }
+    state.timeout = setTimeout(async() => {
+      const res = await getListPerson({ memberIDAPs: state.peopleLists })
+      if (res.code === 200 && res.data && res.data.length) {
+        const userNames = {}
+        res.data.forEach(elm => {
+          const { idap, name } = elm
+          userNames[idap] = name
+        })
+        state.userNames = userNames
+      }
+    }, 100)
+  },
+  // 重新拉取线上问题的 SubTitle,只在tableData数据变化时更新
+  async pullOnlineQuestion({ state }, { domKey, route }) {
+    // 获取数据
+    let baseData = {}
+    let { subReportId } = route.query
+    const { pageType } = route.query
+    const [tabKey, subTabKey] = state.subTabsActive
+    // 查询
+    if (!subReportId) {
+      if (pageType !== 'readAll') {
+        subReportId = state.tabsActive.replace(/tab_/, '')
+      }
+      if (pageType === 'readAll') {
+        let tabName = ''
+        console.log(tabName)
+        // 找到当前 domkey 对应的业务线名称
+        state.tabPageData.children.forEach(elm => {
+          elm.children && elm.children.forEach(item => {
+            if (item.domKey === domKey && !tabName) {
+              tabName = elm.title
+            }
+          })
+        })
+        // 根据找到的业务线名称查询业务线ID
+        state.subReportInfo && state.subReportInfo.length && state.subReportInfo.forEach(elm => {
+          if (elm.reportName === tabName) {
+            subReportId = elm.id
+          }
+        })
+      }
+    }
+    //
+    const tabDataObj = {
+      tabKey: '',
+      subTabKey: ''
+    }
+    const setValue = (item, key, value) => {
+      if (item.domKey === value) {
+        tabDataObj[key] = item
+      }
+    }
+    const find = (arr) => {
+      arr &&
+        arr.length &&
+        arr.forEach((elm) => {
+          setValue(elm, 'tabKey', tabKey)
+          setValue(elm, 'subTabKey', subTabKey)
+          if (elm.domKey === domKey) {
+            baseData = _.cloneDeep(elm)
+          }
+          if (elm.content && elm.content.length) {
+            find(elm.content)
+          }
+          if (elm.children && elm.children.length) {
+            find(elm.children)
+          }
+        })
+    }
+    find(state.tabPageData.children)
+    // 转换数据
+    const tableRows = objToArr(baseData.content[1].tableRows, baseData.content[1].tableHeaders)
+    const res = await pullSubTitle({
+      subReportId,
+      catalogTitle: '线上问题',
+      isServer: tabDataObj.tabKey.title ? tabDataObj.tabKey.title === '服务端' : true,
+      tableRows
+    })
+    // 覆盖数据
+    const setSubTitle = (arr) => {
+      arr &&
+        arr.length &&
+        arr.forEach((elm) => {
+          if (elm.domKey === domKey) {
+            elm.subTitles = res.data
+          }
+          if (elm.content && elm.content.length) {
+            setSubTitle(elm.content)
+          }
+          if (elm.children && elm.children.length) {
+            setSubTitle(elm.children)
+          }
+        })
+    }
+    const tabPageData = { ...state.tabPageData }
+    setSubTitle(tabPageData.children)
+    state.tabPageData = { ...tabPageData }
+  }
+}

+ 544 - 0
src/store/modules/monthlyReport/baseMixin/mutations.js

@@ -0,0 +1,544 @@
+import {
+  reportDataBack,
+  setReportData,
+  setTabActive,
+  setDeptArch,
+  setIndexTitle,
+  objToArr
+} from '../utils/index.js'
+import { uuid10 } from '@/utils'
+import _ from 'lodash'
+
+export default {
+  // 页面基础数据赋值
+  INIT_PAGE_DATA(state, params) {
+    const { pageType } = state
+    if (pageType === 'read' || pageType === 'edit') return
+    if (pageType === 'readAll') {
+      // 设置tabs数据
+      state.tabsList = state.tabsList.map((elm) => ({
+        label: elm,
+        name: `tab_${elm}`
+      }))
+      state.tabsActive = 'tab_上月问题跟进'
+      return
+    }
+    state.pageDate = { ...params }
+    delete state.pageDate.subReports
+    // state.subTitle = state.pageDate.reportName
+    const subReports = [...params.subReports]
+    // 设置部门数据
+    // state.selectEnum = [...params.dependence.deptArch.children]
+    // setDeptArch(state.selectEnum)
+    // 设置端数据
+    if (params.dependence.clientType) {
+      state.clientTypeList = [...params.dependence.clientType]
+    }
+    setDeptArch(state.clientTypeList)
+    if (subReports.length) {
+      state.tabsList = []
+      subReports.forEach((elm, index) => {
+        // 设置tabs数据
+        state.tabsList.push({
+          label: elm.reportName,
+          reportName: elm.reportName,
+          id: elm.id,
+          name: `tab_${elm.id}`
+        })
+      })
+      state.subReportInfo = _.cloneDeep(state.tabsList)
+      // 设置tabs数据
+      state.tabsActive = state.tabsList[0].name
+      // table页签
+      state.reportData = [...subReports]
+    }
+  },
+  // 设置页面的是否为编辑页面
+  SET_PAGE_TYPE(state, key) {
+    state.pageType = key
+  },
+  // 单个tab页面数据初始化设置
+  INIT_TAB_PAGE_DATA(state, tabsActive = '') {
+    const { pageType } = state
+
+    const setKey = (arr, depth) => {
+      if (arr && arr.length) {
+        arr.forEach((elm) => {
+          elm.domKey = uuid10()
+          elm.depth = depth
+          if (arr.children && arr.children.length) {
+            setKey(arr.children, depth + 1)
+          }
+          if (arr.content && arr.content.length) {
+            setKey(arr.content, depth + 1)
+          }
+        })
+      }
+    }
+
+    if (pageType === 'readAll') {
+      state.tabsActive = tabsActive || state.tabsActive
+      return
+    }
+    state.reportData.forEach((elm) => {
+      setKey(elm.reportCatalog.children, 0)
+    })
+    // 从其他页面跳转过来
+    const [tabPageData] = state.reportData.filter((elm) => {
+      return (
+        `${elm.id}` === setTabActive('tab_', tabsActive || state.tabsActive)
+      )
+    })
+    if (tabsActive) {
+      state.tabsActive = `tab_${tabsActive}`
+    }
+    const { newObj, domKeys, peopleLists } = setReportData(
+      tabPageData
+        ? tabPageData.reportCatalog
+        : state.reportData[0].reportCatalog
+    )
+    state.tabPageData = newObj
+    state.domKeys = domKeys
+    // console.log(peopleLists, 171)
+    state.peopleLists = peopleLists.filter(elm => elm.search(/null|\\\\/g) < 0)
+  },
+  // 切换页面之后数据维护
+  TAB_ACTIVE_CHANGE(state, tabsActive) {
+    // 获取原来页签的选中对象的id
+    const newTabsActive = setTabActive('tab_', tabsActive)
+    // tabPageData => 后台源数据结构
+    const oldTabPageData = reportDataBack({ ...state.tabPageData })
+    // console.log(oldTabPageData)
+    let newTabPageData = {}
+    const reportData = state.reportData.map((elm) => {
+      // 找出新页面的数据    && newTabsActive !== oldTabPageData.id
+      if (newTabsActive === `${elm.id}`) {
+        newTabPageData = { ...elm }
+      }
+      // 将上一个被选中的页签数据赋值给源数据(reportData)
+      if (`${elm.reportName}` === `${oldTabPageData.title}`) {
+        return {
+          ...elm,
+          reportCatalog: { ...oldTabPageData }
+        }
+      }
+      return elm
+    })
+    state.reportData = [...reportData]
+    // console.log(state.reportData)
+    // 对新数据进行转换
+    const { newObj, domKeys, peopleLists } = setReportData(
+      newTabPageData.reportCatalog,
+      108
+    )
+    state.tabsActive = `tab_${newTabsActive}`
+    state.tabPageData = newObj
+    state.domKeys = domKeys
+    state.peopleLists = peopleLists.filter(elm => elm.search(/null|\\\\/g) < 0)
+    // console.log(peopleLists)
+    // 页面恢复待编辑状态
+    state.editKeys = []
+    // 子页面页签切换,清空原来的tabs选中状态
+    state.subTabsActive = []
+  },
+  // 添加行
+  ADD_EDIT_KEYS(state, key) {
+    state.editKeys.push(key)
+    // const index = state.editKeys.indexOf(key)
+    // if (index < 0) {
+    //   state.editKeys.push(key)
+    // }
+  },
+  INIT_EDIT_KEYS(state) {
+    state.editKeys = []
+  },
+  // 获取子页面所有距离顶部的集合基础信息
+  GET_ALL_OFFSETTOP(state) {
+    const getOffsetTop = (id) => {
+      const dom = document.getElementById(id)
+      if (!dom) return 0.9527
+      return dom.getBoundingClientRect().top
+    }
+    const list = []
+    state.domKeys.forEach((elm) => {
+      const top = getOffsetTop(elm)
+      if (top > 0 && top !== 0.9527) {
+        list.push({
+          domKey: elm,
+          top: getOffsetTop(elm)
+        })
+      }
+    })
+    state.offsetList = [...list]
+  },
+  // 子页签数据切换
+  SUB_TABS_ACTIVE(state, { key, oldKey }) {
+    const index = state.subTabsActive.indexOf(oldKey)
+    if (index < 0) {
+      state.subTabsActive.push(key)
+    } else {
+      state.subTabsActive.splice(index, 1, key)
+    }
+  },
+  // 删除行
+  /**
+   * @param params.domKey   String   当前表格唯一标识
+   * @param params.btnItem  Object   点击按钮的基础数据
+   * @param params.scope    Object   当前行的数据
+   * @constructor
+   */
+  DELETE_TABLE_LINE(state, params) {
+    //         const { btnItem, scope } = params
+    //
+    // const deepDeleteArray = (arr, key) =>{
+    //           arr.forEach(elm=>{
+    //             if(elm.content && elm.content.length){
+    //               elm.content.forEach(item )
+    //             }
+    //           })
+    // }
+    //
+    //       state.tabPageData.children.forEach((elm) => {
+    //         elm.content.forEach((item) => {
+    //           item.domKey = uuid10(4)
+    //           if (item.type === 'table') {
+    //             setTableHeader(item.tableHeaders)
+    //             item.tableRows = arrToObj(item.tableRows, item.tableHeaders)
+    //           }
+    //         })
+    //       })
+  },
+  // 切换tabs之后,重新生成左侧树
+  CREATE_TREE_DATA(state) {},
+  // 菜单添加子项setInit
+  ADD_MENU_CHILDREN(state, params) {},
+  // 删除某一条数据
+  DELETE_ITEM(state, domKey) {
+    const tabPageData = [...state.tabPageData.children]
+    const delDom = (arr, key) => {
+      if (arr && _.isArray(arr) && arr.length) {
+        for (let i = 0; i < arr.length; i++) {
+          if (arr[i].domKey === key) {
+            arr.splice(i, 1)
+            return
+          }
+
+          if (arr[i].content && arr[i].content.length) {
+            delDom(arr[i].content, key)
+          }
+          if (arr[i].children && arr[i].children.length) {
+            delDom(arr[i].children, key)
+          }
+        }
+      }
+    }
+    delDom(tabPageData, domKey)
+    state.tabPageData.children = [...tabPageData]
+  },
+  /**
+   * 添加同级或者子集
+   * @param state   Object  数据源
+   * @param domKey  String  当前点击元素的唯一标识
+   * @param params  Object  要添加的内容
+   * @param isSub   Boolean 要添加的内容(true:添加子项|false:添加同级)
+   * @constructor
+   */
+  ADD_ITEM(state, { domKey, params, isSub = false }) {
+    if (domKey && params) {
+      const tabPageData = [...state.tabPageData.children]
+      const addItem = (arr, key) => {
+        if (arr && _.isArray(arr) && arr.length) {
+          for (let i = 0; i < arr.length; i++) {
+            if (arr[i].domKey === key) {
+              // 添加子项
+              if (isSub) {
+                // params.domIndexKey = arr[i].children
+                arr[i].children = [...arr[i].children, { ...params }]
+              }
+              // 添加同级
+              if (!isSub) {
+                // params.domIndexKey = i + 1
+                arr.splice(i + 1, 0, params)
+              }
+              return
+            }
+            if (arr[i].content && arr[i].content.length) {
+              addItem(arr[i].content, key)
+            }
+            if (arr[i].children && arr[i].children.length) {
+              addItem(arr[i].children, key)
+            }
+          }
+        }
+      }
+      addItem(tabPageData, domKey)
+      state.tabPageData.children = [...tabPageData]
+    }
+  },
+  // 数据初始化
+  INIT_STATE_DATA(state) {
+    state.pageDate = null // 页面的完整数据
+    state.tabsList = [
+      '上月问题跟进',
+      '本月重点问题',
+      '服务端详情',
+      '客户端详情',
+      '硬件详情',
+      '本月优秀&持续改进'
+    ]
+    state.tabsActive = '' // 最上层tabs焦点
+    state.tabPageData = null // 单个标签页数据
+    state.reportData = [] // 所有标签页数据
+    state.editKeys = [] // 存放需要编辑的区域的  domKey(唯一)
+    state.subTabsActive = [] // 当前页签中所有已切换的数据
+    state.domKeys = [] // 记录所有元素区域的唯一标识
+    state.selectEnum = [] // 部门数据
+    state.userNames = {} // 人员数据
+    state.peopleLists = [] // 人员账号数据
+    state.timeout = null // 函数防抖/节流
+    state.subTitle = '新建月报'
+    state.subReportName = ''
+    state.subReportInfo = null // 为回退时,当前页面为查看完整时,无法获取子月报数据情况设置
+    state.offsetList = []
+    /**
+     * 用户身份权限编号
+     * 100        月报发起人
+     * 50         确认人
+     * 30         用户
+     * 0          管理员
+     */
+    state.roleCode = 50 // 默认为用户
+    state.reportList = [] // 默认为用户
+    state.pageType = 'edit' // edit:(月报编辑和新建); readAll:(查看月报详情)
+    state.loading = false
+    state.clientTypeList = []
+    // 单业务线编辑时,数据迁移
+    state.saveAsTargetList = []
+    state.isLoading = [] // 是否显示刷新组件
+  },
+  // tabPageData
+  SET_TAB_PAGE_DATA(state, { data, id, tabsActive }) {
+    // 对新数据进行转换
+    const { newObj, domKeys, peopleLists } = setReportData(
+      {
+        children: _.cloneDeep(data)
+      },
+      108
+    )
+    // state.tabPageData = {
+    //   children: _.cloneDeep(data)
+    // }
+    // console.log(365, state.tabPageData)
+    state.tabPageData = newObj
+    state.domKeys = domKeys
+    state.peopleLists = peopleLists
+    // console.log(402, peopleLists)
+    // 页面恢复待编辑状态
+    state.editKeys = []
+    // 子页面页签切换,清空原来的tabs选中状态
+    state.subTabsActive = []
+    state.tabsActive = '' + tabsActive
+  },
+  // 设置人员数据,避免重复请求 userNames
+  SET_USER_NAME(state, { key, value }) {
+    if (!state.userNames.hasOwnProperty(key) && !state.userNames[key] && value && value.elm.search(/null|\\\\/g) < 0) {
+      state.userNames[key] = value
+    }
+  },
+  // 获取部门数据
+  SET_SELECT_ENUM(state, params) {
+    // console.log(params)
+    state.selectEnum = params
+    // console.log(state.selectEnum)
+    // setDeptArch(state.selectEnum)
+  },
+  // 标记为本月重点问题
+  MARK_ISSUES(state, { cascaderValue, normalAreaName, multiplePeople }) {
+    let isAdd = true
+    const run = (arr) => {
+      arr.forEach((elm) => {
+        if (
+          isAdd &&
+          elm.title === '本月重点问题' &&
+          elm.content &&
+          elm.content.length
+        ) {
+          elm.content.forEach((item) => {
+            if (item.type === 'Table') {
+              const row = { analyticFeedback: null }
+              item.tableHeaders.forEach((subItem) => {
+                if (subItem.name === '归属团队') {
+                  row[subItem.headerKey] = cascaderValue
+                }
+                if (subItem.name === '问题') {
+                  row[subItem.headerKey] = normalAreaName
+                }
+                if (subItem.name === '责任人') {
+                  row[subItem.headerKey] = multiplePeople
+                }
+              })
+              if (!item.tableRows) {
+                item.tableRows = []
+              }
+              item.tableRows.push(row)
+              isAdd = false
+            }
+          })
+        }
+        if (isAdd && elm.children && elm.children.length) {
+          run(elm.children)
+        }
+      })
+    }
+    run(state.tabPageData.children)
+  },
+  // 设置右侧树的提示内容
+  SET_HEADER_TITLE(state, { domKey, headerTitle }) {
+    let isAdd = true
+    const run = (arr) => {
+      arr.forEach((elm) => {
+        if (isAdd && elm.domKey === domKey) {
+          elm.headerTitle = headerTitle
+          isAdd = false
+        }
+        if (isAdd && elm.content && elm.content.length) {
+          run(elm.content)
+        }
+        if (isAdd && elm.children && elm.children.length) {
+          run(elm.children)
+        }
+      })
+    }
+    run(state.tabPageData.children)
+  },
+  // 获取用户月报操作区域权限
+  GET_USER_PERMISSION(state, { roleCode, reportList }) {
+    state.roleCode = roleCode
+    state.reportList = reportList
+  },
+  // 设置月报子标题 // 设置月报子标题   parentId: 163
+  // 设置月报标题
+  // (state, name) {
+  //   state.subTitle = name
+  // },
+  SET_SUB_TITLE(state, { id, name }) {
+    // commit('SET_SUB_TITLE', {
+    //   parentId: res.data.parentId,
+    //   name: res.data.reportName
+    // })
+    state.reportList &&
+      state.reportList.forEach((elm) => {
+        if (`${elm.id}` === `${id}`) {
+          if (!name) {
+            state.pageDate = {
+              status: elm.status
+            }
+          }
+          // console.log(elm.reportName)
+          // 如果是
+          if (elm.status === 10) {
+            state.subTitle = `确认月报|${elm.reportName}`
+          } else if (elm.status === 20) {
+            state.subTitle = `发布月报|${elm.reportName}`
+          } else if (elm.status === 30) {
+            state.subTitle = `查看|${elm.reportName}`
+          } else {
+            state.subTitle = `${elm.statueStr}|${elm.reportName}`
+          }
+        }
+      })
+    // 如果是单业务线查看
+    if (name) {
+      state.subReportName = `${name}`
+      state.subTitle += `|${name}`
+    }
+  },
+  // 设置页面基础数据
+  SET_PAGE_DATA(state, params) {
+    state.pageDate = _.cloneDeep(params)
+    delete state.pageDate.reportCatalog
+    delete state.pageDate.reportContent
+  },
+  // 设置子月报数据
+  SET_REPORT_INFO(state, params) {
+    state.subReportInfo = params
+  },
+  // 设置页面状态
+  SET_LOADING(state, isShow) {
+    state.loading = isShow
+  },
+  // 设置 页面区域 下标
+  SET_INDEX_TITLE(state) {
+    state.tabPageData = setIndexTitle(state.tabPageData)
+  },
+  // 设置拉取之后的页面数据 tabPageData
+  // 设置`端数据`
+  SET_CLIENT_TYPE_LIST(state, list) {
+    state.clientTypeList = list
+    setDeptArch(state.clientTypeList)
+  },
+  /**
+  * 数据另存为
+  *
+  */
+  SAVE_AS(state, { tableHeaders, tableRows, subReportid, key = 'only' }) {
+    // setTableHeader(data.tableHeaders)
+    const rowData = objToArr(
+      [tableRows],
+      tableHeaders
+    )
+    const find = (arr) => {
+      arr.forEach(elm => {
+        if (elm.title === '线上问题') {
+          const newQuestion = rowData[0].tableItems[1].value
+          const isQuestion = elm.content[0].tableRows.map(elm => elm.tableItems[1]).filter(
+            elm => elm.value === newQuestion
+          )
+          // 判断数据是否冲突
+          if (!isQuestion.length) {
+            elm.content[0].tableRows.push(rowData[0])
+          }
+        }
+        if (elm.children && elm.children.length) {
+          find(elm.children)
+        }
+      })
+    }
+    // 多业务线转移
+    if (state.pageType === 'editAll') {
+      for (let i = state.reportData.length - 1; i >= 0; i--) {
+        const elm = state.reportData[i]
+        if (elm.id === subReportid) {
+          find(elm.reportCatalog.children)
+        }
+      }
+    } else {
+      // 单业务线转移
+      // 判断数据是否存在,不存在,就插入
+      if (state.saveAsTargetList.filter(elm => elm.targetSubReportId === subReportid).length) {
+        state.saveAsTargetList.forEach(elm => {
+          if (elm.targetSubReportId === subReportid) {
+            if (!elm.tableRow) {
+              elm.tableRow = []
+            }
+            elm.tableRow.push(rowData[0])
+          }
+        })
+      } else {
+        state.saveAsTargetList.push({
+          targetSubReportId: subReportid,
+          tableRow: [rowData[0]]
+        })
+      }
+    }
+  },
+  /**
+   * 设置人员账号
+   * @param state  数据源
+   * @param people ['honghaitao_v'] 人员账号数组
+   * @constructor
+   */
+  SET_PEOPLELISTS(state, people) {
+    state.peopleLists = Array.from(new Set([...state.peopleLists, ...people]))
+  }
+}

+ 44 - 0
src/store/modules/monthlyReport/baseMixin/state.js

@@ -0,0 +1,44 @@
+export default {
+  pageDate: null, // 页面的完整数据
+  tabsList: [
+    '上月问题跟进',
+    '本月重点问题',
+    '服务端详情',
+    '客户端详情',
+    '硬件详情',
+    '本月优秀&持续改进'
+  ],
+  tabsActive: '', // 最上层tabs焦点
+  tabPageData: null, // 单个标签页数据
+  reportData: [], // 所有标签页数据
+  editKeys: [], // 存放需要编辑的区域的  domKey(唯一)
+  subTabsActive: [], // 当前页签中所有已切换的数据
+  domKeys: [], // 记录所有元素区域的唯一标识
+  selectEnum: [], // 部门数据
+  userNames: {}, // 人员数据
+  peopleLists: [], // 人员账号数据
+  subTitle: '新建月报',
+  subReportName: '',
+  subReportInfo: null, // 为回退时,当前页面为查看完整时,无法获取子月报数据情况设置
+  timeout: null, // 函数防抖/节流
+  offsetList: [],
+  /**
+   * 用户身份权限编号
+   * 100        月报发起人
+   * 50         确认人
+   * 30         用户
+   * 0          管理员
+   */
+  roleCode: 50, // 默认为用户
+  reportList: [], // 默认为用户
+  pageType: 'edit', // edit:(月报编辑和新建); readAll:(查看月报详情)
+  loading: false,
+  clientTypeList: [],
+  // 单业务线编辑时,数据迁移
+  saveAsTargetList: [],
+  isLoading: [] // 是否显示刷新组件
+  // saveAsData: {
+  //   tableRow: '',
+  //   targetSubReportId: ''
+  // }
+}

+ 6 - 1063
src/store/modules/monthlyReport/edit/index.js

@@ -1,1074 +1,17 @@
-import { uuid10 } from '@/utils'
-import {
-  getMonthlyReport,
-  updateMonthlyReport,
-  delMonthlyReport,
-  getAllSubReportCatalog,
-  getSubReport,
-  // getReportDependence,
-  getDeptArch,
-  sendConfirm,
-  returnReport,
-  sendSubConfirm,
-  publishReport,
-  getSubReportInfo,
-  updateSubReport,
-  pullDataAgain,
-  pullSubTitle
-} from '@/api/qualityMonthlyReport/edit'
-// import { memberQueryMemberInfoByIDAPorName } from '@/api/projectIndex'
-import { getAvaliableInfo, getMonthlyReportVersion } from '@/api/qualityMonthlyReport'
-
-import {
-  reportDataBack,
-  setReportData,
-  setTabActive,
-  setDeptArch,
-  setIndexTitle,
-  readOnlyTableArrToObj,
-  arrToObj,
-  objToArr,
-  setTableHeader
-} from './utils'
-import { message } from '@/utils/mesDebounce'
-
-import _ from 'lodash'
-import { getListPerson } from '@/api/onlineproblem'
+import baseStateData from '../baseMixin/state.js'
+import baseActionsData from '../baseMixin/actions.js'
+import baseMutationsData from '../baseMixin/mutations.js'
 
 export default {
   /* 月报编辑 */
   namespaced: true,
   state: {
-    pageDate: null, // 页面的完整数据
-    tabsList: [
-      '上月问题跟进',
-      '本月重点问题',
-      '服务端详情',
-      '客户端详情',
-      '硬件详情',
-      '本月优秀&持续改进'
-    ],
-    tabsActive: '', // 最上层tabs焦点
-    tabPageData: null, // 单个标签页数据
-    reportData: [], // 所有标签页数据
-    editKeys: [], // 存放需要编辑的区域的  domKey(唯一)
-    subTabsActive: [], // 当前页签中所有已切换的数据
-    domKeys: [], // 记录所有元素区域的唯一标识
-    selectEnum: [], // 部门数据
-    userNames: {}, // 人员数据
-    peopleLists: [], // 人员账号数据
-    subTitle: '新建月报',
-    subReportName: '',
-    subReportInfo: null, // 为回退时,当前页面为查看完整时,无法获取子月报数据情况设置
-    timeout: null, // 函数防抖/节流
-    offsetList: [],
-    /**
-     * 用户身份权限编号
-     * 100        月报发起人
-     * 50         确认人
-     * 30         用户
-     * 0          管理员
-     */
-    roleCode: 50, // 默认为用户
-    reportList: [], // 默认为用户
-    pageType: 'edit', // edit:(月报编辑和新建); readAll:(查看月报详情)
-    loading: false,
-    clientTypeList: [],
-    // 单业务线编辑时,数据迁移
-    saveAsTargetList: [],
-    isLoading: [] // 是否显示刷新组件
-    // saveAsData: {
-    //   tableRow: '',
-    //   targetSubReportId: ''
-    // }
+    ...baseStateData
   },
   mutations: {
-    // 页面基础数据赋值
-    INIT_PAGE_DATA(state, params) {
-      const { pageType } = state
-      if (pageType === 'read' || pageType === 'edit') return
-      if (pageType === 'readAll') {
-        // 设置tabs数据
-        state.tabsList = state.tabsList.map((elm) => ({
-          label: elm,
-          name: `tab_${elm}`
-        }))
-        state.tabsActive = 'tab_上月问题跟进'
-        return
-      }
-      state.pageDate = { ...params }
-      delete state.pageDate.subReports
-      // state.subTitle = state.pageDate.reportName
-      const subReports = [...params.subReports]
-      // 设置部门数据
-      // state.selectEnum = [...params.dependence.deptArch.children]
-      // setDeptArch(state.selectEnum)
-      // 设置端数据
-      if (params.dependence.clientType) {
-        state.clientTypeList = [...params.dependence.clientType]
-      }
-      setDeptArch(state.clientTypeList)
-      if (subReports.length) {
-        state.tabsList = []
-        subReports.forEach((elm, index) => {
-          // 设置tabs数据
-          state.tabsList.push({
-            label: elm.reportName,
-            reportName: elm.reportName,
-            id: elm.id,
-            name: `tab_${elm.id}`
-          })
-        })
-        state.subReportInfo = _.cloneDeep(state.tabsList)
-        // 设置tabs数据
-        state.tabsActive = state.tabsList[0].name
-        // table页签
-        state.reportData = [...subReports]
-      }
-    },
-    // 设置页面的是否为编辑页面
-    SET_PAGE_TYPE(state, key) {
-      state.pageType = key
-    },
-    // 单个tab页面数据初始化设置
-    INIT_TAB_PAGE_DATA(state, tabsActive = '') {
-      const { pageType } = state
-
-      const setKey = (arr, depth) => {
-        if (arr && arr.length) {
-          arr.forEach((elm) => {
-            elm.domKey = uuid10()
-            elm.depth = depth
-            if (arr.children && arr.children.length) {
-              setKey(arr.children, depth + 1)
-            }
-            if (arr.content && arr.content.length) {
-              setKey(arr.content, depth + 1)
-            }
-          })
-        }
-      }
-
-      if (pageType === 'readAll') {
-        state.tabsActive = tabsActive || state.tabsActive
-        return
-      }
-      state.reportData.forEach((elm) => {
-        setKey(elm.reportCatalog.children, 0)
-      })
-      // 从其他页面跳转过来
-      const [tabPageData] = state.reportData.filter((elm) => {
-        return (
-          `${elm.id}` === setTabActive('tab_', tabsActive || state.tabsActive)
-        )
-      })
-      if (tabsActive) {
-        state.tabsActive = `tab_${tabsActive}`
-      }
-      const { newObj, domKeys, peopleLists } = setReportData(
-        tabPageData
-          ? tabPageData.reportCatalog
-          : state.reportData[0].reportCatalog
-      )
-      state.tabPageData = newObj
-      state.domKeys = domKeys
-      // console.log(peopleLists, 171)
-      state.peopleLists = peopleLists
-    },
-    // 切换页面之后数据维护
-    TAB_ACTIVE_CHANGE(state, tabsActive) {
-      // 获取原来页签的选中对象的id
-      const newTabsActive = setTabActive('tab_', tabsActive)
-      // tabPageData => 后台源数据结构
-      const oldTabPageData = reportDataBack({ ...state.tabPageData })
-      // console.log(oldTabPageData)
-      let newTabPageData = {}
-      const reportData = state.reportData.map((elm) => {
-        // 找出新页面的数据    && newTabsActive !== oldTabPageData.id
-        if (newTabsActive === `${elm.id}`) {
-          newTabPageData = { ...elm }
-        }
-        // 将上一个被选中的页签数据赋值给源数据(reportData)
-        if (`${elm.reportName}` === `${oldTabPageData.title}`) {
-          return {
-            ...elm,
-            reportCatalog: { ...oldTabPageData }
-          }
-        }
-        return elm
-      })
-      state.reportData = [...reportData]
-      // console.log(state.reportData)
-      // 对新数据进行转换
-      const { newObj, domKeys, peopleLists } = setReportData(
-        newTabPageData.reportCatalog,
-        108
-      )
-      state.tabsActive = `tab_${newTabsActive}`
-      state.tabPageData = newObj
-      state.domKeys = domKeys
-      state.peopleLists = peopleLists
-      // console.log(peopleLists)
-      // 页面恢复待编辑状态
-      state.editKeys = []
-      // 子页面页签切换,清空原来的tabs选中状态
-      state.subTabsActive = []
-    },
-    // 添加行
-    ADD_EDIT_KEYS(state, key) {
-      state.editKeys.push(key)
-      // const index = state.editKeys.indexOf(key)
-      // if (index < 0) {
-      //   state.editKeys.push(key)
-      // }
-    },
-    INIT_EDIT_KEYS(state) {
-      state.editKeys = []
-    },
-    // 获取子页面所有距离顶部的集合基础信息
-    GET_ALL_OFFSETTOP(state) {
-      const getOffsetTop = (id) => {
-        const dom = document.getElementById(id)
-        if (!dom) return 0.9527
-        return dom.getBoundingClientRect().top
-      }
-      const list = []
-      state.domKeys.forEach((elm) => {
-        const top = getOffsetTop(elm)
-        if (top > 0 && top !== 0.9527) {
-          list.push({
-            domKey: elm,
-            top: getOffsetTop(elm)
-          })
-        }
-      })
-      state.offsetList = [...list]
-    },
-    // 子页签数据切换
-    SUB_TABS_ACTIVE(state, { key, oldKey }) {
-      const index = state.subTabsActive.indexOf(oldKey)
-      if (index < 0) {
-        state.subTabsActive.push(key)
-      } else {
-        state.subTabsActive.splice(index, 1, key)
-      }
-    },
-    // 删除行
-    /**
-     * @param params.domKey   String   当前表格唯一标识
-     * @param params.btnItem  Object   点击按钮的基础数据
-     * @param params.scope    Object   当前行的数据
-     * @constructor
-     */
-    DELETE_TABLE_LINE(state, params) {
-      //         const { btnItem, scope } = params
-      //
-      // const deepDeleteArray = (arr, key) =>{
-      //           arr.forEach(elm=>{
-      //             if(elm.content && elm.content.length){
-      //               elm.content.forEach(item )
-      //             }
-      //           })
-      // }
-      //
-      //       state.tabPageData.children.forEach((elm) => {
-      //         elm.content.forEach((item) => {
-      //           item.domKey = uuid10(4)
-      //           if (item.type === 'table') {
-      //             setTableHeader(item.tableHeaders)
-      //             item.tableRows = arrToObj(item.tableRows, item.tableHeaders)
-      //           }
-      //         })
-      //       })
-    },
-    // 切换tabs之后,重新生成左侧树
-    CREATE_TREE_DATA(state) {},
-    // 菜单添加子项setInit
-    ADD_MENU_CHILDREN(state, params) {},
-    // 删除某一条数据
-    DELETE_ITEM(state, domKey) {
-      const tabPageData = [...state.tabPageData.children]
-      const delDom = (arr, key) => {
-        if (arr && _.isArray(arr) && arr.length) {
-          for (let i = 0; i < arr.length; i++) {
-            if (arr[i].domKey === key) {
-              arr.splice(i, 1)
-              return
-            }
-
-            if (arr[i].content && arr[i].content.length) {
-              delDom(arr[i].content, key)
-            }
-            if (arr[i].children && arr[i].children.length) {
-              delDom(arr[i].children, key)
-            }
-          }
-        }
-      }
-      delDom(tabPageData, domKey)
-      state.tabPageData.children = [...tabPageData]
-    },
-    /**
-     * 添加同级或者子集
-     * @param state   Object  数据源
-     * @param domKey  String  当前点击元素的唯一标识
-     * @param params  Object  要添加的内容
-     * @param isSub   Boolean 要添加的内容(true:添加子项|false:添加同级)
-     * @constructor
-     */
-    ADD_ITEM(state, { domKey, params, isSub = false }) {
-      if (domKey && params) {
-        const tabPageData = [...state.tabPageData.children]
-        const addItem = (arr, key) => {
-          if (arr && _.isArray(arr) && arr.length) {
-            for (let i = 0; i < arr.length; i++) {
-              if (arr[i].domKey === key) {
-                // 添加子项
-                if (isSub) {
-                  // params.domIndexKey = arr[i].children
-                  arr[i].children = [...arr[i].children, { ...params }]
-                }
-                // 添加同级
-                if (!isSub) {
-                  // params.domIndexKey = i + 1
-                  arr.splice(i + 1, 0, params)
-                }
-                return
-              }
-              if (arr[i].content && arr[i].content.length) {
-                addItem(arr[i].content, key)
-              }
-              if (arr[i].children && arr[i].children.length) {
-                addItem(arr[i].children, key)
-              }
-            }
-          }
-        }
-        addItem(tabPageData, domKey)
-        state.tabPageData.children = [...tabPageData]
-      }
-    },
-    // 数据初始化
-    INIT_STATE_DATA(state) {
-      state.pageDate = null // 页面的完整数据
-      state.tabsList = [
-        '上月问题跟进',
-        '本月重点问题',
-        '服务端详情',
-        '客户端详情',
-        '硬件详情',
-        '本月优秀&持续改进'
-      ]
-      state.tabsActive = '' // 最上层tabs焦点
-      state.tabPageData = null // 单个标签页数据
-      state.reportData = [] // 所有标签页数据
-      state.editKeys = [] // 存放需要编辑的区域的  domKey(唯一)
-      state.subTabsActive = [] // 当前页签中所有已切换的数据
-      state.domKeys = [] // 记录所有元素区域的唯一标识
-      state.selectEnum = [] // 部门数据
-      state.userNames = {} // 人员数据
-      state.peopleLists = [] // 人员账号数据
-      state.timeout = null // 函数防抖/节流
-      state.subTitle = '新建月报'
-      state.subReportName = ''
-      state.subReportInfo = null // 为回退时,当前页面为查看完整时,无法获取子月报数据情况设置
-      state.offsetList = []
-      /**
-       * 用户身份权限编号
-       * 100        月报发起人
-       * 50         确认人
-       * 30         用户
-       * 0          管理员
-       */
-      state.roleCode = 50 // 默认为用户
-      state.reportList = [] // 默认为用户
-      state.pageType = 'edit' // edit:(月报编辑和新建); readAll:(查看月报详情)
-      state.loading = false
-      state.clientTypeList = []
-      // 单业务线编辑时,数据迁移
-      state.saveAsTargetList = []
-      state.isLoading = [] // 是否显示刷新组件
-    },
-    // tabPageData
-    SET_TAB_PAGE_DATA(state, { data, id, tabsActive }) {
-      // 对新数据进行转换
-      const { newObj, domKeys, peopleLists } = setReportData(
-        {
-          children: _.cloneDeep(data)
-        },
-        108
-      )
-      // state.tabPageData = {
-      //   children: _.cloneDeep(data)
-      // }
-      // console.log(365, state.tabPageData)
-      state.tabPageData = newObj
-      state.domKeys = domKeys
-      state.peopleLists = peopleLists
-      // console.log(402, peopleLists)
-      // 页面恢复待编辑状态
-      state.editKeys = []
-      // 子页面页签切换,清空原来的tabs选中状态
-      state.subTabsActive = []
-      state.tabsActive = '' + tabsActive
-    },
-    // 设置人员数据,避免重复请求 userNames
-    SET_USER_NAME(state, { key, value }) {
-      if (!state.userNames.hasOwnProperty(key) && !state.userNames[key]) {
-        state.userNames[key] = value
-      }
-    },
-    // 获取部门数据
-    SET_SELECT_ENUM(state, params) {
-      // console.log(params)
-      state.selectEnum = params
-      // console.log(state.selectEnum)
-      // setDeptArch(state.selectEnum)
-    },
-    // 标记为本月重点问题
-    MARK_ISSUES(state, { cascaderValue, normalAreaName, multiplePeople }) {
-      let isAdd = true
-      const run = (arr) => {
-        arr.forEach((elm) => {
-          if (
-            isAdd &&
-            elm.title === '本月重点问题' &&
-            elm.content &&
-            elm.content.length
-          ) {
-            elm.content.forEach((item) => {
-              if (item.type === 'Table') {
-                const row = { analyticFeedback: null }
-                item.tableHeaders.forEach((subItem) => {
-                  if (subItem.name === '归属团队') {
-                    row[subItem.headerKey] = cascaderValue
-                  }
-                  if (subItem.name === '问题') {
-                    row[subItem.headerKey] = normalAreaName
-                  }
-                  if (subItem.name === '责任人') {
-                    row[subItem.headerKey] = multiplePeople
-                  }
-                })
-                if (!item.tableRows) {
-                  item.tableRows = []
-                }
-                item.tableRows.push(row)
-                isAdd = false
-              }
-            })
-          }
-          if (isAdd && elm.children && elm.children.length) {
-            run(elm.children)
-          }
-        })
-      }
-      run(state.tabPageData.children)
-    },
-    // 设置右侧树的提示内容
-    SET_HEADER_TITLE(state, { domKey, headerTitle }) {
-      let isAdd = true
-      const run = (arr) => {
-        arr.forEach((elm) => {
-          if (isAdd && elm.domKey === domKey) {
-            elm.headerTitle = headerTitle
-            isAdd = false
-          }
-          if (isAdd && elm.content && elm.content.length) {
-            run(elm.content)
-          }
-          if (isAdd && elm.children && elm.children.length) {
-            run(elm.children)
-          }
-        })
-      }
-      run(state.tabPageData.children)
-    },
-    // 获取用户月报操作区域权限
-    GET_USER_PERMISSION(state, { roleCode, reportList }) {
-      state.roleCode = roleCode
-      state.reportList = reportList
-    },
-    // 设置月报子标题 // 设置月报子标题   parentId: 163
-    // 设置月报标题
-    // (state, name) {
-    //   state.subTitle = name
-    // },
-    SET_SUB_TITLE(state, { id, name }) {
-      // commit('SET_SUB_TITLE', {
-      //   parentId: res.data.parentId,
-      //   name: res.data.reportName
-      // })
-      state.reportList &&
-        state.reportList.forEach((elm) => {
-          if (`${elm.id}` === `${id}`) {
-            if (!name) {
-              state.pageDate = {
-                status: elm.status
-              }
-            }
-            // console.log(elm.reportName)
-            // 如果是
-            if (elm.status === 10) {
-              state.subTitle = `确认月报|${elm.reportName}`
-            } else if (elm.status === 20) {
-              state.subTitle = `发布月报|${elm.reportName}`
-            } else if (elm.status === 30) {
-              state.subTitle = `查看|${elm.reportName}`
-            } else {
-              state.subTitle = `${elm.statueStr}|${elm.reportName}`
-            }
-          }
-        })
-      // 如果是单业务线查看
-      if (name) {
-        state.subReportName = `${name}`
-        state.subTitle += `|${name}`
-      }
-    },
-    // 设置页面基础数据
-    SET_PAGE_DATA(state, params) {
-      state.pageDate = _.cloneDeep(params)
-      delete state.pageDate.reportCatalog
-      delete state.pageDate.reportContent
-    },
-    // 设置子月报数据
-    SET_REPORT_INFO(state, params) {
-      state.subReportInfo = params
-    },
-    // 设置页面状态
-    SET_LOADING(state, isShow) {
-      state.loading = isShow
-    },
-    // 设置 页面区域 下标
-    SET_INDEX_TITLE(state) {
-      state.tabPageData = setIndexTitle(state.tabPageData)
-    },
-    // 设置拉取之后的页面数据 tabPageData
-    // 设置`端数据`
-    SET_CLIENT_TYPE_LIST(state, list) {
-      state.clientTypeList = list
-      setDeptArch(state.clientTypeList)
-    },
-    /**
-    * 数据另存为
-    *
-    */
-    SAVE_AS(state, { tableHeaders, tableRows, subReportid, key = 'only' }) {
-      // setTableHeader(data.tableHeaders)
-      const rowData = objToArr(
-        [tableRows],
-        tableHeaders
-      )
-      const find = (arr) => {
-        arr.forEach(elm => {
-          if (elm.title === '线上问题') {
-            const newQuestion = rowData[0].tableItems[1].value
-            const isQuestion = elm.content[0].tableRows.map(elm => elm.tableItems[1]).filter(
-              elm => elm.value === newQuestion
-            )
-            // 判断数据是否冲突
-            if (!isQuestion.length) {
-              elm.content[0].tableRows.push(rowData[0])
-            }
-          }
-          if (elm.children && elm.children.length) {
-            find(elm.children)
-          }
-        })
-      }
-      // 多业务线转移
-      if (state.pageType === 'editAll') {
-        for (let i = state.reportData.length - 1; i >= 0; i--) {
-          const elm = state.reportData[i]
-          if (elm.id === subReportid) {
-            find(elm.reportCatalog.children)
-          }
-        }
-      } else {
-        // 单业务线转移
-        // 判断数据是否存在,不存在,就插入
-        if (state.saveAsTargetList.filter(elm => elm.targetSubReportId === subReportid).length) {
-          state.saveAsTargetList.forEach(elm => {
-            if (elm.targetSubReportId === subReportid) {
-              if (!elm.tableRow) {
-                elm.tableRow = []
-              }
-              elm.tableRow.push(rowData[0])
-            }
-          })
-        } else {
-          state.saveAsTargetList.push({
-            targetSubReportId: subReportid,
-            tableRow: [rowData[0]]
-          })
-        }
-      }
-    },
-    /**
-     * 设置人员账号
-     * @param state  数据源
-     * @param people ['honghaitao_v'] 人员账号数组
-     * @constructor
-     */
-    SET_PEOPLELISTS(state, people) {
-      state.peopleLists = Array.from(new Set([...state.peopleLists, ...people]))
-    }
+    ...baseMutationsData
   },
   actions: {
-    // 月报数据获取
-    async initPageData(
-      { commit, state, dispatch },
-      { id, subReportId, subActive }
-    ) {
-      dispatch('setSubReportInfo', id)
-      const { pageType } = state
-      if (
-        pageType === 'readAll' ||
-        pageType === 'read' ||
-        pageType === 'edit'
-      ) {
-        commit('INIT_PAGE_DATA')
-        dispatch('getSubReportData', {
-          id,
-          subReportId,
-          tabsActive: `tab_${subActive || '上月问题跟进'}`
-        })
-      } else {
-        const res = await getMonthlyReport(id)
-        // 设置月报子标题
-        commit('SET_SUB_TITLE', {
-          id: id
-        })
-        if (res.code === 200 && res.data) {
-          commit('INIT_PAGE_DATA', { ...res.data })
-          commit('INIT_TAB_PAGE_DATA', subActive && `tab_${subActive}`)
-          commit('SET_LOADING', false)
-          dispatch('initPeople')
-        }
-      }
-    },
-    // 页面切换 TAB_ACTIVE_CHANGE
-    tabActiveChange({ commit, state, dispatch }, { id, tabsActive }) {
-      const { pageType } = state
-      if (pageType === 'editAll') {
-        return commit('TAB_ACTIVE_CHANGE', tabsActive)
-      }
-      if (pageType === 'readAll') {
-        dispatch('getSubReportData', { id, tabsActive })
-      }
-    },
-    // 获取查看月报数据
-    async getSubReportData({ dispatch, commit, state }, { id, subReportId, tabsActive }) {
-      const { pageType } = state
-      let params = {}
-      const method =
-        pageType === 'readAll' ? getAllSubReportCatalog : getSubReport
-      if (pageType === 'read' || pageType === 'edit') {
-        params = {
-          subReportId
-        }
-      }
-      if (pageType === 'readAll') {
-        // state.pageDate = {
-        //   status: 10
-        // }
-        params = {
-          reportId: id,
-          catalogTitle: setTabActive('tab_', tabsActive)
-        }
-      }
-      const res = await method(params)
-      if (res.code === 200) {
-        // 单个月报与完整月报数据梳理
-        if (pageType === 'read' || pageType === 'edit') {
-          commit('SET_CLIENT_TYPE_LIST', res.data.dependence.clientType)
-          // commit('SET_SELECT_ENUM', res.data.dependence.deptArch.children)
-          commit('SET_PAGE_DATA', res.data)
-        }
-        // console.log(res)
-        if (pageType === 'readAll' && params.catalogTitle.search(/服务端详情|客户端详情/) > -1) {
-          res.data.splice(0, 0, { depth: 1, fromUser: false, hiddenAncestor: null, isVisible: true, subTitles: null, title: '整体概览', type: 'Head1', content: [{ type: 'overallOverviewo' }] })
-          // console.log(params)
-        }
-        commit('SET_TAB_PAGE_DATA', {
-          data:
-            pageType === 'readAll' ? res.data : res.data.reportCatalog.children,
-          id,
-          tabsActive
-        })
-        commit('SET_LOADING', false)
-        // 设置月报子标题
-        setTimeout(() => {
-          commit('SET_SUB_TITLE', {
-            id: pageType.search(/All/) > -1 ? `${id}` : `${res.data.parentId}`,
-            name: pageType.search(/All/) > -1 ? '' : res.data.reportName
-          })
-          dispatch('initPeople')
-        }, 700)
-      }
-    },
-    // 子月报更新
-    async upDateSubReport({ state }, callback) {
-      const params = _.cloneDeep(state.pageDate)
-      params.reportCatalog = {
-        children: _.cloneDeep(state.tabPageData.children),
-        content: [],
-        depth: 0,
-        fromUser: false,
-        hiddenAncestor: null,
-        isVisible: true,
-        subTitles: null,
-        title: params.reportName,
-        type: 'Tag'
-      }
-      params.reportCatalog = reportDataBack(params.reportCatalog)
-      if (state.saveAsTargetList.length) {
-        params.saveAsTargetList = _.cloneDeep(state.saveAsTargetList)
-      }
-      params.dependence = null
-      const res = await updateSubReport(params)
-      if (res.code === 200) {
-        callback()
-      }
-    },
-    // 月报更新
-    async upDateReport({ dispatch, state }, callback) {
-      const params = _.cloneDeep(state.pageDate)
-      const tabPageData = _.cloneDeep(state.tabPageData)
-      const tabsActive = setTabActive('tab_', state.tabsActive)
-      params.subReports = state.reportData.map((elm) => {
-        // 将上一个被选中的页签数据赋值给源数据(reportData)
-        if (`${elm.id}` === tabsActive) {
-          return {
-            ...elm,
-            dependence: null,
-            reportCatalog: { ...reportDataBack({ ...tabPageData }) }
-          }
-        }
-        return elm
-      })
-      // 转换数据结构
-      const res = await updateMonthlyReport(params)
-      if (res.code === 200) {
-        state.pageDate.isDelete = false
-        callback()
-      }
-    },
-    // 获取部门数据
-    async setSelectEnum({ commit }, key) {
-      const depth = JSON.parse(window.localStorage.getItem('depth'))
-      if (!depth || key === 'init') {
-        const res = await getDeptArch()
-        if (res.code === 200) {
-          window.localStorage.setItem('depth', JSON.stringify(res.data.children))
-          commit('SET_SELECT_ENUM', res.data.children)
-        }
-      } else {
-        commit('SET_SELECT_ENUM', depth)
-      }
-    },
-    // 删除月报
-    async deleteReport(
-      { commit, state, context },
-      { key, callback, isMsg = true }
-    ) {
-      const res = await delMonthlyReport(state.pageDate.id)
-      if (res.code === 200) {
-        if (isMsg) {
-          message.success('删除成功!')
-        }
-        callback && callback()
-      }
-    },
-    // 月报发送确认
-    async sendReport({ commit, state, context }, { id, callback }) {
-      const params = _.cloneDeep(state.pageDate)
-      const tabPageData = _.cloneDeep(state.tabPageData)
-      const tabsActive = setTabActive('tab_', state.tabsActive)
-      params.subReports = state.reportData.map((elm) => {
-        // 将上一个被选中的页签数据赋值给源数据(reportData)
-        if (`${elm.id}` === tabsActive) {
-          return {
-            ...elm,
-            dependence: null,
-            reportCatalog: { ...reportDataBack({ ...tabPageData }) }
-          }
-        }
-        return elm
-      })
-      const res = await sendConfirm({
-        ...params,
-        id
-      })
-      if (res.code === 200) {
-        message.success('发送成功!')
-        callback()
-      }
-    },
-    // 月报发布
-    async publishAllReport({ commit, state, context }, { id, callback }) {
-      const res = await publishReport({
-        id
-      })
-      if (res.code === 200) {
-        message.success('发布成功!')
-        callback()
-      }
-    },
-    // 月报确认
-    async confirmReport({ state }, { id, callback }) {
-      const res = await sendSubConfirm({
-        subReportId: id
-      })
-      if (res.code === 200) {
-        callback()
-      }
-    },
-    // 月报回退
-    async returnReport({ commit, state, context }, { data, callback }) {
-      const res = await returnReport(data)
-      if (res.code === 200) {
-        callback()
-      }
-    },
-    // 获取用户月报操作区域权限
-    async getUserPermission({ commit }) {
-      const res = await getAvaliableInfo()
-      if (res.code === 200) {
-        commit('GET_USER_PERMISSION', res.data)
-      }
-    },
-    // 获取子月报列表数据
-    async setSubReportInfo({ commit }, id) {
-      const res = await getSubReportInfo(id)
-      if (res.code === 200) {
-        commit('SET_REPORT_INFO', res.data)
-      }
-    },
-    // 重新拉取数据
-    async refreshReport(
-      { commit, state },
-      { domKey, title, subReportId, callback, errorback }
-    ) {
-      const tabPageData = _.cloneDeep(state.tabPageData)
-      // console.log('refreshReport', domKey, title)
-      const [tabKey, subTabKey] = state.subTabsActive
-      const tabDataObj = {
-        tabKey: '',
-        subTabKey: ''
-      }
-      const setValue = (item, key, value) => {
-        if (item.domKey === value) {
-          tabDataObj[key] = item
-        }
-      }
-      const find = (arr) => {
-        arr &&
-          arr.length &&
-          arr.forEach((elm) => {
-            setValue(elm, 'tabKey', tabKey)
-            setValue(elm, 'subTabKey', subTabKey)
-            if (elm.content && elm.content.length) {
-              elm.content.forEach((item) => {
-                setValue(elm, 'tabKey', tabKey)
-                setValue(elm, 'subTabKey', subTabKey)
-              })
-            }
-            if (elm.children && elm.children.length) {
-              find(elm.children)
-            }
-          })
-      }
-      const params = {
-        subReportId: '',
-        catalogTitle: title,
-        isServer: true,
-        clientType: ''
-      }
-      if (title !== '上月问题跟进') {
-        find(tabPageData.children)
-        if (tabDataObj.tabKey.title) {
-          params.isServer = tabDataObj.tabKey.title === '服务端'
-        }
-        if (!params.isServer) {
-          params.clientType = tabDataObj.subTabKey.title
-        }
-      }
-      if (state.pageType.search(/All/) > -1) {
-        // console.log(state, setTabActive('tab_', state.tabsActive))
-        params.subReportId = setTabActive('tab_', state.tabsActive)
-      }
-      if (state.pageType === 'edit') {
-        params.subReportId = subReportId
-      }
-      // console.log(params)
-      /**
-       * 线上问题、
-       */
-      const res = await pullDataAgain(params)
-      // console.log(res)
-      if (res.code === 200 && res.data) {
-        if (title !== '上月问题跟进' && title !== '线上问题') {
-          if (res.data.type.search(/Table|TableAndRichText/) > -1) {
-            setTableHeader(res.data.tableHeaders)
-            res.data.tableRows = arrToObj(
-              res.data.tableRows,
-              res.data.tableHeaders
-            )
-          }
-        }
-        if (title.search(/线下缺陷/) > -1) {
-          setTableHeader(res.data.content[0].tableHeaders)
-          res.data.content[0].tableRows = readOnlyTableArrToObj(
-            res.data.content[0].tableRows,
-            res.data.content[0].tableHeaders
-          )
-        }
-        if (title.search(/上月问题跟进|发布&回滚|线上问题|延期|提测打回\/发版撤回|提测打回\/准出不通过/) > -1) {
-          const contentIndex = title === '线上问题' ? 1 : 0
-          // console.log(res.data.content, 926)
-          setTableHeader(res.data.content[contentIndex].tableHeaders)
-          res.data.content[contentIndex].tableRows = arrToObj(
-            res.data.content[contentIndex].tableRows,
-            res.data.content[contentIndex].tableHeaders
-          ).newObj
-        }
-        const setDomData = (arr) => {
-          arr &&
-          arr.length &&
-          arr.forEach((elm) => {
-            const newDomKey = uuid10(4)
-            if (elm.domKey === domKey) {
-              if (title.search(/上月问题跟进/) > -1) {
-                elm.content = [{ ...res.data.content[0], domKey: newDomKey }]
-              } else if (title.search(/线上问题/) > -1) {
-                const value = `${elm.content[0].value || ''}`
-                elm.subTitles = _.cloneDeep(res.data.subTitles)
-                elm.content = _.cloneDeep(res.data.content)
-                elm.content[0].value = value
-                elm.content[1].domKey = newDomKey
-              } else if (title.search(/线下缺陷/) > -1) {
-                elm.content[0] = _.cloneDeep(res.data.content[0])
-                elm.content[0].domKey = newDomKey
-                elm.subTitles = [...res.data.subTitles]
-              } else if (title.search(/发布&回滚/) > -1) {
-                const value = `${elm.content[0].value || ''}`
-                elm.content = [{ ...res.data.content[0], value, domKey: newDomKey }]
-                elm.subTitles = [...res.data.subTitles]
-              } else {
-                elm.content = [{ ...res.data.content[0], domKey: newDomKey }]
-              }
-              state.isLoading = [newDomKey]
-            }
-            if (elm.children && elm.children.length) {
-              setDomData(elm.children)
-            }
-          })
-        }
-        setDomData(tabPageData.children)
-        state.tabPageData = tabPageData
-        if (res.code === 200) {
-          callback && callback()
-        }
-      } else {
-        errorback && errorback()
-      }
-    },
-    // 根据月报版本,调整页面执行逻辑
-    async  setMonthlyReportPageVersion({ commit, state }, { self }) {
-      const { query, path } = self.$route
-      if (query && JSON.stringify(query) !== '{}') {
-        const res = await getMonthlyReportVersion(self.$route.query.reportId)
-        if (res.code === 200 && res.data) {
-          const { version } = res.data
-          if (version && version !== 'v1' && path.indexOf(`_${version}`) < 0) {
-            self.$router.push({ path: `${self.$route.path.replace(/_.*$/, '')}_${version}`, query })
-          }
-        }
-      }
-    },
-    // 人员数据初始化
-    initPeople({ commit, state }) {
-      if (state.timeout !== null) {
-        clearTimeout(state.timeout)
-      }
-      state.timeout = setTimeout(async() => {
-        const res = await getListPerson({ memberIDAPs: state.peopleLists })
-        if (res.code === 200 && res.data && res.data.length) {
-          const userNames = {}
-          res.data.forEach(elm => {
-            const { idap, name } = elm
-            userNames[idap] = name
-          })
-          state.userNames = userNames
-        }
-      }, 100)
-    },
-    // 重新拉取线上问题的 SubTitle,只在tableData数据变化时更新
-    async pullOnlineQuestion({ state }, { domKey, route }) {
-      // 获取数据
-      let baseData = {}
-      let { subReportId } = route.query
-      const [tabKey, subTabKey] = state.subTabsActive
-      if (!subReportId) {
-        subReportId = state.tabsActive.replace(/tab_/, '')
-      }
-      //
-      const tabDataObj = {
-        tabKey: '',
-        subTabKey: ''
-      }
-      const setValue = (item, key, value) => {
-        if (item.domKey === value) {
-          tabDataObj[key] = item
-        }
-      }
-      const find = (arr) => {
-        arr &&
-          arr.length &&
-          arr.forEach((elm) => {
-            setValue(elm, 'tabKey', tabKey)
-            setValue(elm, 'subTabKey', subTabKey)
-            if (elm.domKey === domKey) {
-              baseData = _.cloneDeep(elm)
-            }
-            if (elm.content && elm.content.length) {
-              find(elm.content)
-            }
-            if (elm.children && elm.children.length) {
-              find(elm.children)
-            }
-          })
-      }
-      find(state.tabPageData.children)
-      // 转换数据
-      const tableRows = objToArr(baseData.content[1].tableRows, baseData.content[1].tableHeaders)
-      const res = await pullSubTitle({
-        subReportId,
-        catalogTitle: '线上问题',
-        isServer: tabDataObj.tabKey.title ? tabDataObj.tabKey.title === '服务端' : true,
-        tableRows
-      })
-      // 覆盖数据
-      const setSubTitle = (arr) => {
-        arr &&
-          arr.length &&
-          arr.forEach((elm) => {
-            if (elm.domKey === domKey) {
-              elm.subTitles = res.data
-            }
-            if (elm.content && elm.content.length) {
-              setSubTitle(elm.content)
-            }
-            if (elm.children && elm.children.length) {
-              setSubTitle(elm.children)
-            }
-          })
-      }
-      const tabPageData = { ...state.tabPageData }
-      setSubTitle(tabPageData.children)
-      state.tabPageData = { ...tabPageData }
-    }
+    ...baseActionsData
   }
 }

+ 17 - 0
src/store/modules/monthlyReport/read/index.js

@@ -0,0 +1,17 @@
+import baseStateData from '../baseMixin/state.js'
+import baseActionsData from '../baseMixin/actions.js'
+import baseMutationsData from '../baseMixin/mutations.js'
+
+export default {
+  /* 月报编辑 */
+  namespaced: true,
+  state: {
+    ...baseStateData
+  },
+  mutations: {
+    ...baseMutationsData
+  },
+  actions: {
+    ...baseActionsData
+  }
+}

+ 19 - 6
src/store/modules/monthlyReport/edit/utils.js → src/store/modules/monthlyReport/utils/index.js

@@ -34,7 +34,7 @@ export function setReportData(obj, line = 6) {
             setTableHeader(item.tableHeaders)
             const { newObj, peopleList } = arrToObj(item.tableRows, item.tableHeaders)
             item.tableRows = newObj
-            peopleLists = Array.from(new Set([...peopleLists, ...peopleList]))
+            peopleLists = Array.from(new Set([...peopleLists, ...peopleList])).filter(elm => elm.search(/null|\\\\/g) < 0 && elm.indexOf('\\') < 0)
           }
         })
       }
@@ -45,7 +45,7 @@ export function setReportData(obj, line = 6) {
   }
   if (newObj && newObj.children && newObj.children.length) {
     setDomInfo(newObj.children)
-    return { newObj, domKeys, peopleLists }
+    return { newObj, domKeys, peopleLists: peopleLists.filter(elm => elm.search(/null|\\\\/g) < 0 && elm.indexOf('\\') < 0) }
   }
   return {}
 }
@@ -146,7 +146,6 @@ export function arrToObj(arr, headerList) {
           if (selectType && selectType === 'MultiplePeople') {
             obj[headerKey] = strToArr(obj[headerKey])
             peopleList = Array.from(new Set([...peopleList, ...obj[headerKey]]))
-            // console.log({ peopleList })
           }
         }
         if (item.operationTarget) {
@@ -158,7 +157,16 @@ export function arrToObj(arr, headerList) {
       }
     })
     obj.rowKey = uuid10()
-    obj.analyticFeedback = analyticFeedbackToObj(elm.analyticFeedback)
+    const analyticFeedback = analyticFeedbackToObj(elm.analyticFeedback)
+    obj.analyticFeedback = analyticFeedback.newObj
+    // peopleList = Array.from(new Set([...peopleList, ...[analyticFeedback.peopleList ? analyticFeedback.peopleList : []]]))
+    obj.analyticFeedbackList = elm.analyticFeedbackList ? elm.analyticFeedbackList.map(elmL => {
+      const analyticFeedback = analyticFeedbackToObj(elmL)
+      if (analyticFeedback.peopleList && analyticFeedback.peopleList.length) {
+        peopleList = Array.from(new Set([...peopleList, ...analyticFeedback.peopleList]))
+      }
+      return analyticFeedback.newObj
+    }) : elm.analyticFeedbackList
     obj.rowId = `${elm.rowId}`
     obj.operationTargetShow = false
     newObj.push(obj)
@@ -167,16 +175,20 @@ export function arrToObj(arr, headerList) {
 }
 export function analyticFeedbackToObj(obj) {
   const newObj = _.cloneDeep(obj)
+  const peopleLists = []
   newObj &&
   newObj.analyticContents &&
   _.isArray(newObj.analyticContents) &&
   newObj.analyticContents.forEach((elm) => {
     _.isArray(elm.improvementItems) &&
     elm.improvementItems.forEach((item) => {
-      item.personInCharge = item.personInCharge ? strToArr(item.personInCharge) : []
+      if (item.personInCharge && item.personInCharge.search(/\[|\]/g) > -1) {
+        item.personInCharge = item.personInCharge ? strToArr(item.personInCharge) : []
+      }
+      // peopleLists = Array.from(new Set([...peopleLists, ...item.personInCharge]))
     })
   })
-  return newObj
+  return { newObj, peopleLists: peopleLists.filter(elm => elm.search(/null|\\\\/g) < 0 && elm.indexOf('\\') < 0) }
 }
 
 // 月报:elm组件数据转表格数据
@@ -234,6 +246,7 @@ export function objToArr(obj, tableHeaders) {
       }
     })
     elms.analyticFeedback = analyticFeedbackToArr(elm.analyticFeedback)
+    elms.analyticFeedbackList = elm.analyticFeedbackList ? elm.analyticFeedbackList.map(elmChil => analyticFeedbackToArr(elmChil)) : elm.analyticFeedbackList
     elms.rowId = `${elm.rowId}`
     newArr.push(elms)
   })

+ 62 - 0
src/views/dataBigManage/components/drawerModal/drawerModalData.js

@@ -388,6 +388,68 @@ export const columns = {
         align: 'center'
       }
     ],
+    // 任务人力
+    taskPeopleColumns: [
+      {
+        label: '优先级',
+        key: 'priorityStr',
+        minWidth: 50,
+        type: 'level',
+        align: 'left'
+      },
+      {
+        label: '任务名称',
+        key: 'name',
+        minWidth: 200,
+        align: 'left',
+        type: 'topTitle',
+        topName: 'REQUIREMENT',
+        topKey: 'id'
+      },
+      {
+        label: '任务使用人力',
+        key: 'title',
+        minWidth: 90,
+        tips: '团队成员参与的在统计时间范围内任务状态在"已排期"到"已上线"(不包含)状态的任务,或在统计时间范围内变更为已上线的任务',
+        align: 'center'
+      },
+      {
+        label: '状态',
+        key: 'statusStr',
+        minWidth: 90,
+        align: 'center'
+      }
+    ],
+    taskPeopleColumnsTips: [
+      {
+        label: '任务使用人力',
+        key: 'title',
+        minWidth: 90,
+        tips: '团队成员参与的在统计时间范围内需求状态在"已排期"到"已上线"(不包含)状态的需求,或在统计时间范围内变更为已上线的需求',
+        align: 'center'
+      },
+      {
+        label: '开发人力',
+        key: 'title',
+        minWidth: 90,
+        tips: '计算范围内任务,开发、联调、提测、上线排期人日总量 / 参与计算的任务总量',
+        align: 'center'
+      },
+      {
+        label: '测试人力',
+        key: 'title',
+        minWidth: 90,
+        tips: '计算范围内任务,任务用例、测试、准出、上线排期人日总量 / 参与计算的任务总量',
+        align: 'center'
+      },
+      {
+        label: '联调人力',
+        key: 'title',
+        minWidth: 90,
+        tips: '计算范围内任务,任务联调排期人日总量 / 参与计算的任务总量',
+        align: 'center'
+      }
+    ],
     // 缺陷修复时长
     bugRepairDataColumns: [
       {

+ 41 - 5
src/views/dataBigManage/components/drawerModal/index.vue

@@ -87,7 +87,7 @@
       <!-- 质量:上线次数 -->
       <template #deployStartTsSlot="{scope}">
         <div @click.stop>
-          <div>{{ moment(scope.row.deployStartTs * 1000).format("YYYY-MM-DD hh:mm:ss") }}</div>
+          <div>{{ moment(scope.row.deployStartTs * 1000).format("YYYY-MM-DD HH:mm:ss") }}</div>
         </div>
       </template>
     </dmTable>
@@ -127,6 +127,7 @@ import {
   getRequireAvgData, // 需求平均交付周期
   getTaskData, // 任务平均交付周期
   getRequirePeopleData, // 平均需求使用人力
+  getTaskPeopleData, // 平均任务使用人力
   getDelayLaunchData, // 延期提测率
   getDelayReleaseData, // 延期准出率
   bugRepairData, // 缺陷24小时修复率
@@ -272,6 +273,9 @@ export default {
         if (this.drawerData.label === '平均需求使用人力') {
           this.title = '需求人力'
         }
+        if (this.drawerData.label === '平均任务使用人力') {
+          this.title = '任务人力'
+        }
         if (this.drawerData.label === '缺陷平均修复时长') {
           this.title = '缺陷修复时长'
         }
@@ -386,6 +390,9 @@ export default {
                   if (label === '平均需求使用人力') {
                     label = '需求使用人力'
                   }
+                  if (label === '平均任务使用人力') {
+                    label = '任务使用人力'
+                  }
                   if (this.drawerData.label === '缺陷平均修复时长') {
                     label = '全部'
                   }
@@ -408,7 +415,7 @@ export default {
       paging.pageSize = value
       this.paging = _.cloneDeep(paging)
       window.localStorage.setItem('pageSize', value)
-      if (this.headerTitle === '效率' && this.title !== '需求人力') {
+      if (this.headerTitle === '效率' && this.title !== '需求人力' && this.title !== '任务人力') {
         this.tableListPagination()
       } else {
         this.setTableList()
@@ -420,7 +427,7 @@ export default {
       paging.curIndex = value
       this.paging = _.cloneDeep(paging)
       // console.log(this.title)
-      if (this.headerTitle === '效率' && this.title !== '需求人力') {
+      if (this.headerTitle === '效率' && this.title !== '需求人力' && this.title !== '任务人力') {
         this.tableListPagination()
       } else {
         this.setTableList()
@@ -471,6 +478,9 @@ export default {
         if (this.title === '需求人力') {
           columnsKey = 'requirementPeopleColumns'
         }
+        if (this.title === '任务人力') {
+          columnsKey = 'taskPeopleColumns'
+        }
         if (this.title === '延期提测率') {
           columnsKey = 'delayLaunchDataColumns'
         }
@@ -482,7 +492,7 @@ export default {
         }
         const columnsTipsKey = `${columnsKey}Tips`
         this.column = columns.efficiency[columnsKey].map((elm, index) => {
-          if (index === 2 && this.title.search(/任务周期|需求人力|需求周期/) > -1) {
+          if (index === 2 && this.title.search(/任务周期|需求人力|任务人力|需求周期/) > -1) {
             return columns.efficiency[columnsTipsKey][this.timelineData.firstActive || 0]
           }
           return elm
@@ -607,6 +617,12 @@ export default {
             this.setRequirePeopleData()
           }
         }
+        if (this.title === '任务人力') {
+          if (this.sourceData[0].IdList.length) {
+            this.loading = true
+            this.setTaskPeopleData()
+          }
+        }
         if (this.title === '缺陷修复时长') {
           if (this.sourceData[0].IdList.length) {
             this.loading = true
@@ -810,6 +826,26 @@ export default {
         this.loading = false
       }
     },
+    // 平均任务使用人力
+    async setTaskPeopleData() {
+      const paging = this.paging
+      const params = {
+        ...paging,
+        title: this.timelineData.first[this.timelineData.firstActive],
+        ids: this.sourceData[0].IdList
+      }
+      delete params.pageTotal
+      const res = await getTaskPeopleData(params)
+      if (res.code === 200) {
+        // console.log(res.data)
+        this.tableList = res.data
+        // this.tableListOld = res.data.length && res.data.map(e => e)
+        // this.tableListPagination()
+        paging.pageTotal = this.sourceData[0].IdList.length
+        this.paging = { ...paging }
+        this.loading = false
+      }
+    },
     // 缺陷平均修复时长
     async setBugRepair2Data() {
       const paging = this.paging
@@ -915,7 +951,7 @@ export default {
         this.tableHeight = 'calc(100vh - 290px)'
       } else if (this.title.search(/状态停留分布图数据|状态累积流量图数据/) > -1) {
         this.tableHeight = 'calc(100vh - 363px)'
-      } else if (this.title.search(/需求周期|新增项目|新增任务|reopen|新增缺陷|需求人力|任务周期|缺陷修复时长|延期准出率|延期提测率/) > -1) {
+      } else if (this.title.search(/需求周期|新增项目|新增任务|reopen|新增缺陷|需求人力|任务人力|任务周期|缺陷修复时长|延期准出率|延期提测率/) > -1) {
         this.tableHeight = 'calc(100vh - 288px)'
       } else if (this.title.search(/需求|任务|项目/) > -1) {
         // 吞吐量: 需求

+ 52 - 10
src/views/dataBigManage/components/efficiencyModule/index.vue

@@ -52,7 +52,7 @@
       <div v-if="mainData.requirementPeopleData" class="itemBox" style="border-left-color: #7ED321; background: #F7FDF2">
         <div class="titleLevel3" style="color: #7ED321;">平均需求使用人力</div>
         <div class="content">
-          <div class="item effic" style="color: #7ED321;margin-bottom: 20px;">
+          <div class="item effic" style="color: #7ED321;">
             <span
               class="num"
               @click.stop="$emit(
@@ -204,15 +204,57 @@
       </div>
     </el-col>
     <el-col :span="7">
-      <div
-        v-if="Object.keys(mainData).filter(t => mainData[t]).length >= 7"
-        class="itemBox"
-        style="border-left-color: #999999; background: #FAFAFA"
-      >
-        <div class="empty">
-          <svg-icon icon-class="empty" />
+      <div v-if="mainData.requirementPeopleData" class="itemBox" style="border-left-color: #999999; background: #F7FDF2">
+        <div class="titleLevel3" style="color: #999999;">平均任务使用人力</div>
+        <div class="content">
+          <div class="item effic" style="color: #999999;">
+            <span
+              class="num"
+              @click.stop="$emit(
+                'checkDetialModal',
+                { ...mainData.taskPeopleData, activeLabel: mainData.taskPeopleData.label }
+              )"
+            >{{ mainData.taskPeopleData.countStr }}</span>
+            <span class="unit">人/日</span>
+          </div>
+          <div class="item point" style="margin-bottom: 20px;">
+            <span class="title">环比:</span>
+            <span
+              :class="Number(mainData.taskPeopleData.chainRatio) > 0 ? 'item-up num' : 'item-down num'"
+              @click.stop="$emit(
+                'checkDetialModal',
+                { ...mainData.taskPeopleData, activeLabel: mainData.taskPeopleData.label }
+              )"
+            >
+              <i v-if="Number(mainData.taskPeopleData.chainRatio) > 0" class="el-icon-caret-top" />
+              <i v-else class="el-icon-caret-bottom" />
+              {{ mainData.taskPeopleData.chainRatio }}%
+            </span>
+          </div>
+        </div>
+        <div class="foot">
+          <div
+            v-for="item in mainData.taskPeopleData.subCountList"
+            :key="item.label"
+            class="item"
+            @click.stop="$emit(
+              'checkDetialModal',
+              { ...mainData.taskPeopleData, activeLabel: item.label }
+            )"
+          >
+            <span class="title">{{ item.label }}:</span><span class="value"><span class="num">{{ item.countStr }}</span>{{ item.unit }}</span>
+          </div>
         </div>
       </div>
+<!--      <div-->
+<!--        v-if="Object.keys(mainData).filter(t => mainData[t]).length >= 7"-->
+<!--        class="itemBox"-->
+<!--        style="border-left-color: #999999; background: #FAFAFA"-->
+<!--      >-->
+<!--        <div class="empty">-->
+<!--          <svg-icon icon-class="empty" />-->
+<!--        </div>-->
+<!--      </div>-->
     </el-col>
     <el-col :span="6">
       <div v-if="mainData.bugAvgOneDataRepairData" class="itemBox" style="border-left-color: #C97DE9; background: #FCF8FE">
@@ -330,7 +372,7 @@ export default {
     border-radius: 6px;
     margin-bottom: 10px;
     .itemBox {
-      height: 134px;
+      height: 120px;
       border-left: 4px solid transparent;
       margin-bottom: 10px;
       border-radius: 6px;
@@ -344,7 +386,7 @@ export default {
       .content {
         .item {
           display: inline-block;
-          margin: 12px 16px 30px 0;
+          margin: 12px 16px 20px 0;
           .num {
             font-size: 18px;
             cursor: pointer;

+ 3 - 2
src/views/dataBigManage/index.vue

@@ -12,8 +12,9 @@
       <div class="select-group teamDrop">
         <el-dropdown placement="top-start" trigger="click">
           <span class="el-dropdown-link">
-          {{ departmentName && departmentName.length > 6 ? departmentName.substring(0, 11) + '...' : departmentName }}
-          <i class="el-icon-arrow-down el-icon--right" />
+            团队
+            <!-- {{ departmentName && departmentName.length > 6 ? departmentName.substring(0, 11) + '...' : departmentName }} -->
+            <i class="el-icon-arrow-down el-icon--right" />
           </span>
           <el-dropdown-menu slot="dropdown" class="dropTeam">
             <div class="team-val">组织结构</div>

+ 1 - 1
src/views/home/index.vue

@@ -40,7 +40,7 @@
           <span style="font-size: 17pt;">一站式质量效率平台,普惠你的工作</span><br>
           <el-button plain class="enter-button" @click.native="handleSelect('4')"><svg-icon icon-class="project-enter" />项目管理</el-button>
           <el-button plain class="enter-button" @click.native="handleSelect('1')"><svg-icon icon-class="env-enter" />环境管理</el-button>
-          <!-- <el-button plain class="enter-button" @click.native="handleSelect('playback')"><svg-icon icon-class="playback-enter" />流量回放</el-button> -->
+          <el-button plain class="enter-button" @click.native="handleSelect('playback')"><svg-icon icon-class="playback-enter" />流量回放</el-button>
           <el-button plain class="enter-button" @click.native="handleSelect('9')"><svg-icon icon-class="tool-enter" />工具集合</el-button>
         </div>
         <div class="home-carousel">

+ 234 - 44
src/views/monthlyReport/childrenPage/editReport/components/MrTable/Analysis.vue

@@ -12,13 +12,32 @@
       @succes="updateModule"
       @cancel="normalDialogCancel"
     >
+      <!-- 替代反馈人员 -->
+      <div v-show="isFeedbackCharge()" class="el-form-item">
+        <div class="el-form-item__label">
+          <span style="color: red">*</span>&nbsp;&nbsp;替代反馈人员
+        </div>
+        <div class="el-form-item__content">
+          <el-select v-model="feedbackCharge" placeholder="请选择" size="mall">
+            <el-option
+              v-for="(item, itemIndex) in userNamesList.filter(elm => isCommittedUser.indexOf(elm.value) < 0)"
+              :key="itemIndex"
+              :label="item.label"
+              :value="item.value">
+              {{ item.label }}
+            </el-option>
+          </el-select>
+        </div>
+      </div>
       <div class="box-wrapper">
-        <span v-if="analyticFeedback && analyticFeedback.analyticContents">
-          <el-form
-            v-for="(item, index) in analyticFeedback.analyticContents"
-            :key="index"
-            class="analysis-wrapper"
-          >
+        <span v-if="analyticFeedbackList">
+          <span v-for="(parentItem, parentItemIndex) in analyticFeedbackList " :key="parentItemIndex">
+            <span v-if="parentItem && parentItem.analyticContents && parentItem.feedbackCharge === feedbackCharge">
+              <el-form
+              v-for="(item, index) in parentItem.analyticContents"
+              :key="index"
+              class="analysis-wrapper"
+            >
             <span class="del-item">
               <el-button
                 icon="el-icon-delete"
@@ -29,14 +48,14 @@
               <el-input
                 v-model="item.problem"
                 size="small"
-                placeholder="请输入内容"
+                placeholder="该问题反馈出团队或团队同学存在什么问题?"
               />
             </el-form-item>
             <el-form-item label="原因" :label-width="formLabelWidth">
               <el-input
                 v-model="item.reason"
                 size="small"
-                placeholder="请输入内容"
+                placeholder="该问题是什么原因导致的?"
               />
             </el-form-item>
             <el-form-item label="改进项" :label-width="formLabelWidth">
@@ -104,17 +123,32 @@
                 icon="el-icon-plus"
                 style="position: relative;z-index: 1;"
                 @click.stop="addSubItem(index)"
-                >新增改进项</el-button>
+              >新增改进项</el-button>
             </el-form-item>
           </el-form>
+            </span>
+          </span>
         </span>
       </div>
       <el-button
+        v-if="feedbackCharge"
         type="text"
         icon="el-icon-plus"
         @click.stop="addItem"
         >新增问题
       </el-button>
+      <!-- 反思与思考 -->
+      <div v-if="feedbackCharge" class="contentItem-wrapper">
+        <div class="contentItem_title">反思与思考</div>
+        <normal-area
+          :id="normalAreaId"
+          :value="contentItem"
+          default-placeholder="管理者思考和当事人思考"
+          :height="200"
+          :full-position-style="{ top: '20px', left: '15%', right: '15%' }"
+          @change="setContentItem"
+        />
+      </div>
       <template slot="save">
         <el-button
           type="primary"
@@ -146,58 +180,176 @@
 import _ from 'lodash'
 import normalDialog from '@/components/dialog/normalDialog'
 import searchPeople from '@/components/select/searchPeople' // 人员select
+import normalArea from '@/components/input/normalArea'
+// import { ret } from '@/store/modules/monthlyReport/utils' // 富文本
 
 export default {
   name: 'Analysis',
-  components: { normalDialog, searchPeople },
+  components: { normalDialog, searchPeople, normalArea },
   data() {
     return {
       rowIndex: '',
       isBg: false,
-      analyticFeedback: '',
-      formLabelWidth: '80px'
+      isReplaceTheFeedbackPerson: false,
+      analyticFeedbackList: '',
+      formLabelWidth: '80px',
+      row: '',
+      options: [],
+      // contentItem: '',
+      feedbackCharge: '', // 重点问题 需要反馈的人
+      userNamesList: [],
+      isCommittedUser: [],
+      normalAreaId: 'item_domKey_h430sj210dajds93mscsbj' + new Date().getTime(),
+      columns: ''
+    }
+  },
+  computed: {
+    contentItem() {
+      let str = ''
+      this.analyticFeedbackList && this.analyticFeedbackList.length && this.analyticFeedbackList.forEach(elm => {
+        if (elm && elm.feedbackCharge && elm.feedbackCharge === this.feedbackCharge) {
+          str = elm.contentItem
+        }
+      })
+      return str
+    },
+    userNames() {
+      return this.$store.state.monthlyReportEdit.userNames
     }
   },
   methods: {
-    open(analyticFeedback, index) {
+    open(analyticFeedbackList, index, row, columns) {
       this.isBg = true
-      this.analyticFeedback = _.cloneDeep(analyticFeedback)
+      this.normalAreaId = `sdhsjkskwea__${new Date().getTime()}`
+      this.analyticFeedbackList = _.cloneDeep(analyticFeedbackList)
       this.rowIndex = _.cloneDeep(index)
       this.$refs.normalDialog.visible = true
+      row && (this.row = { ...row })
+      columns && (this.columns = [...columns])
+      this.initAnalysis()
+      this.setIsReplaceTheFeedbackPerson()
+      this.setUserNamesList()
     },
-    addItem() {
-      if (!this.analyticFeedback) {
-        this.analyticFeedback = {}
+    // 设置人员账号
+    setUserNamesList() {
+      const username = localStorage.getItem('username')
+      this.userNamesList = this.options.map(elm => ({
+        label: this.userNames[elm],
+        value: elm
+      }))
+
+      if (this.options.filter(elm => elm === username).length && this.isCommittedUser.indexOf(username) < 0) {
+        this.feedbackCharge = username
+      } else {
+        const committedUserList = this.userNamesList.filter(elm => this.isCommittedUser.indexOf(elm.value) < 0)
+        this.feedbackCharge = committedUserList.length ? committedUserList[0].value : ''
       }
-      if (!this.analyticFeedback.analyticContents) {
-        // this.analyticFeedback.analyticContents = []
-        this.$set(this.analyticFeedback, 'analyticContents', [])
+    },
+    // 设置富文本内容
+    setContentItem(value) {
+      const analyticFeedbackList = [...this.analyticFeedbackList]
+      analyticFeedbackList.forEach(elm => {
+        if (elm.feedbackCharge === this.feedbackCharge) {
+          elm.contentItem = value
+        }
+      })
+      this.analyticFeedbackList = [...analyticFeedbackList]
+    },
+    initAnalysis() {
+      let peopleKey = ''
+      // let peoples = ''
+
+      // 找到 责任人 的 headerKey
+      this.columns.forEach(clickItem => {
+        if (!peopleKey && clickItem.name === '责任人') {
+          peopleKey = clickItem.headerKey
+        }
+      })
+
+      // 找到下标的数据
+      this.options = [...this.row[peopleKey]]
+      if (!this.analyticFeedbackList || !this.analyticFeedbackList.length) {
+        this.analyticFeedbackList = this.options.map(elm => ({
+          feedbackCharge: elm,
+          analyticContents: [],
+          contentItem: ''
+        }))
+      } else {
+        this.options.forEach((elm, elmIndex) => {
+          // 找到没有提交分析反馈的人员清单
+          if (this.analyticFeedbackList[elmIndex].isCommitted && this.analyticFeedbackList[elmIndex].feedbackCharge) {
+            this.isCommittedUser.push(this.analyticFeedbackList[elmIndex].feedbackCharge)
+          }
+          if (!this.analyticFeedbackList[elmIndex]) {
+            this.analyticFeedbackList[elmIndex] = {
+              feedbackCharge: elm,
+              analyticContents: [],
+              contentItem: ''
+            }
+          }
+        })
       }
-      this.analyticFeedback.analyticContents.push({})
+    },
+    addItem() {
+      const analyticFeedbackList = [...this.analyticFeedbackList]
+      analyticFeedbackList.forEach(elm => {
+        if (elm && elm.feedbackCharge && elm.feedbackCharge === this.feedbackCharge) {
+          if (!elm.analyticContents) {
+            elm.analyticContents = []
+          } else {
+            elm.analyticContents.push({})
+          }
+        } else {
+          elm = {
+            ...elm,
+            analyticContents: [{}]
+          }
+        }
+      })
+      this.analyticFeedbackList = [...analyticFeedbackList]
       this.$forceUpdate()
     },
     delItem(index) {
-      // console.log('删除')
-      this.analyticFeedback.analyticContents.splice(index, 1)
+      // this.analyticFeedbackList.analyticContents.splice(index, 1)
+      const analyticFeedbackList = [...this.analyticFeedbackList]
+      analyticFeedbackList.forEach(elm => {
+        if (elm.feedbackCharge === this.feedbackCharge) {
+          elm.analyticContents.splice(index, 1)
+        }
+      })
+      this.analyticFeedbackList = [...analyticFeedbackList]
     },
     addSubItem(index) {
-      if (!this.analyticFeedback.analyticContents[index].improvementItems) {
-        // this.analyticFeedback.analyticContents[index].improvementItems = []
-        this.$set(
-          this.analyticFeedback.analyticContents[index],
-          'improvementItems',
-          []
-        )
+      const analyticFeedbackList = [...this.analyticFeedbackList]
+      let subIndex = -1
+      analyticFeedbackList.forEach((elm, elmIndex) => {
+        if (elm.feedbackCharge === this.feedbackCharge) {
+          subIndex = elmIndex
+        }
+      })
+      const analyticContents = [...this.analyticFeedbackList[subIndex].analyticContents]
+      let improvementItems = []
+      if (analyticContents[index] && analyticContents[index].improvementItems && analyticContents[index].improvementItems.length) {
+        improvementItems = [...analyticContents[index].improvementItems]
       }
-      this.analyticFeedback.analyticContents[index].improvementItems.push({})
-      this.$forceUpdate()
+      improvementItems.push({})
+      analyticContents[index] = {
+        ...analyticContents[index],
+        improvementItems: [...improvementItems]
+      }
+      this.$set(this.analyticFeedbackList[subIndex], 'analyticContents', [...analyticContents])
     },
     delSubItem(index, subindex) {
-      // console.log(index, subindex)
-      this.analyticFeedback.analyticContents[index].improvementItems.splice(
-        subindex,
-        1
-      )
+      const analyticFeedbackList = [...this.analyticFeedbackList]
+      analyticFeedbackList.forEach(elm => {
+        if (elm.feedbackCharge === this.feedbackCharge) {
+          elm.analyticContents[index].improvementItems.splice(
+            subindex,
+            1
+          )
+        }
+      })
+      this.analyticFeedbackList = [...analyticFeedbackList]
     },
     openDialogConfirm() {
       this.$refs['normalDialog'].visible = false
@@ -205,7 +357,6 @@ export default {
       this.isBg = true
     },
     normalDialogCancel() {
-      // console.log(210, '这里隐藏了时间', this.$refs['dialogConfirm'].visible)
       if (!this.$refs['dialogConfirm'].visible) {
         this.isBg = false
       }
@@ -216,21 +367,47 @@ export default {
       this.$refs.normalDialog.visible = true
     },
     updateModule(key) {
-      // console.log(key)
-      const { analyticFeedback, rowIndex } = this
+      const { analyticFeedbackList, rowIndex } = this
       if (key && key === 'Submission') {
-        analyticFeedback.isCommitted = true
-        analyticFeedback.feedbackType = 'feedback_commit'
+        analyticFeedbackList.forEach(elm => {
+          if (elm.feedbackCharge === this.feedbackCharge) {
+            elm.isCommitted = true
+            elm.feedbackType = 'feedback_commit'
+          }
+        })
+      } else {
+        analyticFeedbackList.forEach(elm => {
+          if (elm.feedbackCharge === this.feedbackCharge) {
+            elm.isCommitted = false
+            elm.feedbackType = ''
+          }
+        })
       }
       this.oldBaseData = _.cloneDeep(this.baseData)
       this.$emit('upData', {
-        analyticFeedback,
-        rowIndex
+        analyticFeedbackList,
+        rowIndex,
+        isFeedbackType: key === 'Submission',
+        feedbackCharge: this.feedbackCharge,
+        isReplaceTheFeedbackPerson: this.isReplaceTheFeedbackPerson
       })
       this.$refs['dialogConfirm'].visible = false
       setTimeout(() => {
         this.$refs['normalDialog'].visible = false
       }, 0)
+    },
+    // 替代反馈人员
+    setIsReplaceTheFeedbackPerson() {
+      this.isReplaceTheFeedbackPerson = !this.options.filter(elm => elm === localStorage.getItem('username')).length
+    },
+    isFeedbackCharge() {
+      if (this.analyticFeedbackList && this.analyticFeedbackList.length) {
+        // const committedUserList = this.userNamesList.filter(elm => this.isCommittedUser.indexOf(elm.value) < 0)
+        const username = localStorage.getItem('username')
+        const committedUserList = this.analyticFeedbackList.filter(elm => elm.isCommitted && elm.feedbackCharge)
+        return committedUserList.indexOf(username) < 0
+      }
+      return false
     }
   }
 }
@@ -333,6 +510,15 @@ export default {
   }
 }
 
+.contentItem-wrapper{
+  .contentItem_title{
+    font-weight: 600;
+    //font-size: 24px;
+    margin-top: 20px;
+    color: #333;
+    margin-bottom: 10px;
+  }
+}
 /deep/ .el-form-item {
   margin-bottom: 10px;
 }
@@ -357,4 +543,8 @@ export default {
   opacity: 0.5;
   background: #000;
 }
+.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{
+  color: rgb(204 207 213)!important;
+  font-weight: 400!important;
+}
 </style>

+ 4 - 1
src/views/monthlyReport/childrenPage/editReport/components/MrTable/Hold.vue

@@ -35,6 +35,7 @@ export default {
     return {
       index: '',
       subIndex: '',
+      parentIndex: '',
       ruleForm: {
         holdReason: ''
       },
@@ -46,9 +47,10 @@ export default {
     }
   },
   methods: {
-    open(index, subIndex, holdReason) {
+    open(index, subIndex, holdReason, parentIndex) {
       this.index = index
       this.subIndex = subIndex
+      this.parentIndex = parentIndex
       this.ruleForm.holdReason = holdReason
       this.$refs.normalDialog.visible = true
     },
@@ -60,6 +62,7 @@ export default {
           this.$emit('upData', {
             index: this.index,
             subIndex: this.subIndex,
+            parentIndex: this.parentIndex,
             holdReason: this.ruleForm.holdReason
           })
           this.$refs.normalDialog.visible = false

+ 10 - 0
src/views/monthlyReport/childrenPage/editReport/components/MrTable/TableExpandRow.vue

@@ -113,6 +113,16 @@ export default {
   name: 'TableExpandRow',
   components: { MultiplePeopleInfo, Hold },
   props: {
+    // columns: {
+    //   type: Object,
+    //   required: false,
+    //   default: null
+    // },
+    // row: {
+    //   type: Object,
+    //   required: false,
+    //   default: null
+    // },
     analyticFeedback: {
       type: Object,
       required: false,

+ 394 - 0
src/views/monthlyReport/childrenPage/editReport/components/MrTable/TableExpandRowList.vue

@@ -0,0 +1,394 @@
+<template>
+  <div class="TableExpandRowList-wrapper">
+    <div>
+      <div v-for="(parentItem, parentIndex) in analyticFeedbackList" :key="parentIndex">
+        <div v-if="parentItem && parentItem.feedbackCharge && parentItem.analyticContents && parentItem.analyticContents.length" style="margin-bottom: 30px;">
+          <div v-if="parentItem && parentItem.feedbackCharge " class="contentItem-wrapper-feedbackCharge">
+            <MultiplePeopleInfo
+              class="contentItem-wrapper-MultiplePeopleInfo"
+              :team-data="[parentItem.feedbackCharge]"
+            />
+<!--            <div class="identity">负责人</div>-->
+            <div v-if="parentItem.feedbackBy" class="contentItem-wrapper-feedbackBy">
+              <span class="by">by</span> <MultiplePeopleInfo
+              class="contentItem-wrapper-MultiplePeopleInfo"
+              :team-data="[parentItem.feedbackBy]"
+            />
+            </div>
+          </div>
+
+          <div v-if="parentItem && parentItem.analyticContents && parentItem.analyticContents.length">
+            <div
+              v-for="(item, index) in parentItem.analyticContents"
+              :key="index"
+              class="analyticContents-wrapper"
+            >
+              <!--序号-->
+              <div>
+                <span class="item-index">{{ index + 1 }}</span>
+              </div>
+              <!--问题-->
+              <span class="item-title">问题:</span>
+              <span class="item-content">{{ item.problem }}</span>
+              <br>
+              <!--原因-->
+              <span class="item-title">原因:</span>
+              <span class="item-content">{{ item.reason }}</span>
+              <br>
+              <!--改进项-->
+              <span class="item-title">改进项:</span>
+              <span v-if="item.improvementItems && item.improvementItems.length">
+                <div
+                  v-for="(subItem, subIndex) in item.improvementItems"
+                  :key="subIndex"
+                  class="improvementItems-wrapper"
+                >
+                  <!--改进项: 描述-->
+                  <div>{{ subIndex + 1 }}、{{ subItem.description }}{{ subItem.detail && ':' }}{{ subItem.detail }}</div>
+                  <!--改进项: 其他-->
+                  <div class="description-wrapper">
+                    <!--改进项: 责任人-->
+                    <span style="min-width: 50px;display: inline-block;"><span class="new-title">责任人:</span><span v-if="!subItem.personInCharge || !subItem.personInCharge.length">暂无负责人</span>
+                      <MultiplePeopleInfo
+                        v-else
+                        style="display:inline-block "
+                        :team-data="subItem.personInCharge"
+                      />
+                    </span>
+                    <!--改进项: 计划完成时间-->
+                    <span style="min-width: 120px;max-width: 200px;display: inline-block;margin-right: 40px;margin-left: 30px;">计划完成时间:{{ rTime(subItem.deadline) }}</span>
+                    <!--改进项: 进度-->
+                    <span
+                      class="progress-wrapper"
+                      :style="{ width: !subItem.isProgressEdit ? '300px' : '380px' }"
+                    ><span class="new-title">进度:</span><span v-if="!subItem.isProgressEdit">{{
+                        subItem.progress || '0'
+                      }}</span
+                    ><span v-else>
+                        <el-input-number
+                          v-model="subItem.progress"
+                          controls-position="right"
+                          size="small"
+                          style="width:100px"
+                          :min="0"
+                          :max="100" /></span
+                    >%<el-button
+                      v-if="subItem.isProgressEdit"
+                      type="text"
+                      @click.stop="progressEdit(subItem)"
+                    >
+                      保存
+                    </el-button>
+                      <el-tooltip
+                        v-if="subItem.isHold"
+                        class="item"
+                        effect="dark"
+                        :content="subItem.holdReason"
+                        placement="top"
+                      >
+                        <span class="isHold">Hold</span>
+                      </el-tooltip>
+                      <!--改进项: 进度更新-->
+                      <span
+                        class="up-progress"
+                        :style="{ width: !subItem.isHold ? '60px' : '60px' }"
+                      ><span
+                        v-if="
+                            (!subItem.personInCharge ||
+                              subItem.personInCharge.indexOf(username) > -1) &&
+                              !subItem.isHold
+                          "
+                        @click.stop="progressEdit(subItem)"
+                      >进度更新</span
+                      ></span
+                      >
+                      <!--改进项: Hold-->
+                      <span
+                        v-if=" !subItem.personInCharge || subItem.personInCharge.indexOf(username) > -1 "
+                        class="Hold"
+                        @click.stop="setHold(index, subIndex, subItem,parentIndex)"
+                      >{{ subItem.isHold ? '解除Hold' : 'Hold' }}</span
+                      >
+                    </span>
+                  </div>
+                </div>
+              </span>
+              <!--责任人: 计划完成时间:进度-->
+            </div>
+            <div class="contentItem-wrapper-title">反思与思考</div>
+            <div class="contentItem-wrapper-content" v-html="parentItem.contentItem" />
+            <div v-if="!parentItem.contentItem" style="padding-bottom: 10px;padding-left: 0;font-size: 14px">暂无反思与思考!</div>
+          </div>
+          <div v-else style="padding-bottom: 0px;padding-left: 0;font-size: 14px">暂无分析反馈数据!</div>
+        </div>
+      </div>
+<!--      <div v-if="!analyticFeedbackList" style="padding-bottom: 20px;padding-top: 10px;padding-left: 0;font-size: 14px">暂无分析反馈数据!</div>-->
+      <Hold ref="Hold" @upData="upHold" />
+    </div>
+  </div>
+</template>
+
+<script>
+import MultiplePeopleInfo from '../MultiplePeopleInfo'
+import _ from 'lodash'
+import Hold from './Hold'
+
+export default {
+  name: 'TableExpandRow',
+  components: { MultiplePeopleInfo, Hold },
+  props: {
+    // columns: {
+    //   type: Object,
+    //   required: false,
+    //   default: null
+    // },
+    // row: {
+    //   type: Object,
+    //   required: false,
+    //   default: null
+    // },
+    analyticFeedbackList: {
+      type: Array,
+      required: false,
+      default: null
+    }
+  },
+  data() {
+    return {
+      username: localStorage.getItem('username')
+    }
+  },
+  methods: {
+    setHold(index, subIndex, subItem, parentIndex) {
+      subItem.isProgressEdit = false
+      // console.log(this.analyticFeedback)
+      if (subItem.isHold) {
+        subItem.isHold = false
+        this.$forceUpdate()
+        return
+      }
+      this.$refs.Hold.open(index, subIndex, subItem.holdReason, parentIndex)
+    },
+    upHold({ index, subIndex, holdReason, parentIndex }) {
+      console.log({ index, subIndex, holdReason, analyticFeedbackList: this.analyticFeedbackList })
+      this.analyticFeedbackList[parentIndex].analyticContents[index].improvementItems[
+        subIndex
+      ].isHold = true
+      if (holdReason) {
+        window.log({ c: 'report_view', d: 'report_view_Feeback_hold' })
+        this.analyticFeedbackList[parentIndex].analyticContents[index].improvementItems[
+          subIndex
+        ].holdReason = holdReason
+      }
+      this.$forceUpdate()
+      this.$emit('upAnalyticFeedback')
+    },
+    // 处理日期格式:JS - 2020-01-01T00:00:00.000000Z 日期格式转换
+    rTime(date) {
+      if (!date) return ''
+      var json_date = new Date(date).toJSON()
+      return new Date(new Date(json_date) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '').replace(/00:00:00/, '')
+    },
+    progressEdit(item) {
+      if (!_.isBoolean(item.isProgressEdit)) {
+        item.isProgressEdit = false
+      }
+      if (_.isNaN(Number.parseInt(item.progress))) {
+        item.progress = 0
+      }
+      item.isProgressEdit = !item.isProgressEdit
+      window.log({ c: 'report_view', d: 'report_view_Feedback_upload' })
+      this.$forceUpdate()
+      this.$emit('upAnalyticFeedback')
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+.TableExpandRowList-wrapper {
+  .analyticContents-wrapper {
+    .text-hide {
+      overflow: hidden; //超出的文本隐藏
+      text-overflow: ellipsis; //溢出用省略号显示
+      white-space: nowrap; //溢出不换行
+    }
+
+    color: #333333;
+    position: relative;
+    // border-bottom: 1px solid #EBEEF5;
+    padding-bottom: 10px;
+    margin-bottom: 10px;
+    font-size: 14px;
+
+    //&::after {
+    //  content: '';
+    //  position: absolute;
+    //  bottom: 0;
+    //  left: -50px;
+    //  right: -50px;
+    //  height: 1px;
+    //  border-bottom: 1px solid #ebeef5;
+    //}
+
+    &:nth-last-child(2) &:nth-last-child(1) {
+      background: #0eb400;
+      border-bottom: 0;
+      padding-bottom: 0;
+      margin-bottom: 0;
+
+      &::after {
+        border-bottom: 0;
+      }
+    }
+
+    .item-index {
+      position: absolute;
+      left: -26px;
+      text-align: center;
+      color: #fff;
+      width: 16px;
+      height: 16px;
+      line-height: 1;
+      background: #1890ff;
+      border-radius: 50%;
+      opacity: 1;
+      display: inline-block;
+    }
+
+    .item-title {
+      color: #666666;
+      margin-bottom: 5px;
+    }
+
+    .item-content {
+      margin-bottom: 5px;
+    }
+
+    .progress-wrapper {
+      width: 75px;
+      display: inline-block;
+      margin-right: 60px;
+      position: relative;
+
+      .isHold {
+        position: absolute;
+        background: #e8e8e8;
+        border-radius: 2px;
+        font-size: 0.25em;
+        line-height: 15px;
+        color: #666666;
+        top: -10px;
+        padding: 0 3px;
+        cursor: pointer;
+
+        &:hover {
+          .holdReason {
+            display: block;
+          }
+        }
+
+        .holdReason {
+          display: none;
+          position: absolute;
+          bottom: 18px;
+          left: 30px;
+          min-width: 90px;
+          background: #e8e8e8;
+          min-height: 14px;
+          z-index: 9999;
+          box-sizing: content-box;
+          padding: 10px;
+          border-radius: 10px;
+        }
+      }
+    }
+
+    .up-progress {
+      color: #1890ff;
+      display: inline-block;
+      // width: 50px;
+      margin: 0 20px 0 50px;
+      // margin-right: 10px;
+      cursor: pointer;
+    }
+
+    .Hold {
+      color: #1890ff;
+      display: inline-block;
+      cursor: pointer;
+    }
+    .new-title{
+      color: #666666;
+    }
+    // .description-wrapper {
+    // }
+    // .item-problem {
+    // }
+    // .item-reason {
+    // }
+    .improvementItems-wrapper {
+      margin-bottom: 20px;
+      padding-left: 28px;
+      &:last-child{
+        margin-bottom: 0;
+      }
+    }
+  }
+  .MultiplePeopleInfo_932n23211{
+    font-weight: 600;
+    display:inline-block;
+    text-align: center;
+    font-size: 14px
+  }
+  .contentItem-wrapper-feedbackCharge{
+    display: inline-block;
+    border-radius: 5px;
+    position: relative;
+    left: -40px;
+    border: 2px solid #00a0ff;
+    padding: 0px 5px;
+    text-align: center;
+    padding-left: 10px;
+    margin-bottom: 10px;
+    .identity{
+      display: inline-block;
+      //position: absolute;
+      //top: 0px;
+      //right: -35px;
+      border-radius: 20px;
+      padding: 0px 5px;
+      font-size: 12px;
+      background-color: #dcedff;
+      color: #409eff;
+    }
+    .contentItem-wrapper-MultiplePeopleInfo{
+      .MultiplePeopleInfo_932n23211();
+    }
+  }
+  .contentItem-wrapper-feedbackBy {
+    position: relative;
+    //left: -35px;
+    text-align: left;
+    display: inline-block;
+    .by{
+      .MultiplePeopleInfo_932n23211();
+    }
+    .contentItem-wrapper-MultiplePeopleInfo {
+      .MultiplePeopleInfo_932n23211();
+    }
+  }
+  .contentItem-wrapper-title {
+    font-weight: 600;
+    color: #333;
+    font-size: 14px;
+  }
+  .contentItem-wrapper-content {
+    background-color: #f7f7f7;
+    padding: 10px;
+    margin-top: 5px;
+    border-radius: 5px;
+  }
+}
+
+</style>

+ 77 - 15
src/views/monthlyReport/childrenPage/editReport/components/MrTable/index.vue

@@ -35,7 +35,18 @@
           <template slot-scope="scope">
             <!--    展开    -->
             <div v-if="item.type === 'expand'">
+<!--              <div @click="showItem(item, scope)">item</div>-->
+              <TableExpandRowList
+                v-if="scope.row.analyticFeedbackList"
+                :columns="columns"
+                :row="scope.row"
+                :analytic-feedback-list="scope.row.analyticFeedbackList"
+                @upAnalyticFeedback="setAnalyticFeedback"
+              />
               <TableExpandRow
+                v-if="scope.row.analyticFeedback && !scope.row.analyticFeedbackList"
+                :columns="columns"
+                :row="scope.row"
                 :analytic-feedback="scope.row.analyticFeedback"
                 @upAnalyticFeedback="setAnalyticFeedback"
               />
@@ -289,12 +300,13 @@ import CascaderInfo from '../CascaderInfo'
 import TextInfo from '../TextInfo'
 import MultiplePeopleInfo from '../MultiplePeopleInfo'
 import TableExpandRow from './TableExpandRow'
+import TableExpandRowList from './TableExpandRowList'
 import markingIssues from '../markingIssues'
 import CascaderSingle from '../CascaderSingle'
 import CascaderSingleInfo from '../CascaderSingleInfo'
 import searchPeople from '@/components/select/searchPeople' // 人员select
 import { updateAnalyticFeedback, getDeptCharge } from '@/api/qualityMonthlyReport/edit'
-import { reportDataBack } from '@/store/modules/monthlyReport/edit/utils.js'
+import { reportDataBack } from '@/store/modules/monthlyReport/utils'
 // import { getDeptByKeyWord } from '@/api/qualityMonthlyReport'
 
 export default {
@@ -307,6 +319,7 @@ export default {
     searchPeople,
     MultiplePeopleInfo,
     TableExpandRow,
+    TableExpandRowList,
     markingIssues,
     TextInfo,
     CascaderSingle,
@@ -539,7 +552,7 @@ export default {
       }
       if (btnItem.value === '分析反馈') {
         // console.log(293, btnItem, scope)
-        this.$refs.Analysis.open(scope.row.analyticFeedback, scope.$index)
+        this.$refs.Analysis.open(scope.row.analyticFeedbackList, scope.$index, scope.row, this.columns)
       }
     },
     // 另存为
@@ -551,21 +564,34 @@ export default {
         subReportid: command.id
       })
     },
-    // 分析反馈问题更新
-    upDataAnalysis({ rowIndex, analyticFeedback }) {
-      // console.log({ rowIndex, analyticFeedback })
+    /**
+     * 分析反馈问题更新
+     * rowIndex, 提交时的下标
+     * analyticFeedbackList, 新版的分析反馈的数组,里面的各个item 对应原来的 analyticFeedback 字段
+     * feedbackCharge,
+     * isReplaceTheFeedbackPerson,
+     * isFeedbackType
+     * */
+    upDataAnalysis({ rowIndex, analyticFeedbackList, feedbackCharge, isReplaceTheFeedbackPerson, isFeedbackType }) {
+      console.log(rowIndex, analyticFeedbackList, isReplaceTheFeedbackPerson)
+      analyticFeedbackList.forEach(elm => {
+        // if (elm.feedbackCharge === feedbackCharge && isReplaceTheFeedbackPerson) {
+        if (elm.feedbackCharge === feedbackCharge && feedbackCharge !== localStorage.getItem('username')) {
+          elm.feedbackBy = localStorage.getItem('username')
+        }
+      })
       if (this.pageType.search(/edit/) < 0) {
         window.log({ c: 'report_view', d: 'report_view_Feedback' })
-        // console.log(rowIndex, analyticFeedback)
         this.feedbackIndex = rowIndex
-        this.tableData[rowIndex].analyticFeedback = _.cloneDeep(
-          analyticFeedback
+        this.tableData[rowIndex].analyticFeedbackList = _.cloneDeep(
+          analyticFeedbackList
         )
-        let feedbackType = ''
-        if (analyticFeedback.hasOwnProperty('feedbackType')) {
-          feedbackType = 'feedbackType'
-        }
-        this.setAnalyticFeedback(feedbackType)
+        // let feedbackType = ''
+        // if (analyticFeedback.hasOwnProperty('feedbackType')) {
+        //   feedbackType = 'feedbackType'
+        // }
+        this.setAnalyticFeedback(isFeedbackType ? 'feedbackType' : '', feedbackCharge)
+        this.setExpandRowKeys()
       }
     },
     addTableData() {
@@ -643,7 +669,7 @@ export default {
       }
     },
     // 查看页面数据分析
-    setAnalyticFeedback(key = '') {
+    setAnalyticFeedback(key = '', feedbackCharge = '') {
       if (
         // this.pageType.search(/edit/) < 0 &&
         // this.pageDate.status > 10 &&
@@ -676,7 +702,9 @@ export default {
           reportId: this.$route.query.reportId,
           subReportName: this.subReportName,
           feedbackIndex: this.feedbackIndex,
-          reportCatalog: obj
+          reportCatalog: obj,
+          feedbackCharge
+          // feedbackBy
         }
         if (this.$route.query.pageType === 'readAll' && obj) {
           params.subReportName = `${obj.title}`
@@ -730,6 +758,29 @@ export default {
       if (row.analyticFeedback && row.analyticFeedback.isCommitted) {
         return false
       }
+      const username = localStorage.getItem('username')
+
+      // 新版分析反馈控制显示隐藏
+      if (row.analyticFeedbackList) {
+        let peopleKey = ''
+        // let peoples = ''
+        // 找到 责任人 的 headerKey
+        this.columns.forEach(clickItem => {
+          if (!peopleKey && clickItem.name === '责任人') {
+            peopleKey = clickItem.headerKey
+          }
+        })
+        const options = [...row[peopleKey]]
+        let isNewCommitteds = []
+
+        if (row.analyticFeedbackList && row.analyticFeedbackList.length) {
+          isNewCommitteds = row.analyticFeedbackList.filter(elm => {
+            return elm && elm.isCommitted && elm.feedbackCharge
+          }).map(elm => elm.feedbackCharge)
+        }
+
+        return isNewCommitteds.length !== options.length && !isNewCommitteds.filter(elm => elm === username).length
+      }
       // 默认所有情况都展示
       if (this.pageType) {
         return true
@@ -756,6 +807,13 @@ export default {
           ) {
             this.expandRowKeys.push(elm.rowKey)
           }
+          if (
+            elm.analyticFeedbackList &&
+            elm.analyticFeedbackList.length &&
+            this.expandRowKeys.indexOf(elm.rowKey) < 0
+          ) {
+            this.expandRowKeys.push(elm.rowKey)
+          }
         })
       }
     },
@@ -791,6 +849,10 @@ export default {
       }, this.paging.timer)
     },
     /* E 分页 */
+    showItem(item, scope) {
+      console.log(item)
+      console.log(797, scope)
+    },
     // 页面跳转
     goto(url) {
       // console.log(url)

+ 3 - 1
src/views/monthlyReport/childrenPage/editReport/components/VarText.vue

@@ -14,7 +14,7 @@
         />
         <span
           v-if="pageDate.status > 10 && textValue"
-          style="padding: 10px 0;display: inline-block;line-height: 1.65;"
+          style="display: inline-block;line-height: 1.65;    background-color: #f7f7f7; padding: 10px; border-radius: 5px;"
           v-html="textValue.replace(/\n/g, '<br />')"
           />
       </div>
@@ -91,6 +91,8 @@ export default {
 
 <style scoped lang="less">
 .fixedText {
+  //margin-top: 10px;
+  padding-top: 10px;
   .top-title {
     width: 100%;
     display: flex;

+ 0 - 1
src/views/monthlyReport/childrenPage/editReport/components/core.vue

@@ -279,7 +279,6 @@ export default {
       // this.$store.commit('monthlyReportEdit/SUB_TABS_ACTIVE', this.baseData.children[0].domKey, this.activeName)
     },
     setHeader() {
-      console.log(281)
       let title = `${this.baseData.title}`
       // if (title === '发布&回滚') {
       //   this.pushAndBanckheadle()

+ 12 - 9
src/views/monthlyReport/childrenPage/editReport/index.vue

@@ -471,15 +471,18 @@ export default {
       window.open(url, '_blank')
     },
     tabClick(tab, event) {
-      this.bodyLoading = true
-      this.$store.dispatch('monthlyReportEdit/tabActiveChange', {
-        ...this.$route.query,
-        id: this.$route.query.reportId,
-        tabsActive: tab.name
-      })
-      setTimeout(() => {
-        this.bodyLoading = false
-      }, 700)
+      event.stopPropagation()
+      if (tab.name !== this.tabsActive) {
+        this.bodyLoading = true
+        this.$store.dispatch('monthlyReportEdit/tabActiveChange', {
+          ...this.$route.query,
+          id: this.$route.query.reportId,
+          tabsActive: tab.name
+        })
+        setTimeout(() => {
+          this.bodyLoading = false
+        }, 700)
+      }
     },
     dialogOpen(key) {
       if (key === 'dialogPublishAll') {

+ 466 - 0
src/views/monthlyReport/childrenPage/readReport/index.vue

@@ -0,0 +1,466 @@
+<template>
+  <div
+    v-if="indexShow"
+    ref="pageWrapper"
+    v-loading="loading"
+    class="page-wrapper"
+    @click.stop="$store.commit('monthlyReportEdit/INIT_EDIT_KEYS')"
+  >
+    <headerCom :key="subTitle" title="月报" :sub-title="subTitle" :address="address" />
+    <div class="content-wrapper">
+      <el-tabs v-if="pageType.search(/All/) > -1" :value="tabsActive" @tab-click="tabClick">
+        <el-tab-pane v-for="item in tabsList" :key="item.name" :label="item.label" :name="item.name" />
+      </el-tabs>
+      <div v-loading="bodyLoading" class="body-wrapper">
+        <div class="left-wrapper">
+          <div v-if="tabPageShow">
+            <Core
+              v-for="(item, index) in tabPageData.children"
+              :key="item.domKey"
+              :dom-index="index"
+              :base-data="item"
+            />
+          </div>
+          <div v-else style="margin-top: 30px;">暂无数据!</div>
+        </div>
+        <div class="right-wrapper">
+          <Affix
+            ref="affix"
+            v-clickoutside="$refs.menu && $refs.menu.closeMenu"
+            :listen-time="pageType.search(/read/) ? 5 : 5"
+            :offset-top="134"
+            :target="() => $refs && $refs.pageWrapper && $refs.pageWrapper.parentNode"
+            @change="userFun"
+          >
+            <div class="set_scroll" style="max-height: 570px;overflow-y: scroll;">
+              <Anchor
+                :list="tabPageData && tabPageData.children"
+                :active="anchorActive"
+                @change="anchorChange"
+                @openMenu="openMenu"
+              />
+              <Menu ref="menu" />
+            </div>
+          </Affix>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script type='text/javascript'>
+import { mapState, mapMutations, mapActions } from 'vuex'
+import headerCom from '../../components/header'
+import Affix from '@/components/affix/affix'
+import Anchor from '../editReport/components/anchor'
+import Menu from '../editReport/components/menu'
+import Core from '../editReport/components/core'
+import Clickoutside from 'element-ui/src/utils/clickoutside'
+import { projectManagementUrl } from '@/apiConfig/api'
+import { getMonthlyReportPreView, getMonthlyReportPrePdfView } from '@/api/qualityMonthlyReport/edit'
+
+export default {
+  name: '',
+  components: {
+    headerCom,
+    Affix,
+    Anchor,
+    Menu,
+    Core
+  },
+  directives: { Clickoutside },
+  data() {
+    // this.userFun = _.debounce(this.userFun, 300)
+    return {
+      /* 右侧列表页数据 */
+      anchorActive: '',
+      bodyLoading: false,
+      monthlyReportPreView: null,
+      monthlyReportPrePdfView: null,
+      scrollTop: 0
+    }
+  },
+  computed: {
+    tabPageShow() {
+      return this.tabPageData && this.tabPageData.children && this.tabPageData.children.length
+    },
+    address() {
+      let pathName = '/monthlyReport/index'
+      if (this.$route.query.reportId) {
+        pathName += `?reportId=${this.$route.query.reportId}`
+      }
+      return pathName
+    },
+    ...mapState('monthlyReportEdit',
+      ['pageDate', 'tabPageData', 'subTitle', 'tabsList', 'tabsActive', 'treeData', 'subTabsActive', 'domKeys', 'offsetList', 'pageType', 'subReportInfo', 'roleCode', 'loading']
+    )
+  },
+  watch: {
+    subTabsActive() {
+      this.$refs.affix.init()
+    }
+  },
+  created() {
+    this.INIT_STATE_DATA()
+    this.SET_LOADING(true)
+    this.indexShow = true
+    // 默认获取用户权限
+    this.getUserPermission()
+    // 获取部门数据
+    this.setSelectEnum()
+  },
+  mounted() {
+    /*
+     * read: 查看子月报
+     * readAll:查看完整月报
+     * edit:编辑子月报
+     * editAll:编辑完整月报
+     * */
+    if (this.$route.query.pageType) {
+      this.SET_PAGE_TYPE(this.$route.query.pageType)
+    }
+    // 查看
+    if (this.$route.query.pageType === 'readAll') {
+      this.SET_SUB_TITLE('查看完整月报')
+    }
+
+    if (this.$route.query.reportId || this.$route.query.subReportId) {
+      this.initPageData({
+        id: this.$route.query.reportId,
+        subActive: this.$route.query.subActive,
+        subReportId: this.$route.query.subReportId
+      })
+    }
+    // 数据埋点
+    this.monthlyReportBuriedPoint()
+    // 防止页面后退
+    if (this.$route.query.pageType.search(/edit/) > -1) {
+      history.pushState(null, null, document.URL)
+      window.addEventListener('popstate', function() {
+        history.pushState(null, null, document.URL)
+      })
+    }
+  },
+  destroyed() {
+    this.indexShow = false
+    this.INIT_STATE_DATA()
+    // 判断当前页面是否为新建页面
+    if (this.$route.query.type && this.$route.query.type === 'create') {
+      this.deleteReport({ isMsg: false })
+    }
+    // 销毁组件时,取消浏览器前进后端拦截事件
+    window.removeEventListener('popstate', function() {
+      history.pushState(null, null, document.URL)
+    })
+  },
+  methods: {
+    ...mapMutations('monthlyReportEdit',
+      ['INIT_STATE_DATA', 'SET_LOADING', 'SET_PAGE_TYPE', 'SET_SUB_TITLE']
+    ),
+    ...mapActions('monthlyReportEdit',
+      ['getUserPermission', 'deleteReport', 'setSelectEnum', 'initPageData', 'upDateReport', 'upDateSubReport', 'confirmReport']
+    ),
+    setInit() {
+      // this.$store.commit('monthlyReportEdit/INIT_EDIT_KEYS')
+      // window.addEventListener('click', () => {
+      //   this.$refs.menu.show = true
+      //   console.log(127)
+      // })
+    },
+    anchorChange(item) {
+      // 获取元素到文档区域的坐标
+      const getPosition = (element) => {
+        var actualLeft = element.offsetLeft
+        var actualTop = element.offsetTop
+        var current = element.offsetParent // 取得元素的offsetParent
+        // 一直循环直到根元素
+        while (current !== null) {
+          actualLeft += current.offsetLeft
+          actualTop += current.offsetTop
+          current = current.offsetParent
+        }
+        // 返回包含left、top坐标的对象
+        return {
+          left: actualLeft,
+          top: actualTop
+        }
+      }
+      this.anchorActive = item.domKey
+      const anchor = document.getElementById(`${item.domKey}`) // 参数为要跳转到的元素id
+
+      if (!anchor) {
+        return (this.$el.parentNode.scrollTop = 0)
+      }
+      const { top } = getPosition(anchor)
+      this.$el.parentNode.scrollTop = top // chrome
+    },
+    openMenu({ event, item }) {
+      this.$refs.menu.init({ event, item })
+      // console.log(event, item)
+    },
+    userFun({ scrollTop }) {
+      this.$nextTick(() => {
+        if (!this.tabPageData || !this.tabPageData.children) return false
+        this.$refs.menu && this.$refs.menu.closeMenu()
+        // this.anchorActive = ''
+        const getOffsetTop = (id) => {
+          const dom = document.getElementById(id)
+          if (!dom) return 0.9527
+          return dom.getBoundingClientRect().top
+        }
+        const setActive = (key) => {
+          const offsetTop = getOffsetTop(key)
+          if (offsetTop && offsetTop !== 0.9527 && Math.abs(offsetTop) < 50) {
+            this.anchorActive = key
+            return
+          }
+        }
+        const setList = (arr) => {
+          for (let index = 0; index < arr.length; index++) {
+            const element = arr[index]
+            if (element.domKey) {
+              setActive(element.domKey)
+            }
+            if (element.content && element.content.length) {
+              for (let itemIndex = 0; itemIndex < element.content.length; itemIndex++) {
+                const item = element.content[itemIndex]
+                if (item.domKey) {
+                  setActive(item.domKey)
+                }
+              }
+            }
+            if (element.children && element.children.length) {
+              setList(element.children)
+            }
+          }
+        }
+        // 每次 scroll 事件结束之后,递归计算各个标签距离窗口顶部的位置
+        setList(this.tabPageData.children)
+      })
+    },
+    // 月报更新
+    upDateReportFn(key = 'cb', confirmReportBack) {
+      this.SET_LOADING(true)
+      const method = this.pageType.search(/All/) > -1 ? 'upDateReport' : 'upDateSubReport'
+      this[method](() => {
+        confirmReportBack && confirmReportBack()
+        if (!confirmReportBack) {
+          this.SET_LOADING(false)
+        }
+        if (key === 'cb') {
+          window.log({ c: 'report_edit', d: 'report_edit_save' })
+          this.$message.success('保存成功!')
+        }
+      })
+    },
+    // 月报确认
+    confirmReport() {
+      this.$refs['dialogConfirm'].visible = false
+      this.upDateReportFn('nocb', () => {
+        this.$store.dispatch('monthlyReportEdit/confirmReport', {
+          id: this.$route.query.subReportId,
+          callback: () => {
+            window.log({ c: 'report_edit', d: 'report_edit_confirm' })
+            this.SET_LOADING(false)
+            this.$router.push({ path: '/monthlyReport/index' })
+          }
+        })
+      })
+    },
+    // 删除月报
+    deleteReport(key) {
+      this.$refs['dialogDelete'].visible = false
+      if (key === '删除') {
+        this.deleteReport({
+          key,
+          callback: () => {
+            window.log({ c: 'report_edit', d: 'report_edit_delete' })
+            this.$router.push({ path: '/monthlyReport/index' })
+          }
+        })
+      } else {
+        // this.$message('删除操作已取消!')
+      }
+    },
+    tabClick(tab, event) {
+      this.bodyLoading = true
+      this.$store.dispatch('monthlyReportEdit/tabActiveChange', {
+        ...this.$route.query,
+        id: this.$route.query.reportId,
+        tabsActive: tab.name
+      })
+      setTimeout(() => {
+        this.bodyLoading = false
+      }, 700)
+    },
+    dialogOpen(key) {
+      if (key === 'dialogPublishAll') {
+        this.setMonthlyReportPreView()
+      }
+      if (key === 'dialogViewPdf') {
+        this.setMonthlyReportPrePdfView()
+      }
+      this.$refs[key].visible = true
+    },
+    sendReport(key) {
+      this.$refs['dialogSend'].visible = false
+      if (key === '取消') {
+        // this.$message('发送操作已取消!')
+        return
+      }
+      this.SET_LOADING(true)
+      this.$store.dispatch('monthlyReportEdit/sendReport', {
+        id: this.$route.query.reportId,
+        callback: () => {
+          setTimeout(() => {
+            window.log({ c: 'report_edit', d: 'report_edit_send' })
+            this.SET_LOADING(false)
+            this.$router.push({ path: '/monthlyReport/index' })
+          }, 500)
+        }
+      })
+    },
+    // 月报退回
+    returnReport(command) {
+      this.SET_LOADING(true)
+      let list = []
+      if (command === 'all') {
+        list = this.subReportInfo.map((elm) => {
+          return Number.parseInt(elm.id)
+        })
+      } else {
+        list.push(Number.parseInt(command))
+      }
+      if (command === 'only' && this.$route.query.subReportId) {
+        list = [Number.parseInt(this.$route.query.subReportId)]
+      }
+      this.$store.dispatch('monthlyReportEdit/returnReport', {
+        data: {
+          subReportIds: list
+        },
+        callback: () => {
+          window.log({ c: 'report_edit', d: 'report_edit_return' })
+          this.SET_LOADING(false)
+          this.$message.success('退回成功!')
+          this.$router.push({ path: '/monthlyReport/index' })
+        }
+      })
+    },
+    // 月报预览
+    async setMonthlyReportPreView() {
+      const res = await getMonthlyReportPreView(this.$route.query.reportId)
+      if (res.code === 200) {
+        this.monthlyReportPreView = res.data
+      }
+    },
+    // 月报Pdf预览
+    async setMonthlyReportPrePdfView() {
+      const res = await getMonthlyReportPrePdfView(this.$route.query.reportId)
+      if (res.code === 200) {
+        this.monthlyReportPrePdfView = res.data
+      }
+    },
+    // 埋点
+    monthlyReportBuriedPoint() {
+      const { pageType, type } = this.$route.query
+      if (type !== 'create') {
+        // 月报编辑
+        if (pageType === 'editAll') {
+          window.log({ c: 'report_view', d: 'report_view_edit' })
+        }
+        // 月报浏览
+        if (pageType === 'readAll') {
+          window.log({ c: 'report_view', d: 'report_view_only' })
+        }
+        // 单业务线编辑
+        if (pageType === 'edit') {
+          window.log({ c: 'report_view', d: 'report_view_only_edit' })
+        }
+        // 单业务线浏览
+        if (pageType === 'read') {
+          window.log({ c: 'report_view', d: 'report_view' })
+        }
+      }
+    }
+
+  }
+}
+</script>
+<style scoped lang='less'>
+@import '../../style';
+// setscroll
+.set_scroll {
+  &::-webkit-scrollbar {
+    width: 0px;
+    //height: 8px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #c8cbcc;
+    border-radius: 8px;
+  }
+
+  &::-webkit-scrollbar-track-piece {
+    background: #d3d3d3;
+  }
+}
+
+/deep/ .report-delete {
+  text-align: center;
+}
+
+.content-wrapper {
+  /deep/ .el-tabs__nav-wrap::after {
+    height: 1px;
+  }
+
+  .body-wrapper {
+    display: grid;
+    grid-template-columns: calc(100% - 190px) 190px;
+    //grid-template-rows: 100px 100px 100px;
+
+    .left-wrapper {
+      //flex: 1;
+      //width: 100%;
+      margin-top: -45px;
+      padding-top: 16px;
+      padding-right: 20px;
+    }
+
+    // .right-wrapper {
+    //flex: 1 1 0;
+    //display: contents;
+    // }
+  }
+}
+
+/*特殊字体*/
+/deep/ hhtem {
+  color: #333;
+  font-weight: 600;
+
+  &.red {
+    color: red;
+  }
+}
+
+/deep/ hhtsubtitle {
+  color: #333;
+  font-weight: 600;
+}
+
+/deep/ .view-report {
+  //background-color: #0EB400;
+
+  .report-delete {
+    padding: 0 20px;
+    margin: -20px 0;
+    color: #333;
+  }
+
+  .el-dialog {
+    margin-top: 5vh !important;
+    margin-bottom: 0;
+  }
+}
+</style>

+ 70 - 8
src/views/monthlyReport/index.vue

@@ -22,12 +22,18 @@
     <div v-loading="contentLoading" class="content-wrapper">
       <div class="content-reportName">
         {{ reportName }}
-        <el-button v-if="tagData.status === 20" type="text" @click="jump('report_home_Publication', '/monthlyReport/edit', { pageType: 'readAll', reportId: reportStatus.id })"> 月报发布</el-button>
-        <el-button v-if="tagData.status === 30" type="text" @click="jump('report_home_viewReport', '/monthlyReport/edit', { pageType: 'readAll', reportId: reportStatus.id })"> 查看完整报告</el-button>
-        <!--    @click="downloadMonthlyReportFn"    -->
-        <a v-if="isShowPdfPushDow() && tagData.status === 20" target="blank" :href="`${projectManagementUrl}/monthlyReport/downloadMonthlyReport?id=${reportValue}&refrash=true`" :download="`${reportName}.pdf`" style="margin-left: 10px;display: inline-block"><svg-icon icon-class="monthlyReport下载" class="icon" /></a>
-        <a v-if="isShowPdfDow()" target="blank" :href="`${projectManagementUrl}/monthlyReport/downloadMonthlyReport?id=${reportValue}`" :download="`${reportName}.pdf`" style="margin-left: 10px;display: inline-block"><svg-icon icon-class="monthlyReport下载" class="icon" /></a>
-        <el-button v-if="tagData.status === 0" type="text" @click="sendConfirm(reportData)"> 发送确认</el-button>
+        <div class="content-reportName-btn-wrapper">
+          <span v-if="tagData.status === 20" type="text" @click="jump('report_home_Publication', '/monthlyReport/edit', { pageType: 'readAll', reportId: reportStatus.id })"><i class="el-icon-document" />&nbsp;&nbsp;月报发布</span>
+          <span v-if="tagData.status === 30" type="text" @click="jump('report_home_viewReport', '/monthlyReport/edit', { pageType: 'readAll', reportId: reportStatus.id })"><i class="el-icon-document" />&nbsp;&nbsp;查看完整报告</span>
+          <!--    @click="downloadMonthlyReportFn"    -->
+          <!-- <a target="blank" :href="`${projectManagementUrl}/monthlyReport/downloadMonthlyReport?id=${reportValue}&refrash=true`" :download="`${reportName}.pdf`" style="margin-left: 10px;display: inline-block"><svg-icon icon-class="monthlyReport下载" class="icon" /></a> -->
+          <span v-show="isShowPdfPushDow() && tagData.status === 20" style="margin-left: 10px;display: inline-block" @click="downloadFile(true)"><i class="el-icon-download" />下载报告</span>
+<!--          <a v-show="isShowPdfPushDow() && tagData.status === 20" style="margin-left: 10px;display: inline-block" @click="downloadFile(true)"><svg-icon icon-class="monthlyReport下载" class="icon" /></a>-->
+          <span v-show="isShowPdfDow()" style="margin-left: 10px;display: inline-block" @click="downloadFile(true)"><i class="el-icon-download" />下载报告</span>
+<!--          <a v-show="isShowPdfDow()" target="blank" style="margin-left: 10px;display: inline-block" @click="downloadFile"><svg-icon icon-class="monthlyReport下载" class="icon" /></a>-->
+          <span v-if="tagData.status === 0" type="text" @click="sendConfirm(reportData)">发送确认</span>
+        </div>
+
       </div>
       <div v-show="tagData.status === 30" class="report-bottom">
         <span v-if="tagData.analysisList"><i class="el-icon-warning report-icon-warning" /> 本月质量月报<b>{{ tagData.analysisList }}</b>有您负责的重点问题需要分析反馈,请点击<b>{{ tagData.analysisList }}</b>的"查看更多"按钮进入填写!</span>
@@ -94,9 +100,10 @@
 import normalDialog from '@/components/dialog/normalDialog'
 import headerCom from './components/header'
 import monthlyEards from './components/monthlyEards'
-import { getAvaliableInfo, monthlyReportIndex, getReportBizInfo, createMonthlyReport } from '@/api/qualityMonthlyReport'
-import { downloadMonthlyReport } from '@/api/qualityMonthlyReport/edit'
+import { getAvaliableInfo, monthlyReportIndex, getReportBizInfo, createMonthlyReport, downloadMonthlyReport } from '@/api/qualityMonthlyReport'
+// import { downloadMonthlyReport } from '@/api/qualityMonthlyReport/edit'
 import { projectManagementUrl } from '@/apiConfig/api'
+// import { Encrypt } from '@/utils/crypto-js.js'
 
 export default {
   name: '',
@@ -223,6 +230,61 @@ export default {
       this.reportName = e.reportName
       this.reportValue = e.id
       this.reportStatus = e
+    },
+    downloadFile(refrash = false) {
+      console.log(this.projectManagementUrl)
+      // fetch(`${this.projectManagementUrl}/monthlyReport/downloadMonthlyReport?id=${this.reportValue}&refrash=true`, {
+      //   method: 'POST',
+      //   header: {
+      //      'Content-Type': 'application/json;charset=UTF-8',
+      //      'secret': Encrypt()
+      //   }
+      // })
+      downloadMonthlyReport({
+        id: this.reportValue,
+        refrash
+      }).then((res) => {
+        this.convertRes2Blob(res)
+        // console.log(blob)
+        //  const link = document.createElement('a')
+        //  link.style.display = 'none'
+        //  link.setAttribute('target', 'blank')
+        //  link.href = URL.createObjectURL(blob)
+        //  document.body.appendChild(link)
+        //  link.click()
+        //  // 释放的 URL 对象以及移除 a 标签
+        //  URL.revokeObjectURL(link.href)
+        //  document.body.removeChild(link)
+      })
+    },
+    convertRes2Blob(response) {
+      // 提取文件名
+      const fileName = `${this.reportName}.pdf`
+      console.log(fileName)
+      // 将二进制流转为blob
+      const blob = new Blob([response], { type: 'application/pdf' })
+      if (typeof window.navigator.msSaveBlob !== 'undefined') {
+        // 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
+        window.navigator.msSaveBlob(blob, decodeURI(`${this.reportName}.pdf`))
+      } else {
+        // 创建新的URL并指向File对象或者Blob对象的地址
+        const blobURL = window.URL.createObjectURL(blob)
+        // 创建a标签,用于跳转至下载链接
+        const tempLink = document.createElement('a')
+        tempLink.style.display = 'none'
+        tempLink.href = blobURL
+        tempLink.setAttribute('download', decodeURI(`${this.reportName}.pdf`))
+        // 兼容:某些浏览器不支持HTML5的download属性
+        if (typeof tempLink.download === 'undefined') {
+          tempLink.setAttribute('target', '_blank')
+        }
+        // 挂载a标签
+        document.body.appendChild(tempLink)
+        tempLink.click()
+        document.body.removeChild(tempLink)
+        // 释放blob URL地址
+        window.URL.revokeObjectURL(blobURL)
+      }
     }
   }
 }

+ 15 - 0
src/views/monthlyReport/style.less

@@ -25,6 +25,21 @@
     font-weight: 600;
     color: #333333;
     line-height: 39px;
+    position: relative;
+    .content-reportName-btn-wrapper {
+      position: absolute;
+      right: 0;
+      top: 0;
+      font-size: 14px;
+      font-weight: 400;
+      span{
+        margin-left: 10px;
+        &:hover{
+          color: #409EFF;
+          cursor: pointer;
+        }
+      }
+    }
   }
 }
 .report-create-margin {

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است