didi 4 år sedan
förälder
incheckning
5f67c1fe31

+ 1 - 0
package.json

@@ -71,6 +71,7 @@
   },
   "devDependencies": {
     "@babel/core": "7.0.0",
+    "@babel/preset-env": "^7.12.7",
     "@babel/register": "7.0.0",
     "@vue/cli-plugin-babel": "3.6.0",
     "@vue/cli-plugin-eslint": "3.6.0",

+ 5 - 2
src/api/workSchedule.js

@@ -193,7 +193,8 @@ export function getPersonalRequireSummary(data) {
 export function getPersonalRequireDisData(data) {
   return request({
     url: TeamManagement + `/workbench/personal/getRequireDisDataByStatus`,
-    method: 'get'
+    method: 'post',
+    data
   })
 }
 // 任务头部统计数据,数据里返idList(个人)
@@ -205,9 +206,11 @@ export function getPersonalTaskSummary(data) {
 }
 // 任务按状态统计数据,数据里返idList(个人)
 export function getPersonalTaskDisData(data) {
+  console.log(data)
   return request({
     url: TeamManagement + `/workbench/personal/getTaskDisDataByStatus`,
-    method: 'get'
+    method: 'post',
+    data
   })
 }
 // 缺陷头部统计数据,数据里返(个人)

+ 96 - 0
src/components/chart/statusStayChart.vue

@@ -0,0 +1,96 @@
+<template>
+  <section>
+    <div class="chart-contain">
+      <normal-echart v-if="echartsOption" :chart-id="id" :option="echartsOption" @onClick="chartClick" />
+    </div>
+  </section>
+</template>
+<script>
+import normalEchart from '@/components/chart/normalEchart'
+export default {
+  components: { normalEchart },
+  props: {
+    id: {
+      type: String,
+      default: 'status-stay-chart',
+      required: false
+    },
+    chartData: {
+      type: Object,
+      default: () => null,
+      required: false
+    }
+  },
+  data() {
+    return {
+      echartsOption: null
+    }
+  },
+  watch: {
+    chartData: {
+      handler(newV) {
+        this.setChart()
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    setChart() {
+      if (!this.chartData) return
+      const newArr = this.chartData.yaxis.filter(item => { return item.name !== '全部' })
+      const colorArr = ['#409EFF', '#F8CE5C', '#F2904F', '#5EE2BE', '#D873F5', '#7479F5']
+      let series = null
+      if (this.chartData.type === '0') {
+        const childArr = this.chartData.xaxis.map((item, index) => {
+          return {
+            value: this.chartData.yaxis[0]?.data[index] || 0,
+            idList: this.chartData.yaxis[0]?.idList[index] || []
+          }
+        })
+        series = [{
+          name: '数量', type: 'bar', barWidth: '20px', data: childArr,
+          itemStyle: { normal: { label: { show: true, formatter: '{c}', position: 'top' }}}
+        }]
+      } else {
+        series = newArr.map(item => (
+          { ...item, type: 'bar', stack: '总和', barWidth: '20px' }
+        ))
+      }
+      this.echartsOption = {
+        color: colorArr,
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { type: 'line' },
+          formatter: params => {
+            let total = 0
+            let backString = ``
+            params.map((item, index) => {
+              total = total + item.value
+              backString = backString + `<span style="color: ${colorArr[index] || ''}">${item.seriesName}</span>:${item.value}个</br>`
+            })
+            return backString + `<span style="color: #F04864">总和</span>:${total}个`
+          }
+        },
+        legend: { data: newArr.map(item => { return item.name }), left: 0, top: 0 },
+        grid: { left: '0', right: '0', top: '8%', bottom: '0', containLabel: true },
+        xAxis: { type: 'category', data: this.chartData.xaxis, axisTick: { alignWithLabel: true }, axisLabel: { interval: 0, rotate: 40 }},
+        yAxis: { type: 'value', axisLine: { show: false }, splitLine: { lineStyle: { type: 'dashed' }}, axisLabel: { formatter: '{value}个' }},
+        series
+      }
+    },
+    chartClick(param) {
+      this.$emit('onClick', param)
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.chart-contain {
+  position: relative;
+  height: 320px;
+  width: 84%;
+  margin: 20px auto;
+}
+
+</style>

+ 0 - 48
src/layout/components/Sidebar/index.vue

@@ -21,13 +21,6 @@
       <el-divider style="color: #EEF0F5; margin: 0px;" />
       <hamburger :is-active="sidebar.opened" class="hamburger-containers" @toggleClick="toggleSideBar" />
     </el-footer>
-    <div v-if="!isKnownBusness && bizId !== -1" class="business-guide">
-      <div class="guide-dialog">
-        <div class="guide-close"><i class="el-icon-error" @click="knownBusness()" /></div>
-        <div class="guide-title">业务线切换在这里哦!</div>
-        <div class="guide-confirm" @click="knownBusness()">好的,我知道了</div>
-      </div>
-    </div>
   </el-container>
 </template>
 
@@ -45,7 +38,6 @@ export default {
   mixins: [websocket],
   data() {
     return {
-      isKnownBusness: localStorage.getItem('known-business') || false,
       activeRoutes: []
     }
   },
@@ -94,10 +86,6 @@ export default {
     Logout() {
       location.href = logoutUrl
     },
-    knownBusness() {
-      localStorage.setItem('known-business', true)
-      this.isKnownBusness = true
-    },
     websocketonmessage(e) { // websocket数据接收
       const { hasReminding } = JSON.parse(e.data)
       if (hasReminding) {
@@ -138,40 +126,4 @@ export default {
 .el-submenu__title i {
   color: #333B4A;
 }
-.business-guide {
-  position: fixed;
-  height: 100vh;
-  width: 100vw;
-  z-index: 99;
-  background-color: rgba(0, 0, 0, 0.25);
-  font-size: 18px;
-  color: #FFFFFF;
-  .guide-dialog {
-    cursor: pointer;
-    width: 250px;
-    height: 215px;
-    padding-top: 110px;
-    position: relative;
-    left: 30px;
-    top: 15px;
-    background-image: url('../../../assets/bisness_guide.png');
-    background-size: contain;
-  }
-  .guide-close {
-    display: flex;
-    justify-content: flex-end;
-    padding: 0 10px;
-  }
-  .guide-title {
-    text-align: center;
-  }
-  .guide-confirm {
-    color: #409EFF;
-    background-color: #FFFFFF;
-    width: 140px;
-    margin: 10px auto;
-    text-align: center;
-    border-radius: 4px;
-  }
-}
 </style>

+ 9 - 0
src/utils/global.js

@@ -42,3 +42,12 @@ export function getAllTime(start, end, noHoliday = true) {
   }
   return NewArr
 }
+
+export function formatHMS(data) {
+  let time = '--'
+  var hours = parseInt((data % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
+  var minutes = parseInt((data % (1000 * 60 * 60)) / (1000 * 60))
+  var seconds = parseInt((data % (1000 * 60)) / 1000)
+  time = (hours < 10 ? ('0' + hours) : hours) + ':' + (minutes < 10 ? ('0' + minutes) : minutes) + ':' + (seconds < 10 ? ('0' + seconds) : seconds)
+  return time
+}

+ 55 - 1
src/views/newLayout/layout.vue

@@ -4,6 +4,13 @@
     <Head />
     <Aside />
     <Main />
+    <div v-if="!isKnownBusness && bizId !== -1" class="business-guide">
+      <div class="guide-dialog">
+        <div class="guide-close"><i class="el-icon-error" @click="knownBusness()" /></div>
+        <div class="guide-title">业务线切换在这里哦!</div>
+        <div class="guide-confirm" @click="knownBusness()">好的,我知道了</div>
+      </div>
+    </div>
   </div>
 </template>
 <script>
@@ -18,8 +25,19 @@ export default {
     Main,
     Head
   },
+  data() {
+    return {
+      isKnownBusness: localStorage.getItem('known-business') || false
+    }
+  },
   computed: {
-    ...mapGetters(['noNetwork'])
+    ...mapGetters(['noNetwork', 'bizId'])
+  },
+  methods: {
+    knownBusness() {
+      localStorage.setItem('known-business', true)
+      this.isKnownBusness = true
+    }
   }
 }
 </script>
@@ -39,6 +57,42 @@ export default {
   animation: loading linear 5s infinite;
   background: linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c);
 }
+.business-guide {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  z-index: 99;
+  background-color: rgba(0, 0, 0, 0.25);
+  font-size: 18px;
+  color: #FFFFFF;
+  .guide-dialog {
+    cursor: pointer;
+    width: 250px;
+    height: 215px;
+    padding-top: 110px;
+    position: relative;
+    left: 0;
+    top: 15px;
+    background-image: url('../../assets/bisness_guide.png');
+    background-size: contain;
+  }
+  .guide-close {
+    display: flex;
+    justify-content: flex-end;
+    padding: 0 10px;
+  }
+  .guide-title {
+    text-align: center;
+  }
+  .guide-confirm {
+    color: #409EFF;
+    background-color: #FFFFFF;
+    width: 140px;
+    margin: 10px auto;
+    text-align: center;
+    border-radius: 4px;
+  }
+}
 @keyframes loading{
   from{
     width: 0

+ 1 - 1
src/views/projectManage/bugList/file/createdBug.vue

@@ -646,7 +646,7 @@ export default {
       const isLt200M = file.size / 1024 / 1024 < 20
       if (!isLt200M) {
         this.$message({
-          message: '上传文件大小不能超过 20MB!',
+          message: '上传文件大小不能超过 10MB!',
           type: 'warning'
         })
         return false

+ 9 - 0
src/views/projectManage/schedule.vue

@@ -4,6 +4,7 @@
     <div v-if="isSchedule === 0" align="center">是否需要锁定当前{{ name === '需求'? '需求': "任务" }}的排期?</div>
     <div v-if="isSchedule === 1" align="center">
       <el-form ref="numberValidateForm" :model="numberValidateForm" label-width="100px" class="demo-ruleForm">
+        <p class="tip"><i class="el-icon-warning icon" />解锁后,排期将在24小时后自动锁定,请及时完成排期调整</p>
         <el-form-item label="解锁原因" :rules="[{ required: true, message: '解锁原因不能为空'}]">
           <el-select v-model="numberValidateForm.remarkType" style="width:100%;" placeholder="请选择">
             <el-option v-for="(item,index) in scheduleOperateReason" :key="index" :label="item.msg" :value="item.code" />
@@ -134,5 +135,13 @@ export default {
   top: 23px;
   left: 20px;
 }
+.tip {
+  color: #F56C6C;
+  text-align: left;
+  padding: 0 20px;
+  .icon {
+    margin-right:5px;
+  }
+}
 }
 </style>

+ 32 - 0
src/views/projectManage/taskList/taskViewDetail.vue

@@ -190,6 +190,9 @@
                     {{ isScheduleLocked === 1 ? '已锁定' : '未锁定' }}
                   </span>
                 </el-tooltip>
+                <span v-if="isScheduleLocked === 0" class="tip">
+                  <i class="el-icon-timer icon" />剩余{{ autoLockScheduleCountdown }}
+                </span>
               </div>
             </div>
           </div>
@@ -421,6 +424,7 @@ import { dailyReportCheckStatus, reportreleaseCheckStatus, reportdelivertestChec
 import synchronizeDialog from './dialog/synchronizeDialog' // 同步弹框
 import workflowAndStatus from '@/views/projectManage/components/workflowAndStatus.vue'
 import '@/styles/PublicStyle/index.scss'
+import { formatHMS } from '@/utils/global'
 export default {
   components: {
     searchPeople,
@@ -456,6 +460,8 @@ export default {
   },
   data() {
     return {
+      autoLockScheduleCountdown: '--', // 解锁剩余时间
+      timer: null, // 定时器
       tabPosition: 'first',
       textarea2: '',
       HoldTask: '',
@@ -530,6 +536,7 @@ export default {
     this.$store.state.data.status = true
   },
   destroyed() {
+    clearInterval(this.timer)
     this.$store.state.data.status = false
   },
   methods: {
@@ -550,6 +557,18 @@ export default {
       this.SchedulingContent = res.data
       const res1 = await listByTask(this.taskId)
       this.isScheduleLocked = res1.data.isScheduleLocked
+      if (res1.data.isScheduleLocked !== 1 && res1.data.autoLockScheduleCountdown > 0) {
+        let totolTime = res1.data.autoLockScheduleCountdown || 6000
+        clearInterval(this.timer)
+        this.timer = setInterval(() => {
+          totolTime = totolTime - 1000
+          this.autoLockScheduleCountdown = formatHMS(totolTime)
+          if (totolTime < 1000) {
+            this.isScheduleLocked = 1
+            clearInterval(this.timer)
+          }
+        }, 1000)
+      }
       this.tips = res1.data.tips
       this.isParentRequireScheduleLocked = res1.data.isParentRequireScheduleLocked
       this.$refs.taskSchedule.listByTask(this.taskId)
@@ -1066,6 +1085,18 @@ export default {
 </style>
 
 <style lang="scss">
+.bg-project {
+  .tip {
+    color: #F56C6C;
+    text-align: left;
+    padding: 0 14px;
+    font-size: 12px;
+    .icon {
+      margin-right: 2px;
+    }
+  }
+}
+
 .synchronize {
   .el-popover__title {
     color: #333333;
@@ -1097,4 +1128,5 @@ export default {
   margin: 12px 10px 0 0;
   width: 300px;
 }
+
 </style>

+ 1 - 1
src/views/workbench/components/createDialog.vue

@@ -82,7 +82,7 @@ export default {
       const res = await settingGetMyAndOtherBizList()
       if (res.code === 200) {
         this.$nextTick(() => {
-          const biz = res.data[0]
+          const biz = res.data.filter(item => item.length > 0)
           this.bizId = biz[0].code
         })
         this.bizList = [{

+ 35 - 14
src/views/workbench/components/statisticsSection.vue

@@ -24,10 +24,15 @@
           </div>
         </div>
         <div v-if="title !=='缺陷'" class="statistics-chart">
-          <h2>未上线{{ title }}状态分布</h2>
+          <!-- <h2>未上线{{ title }}状态分布</h2> -->
+          <el-radio-group v-model="itemType" @change="onChangeTagRadio">
+            <el-radio-button label="0">未上线{{ title }}状态分布</el-radio-button>
+            <el-radio-button label="1">本周{{ title }}状态流入图</el-radio-button>
+          </el-radio-group>
           <h3 @click="getAll()">总数:<span>{{ totalTask }}</span></h3>
           <div class="chart-contain">
-            <normal-echart v-if="echartsOption" :chart-id="type+title" :option="echartsOption" @onClick="chartChange" />
+            <status-stay-chart :chart-data="echartsOption" @onClick="chartChange" />
+            <!-- <normal-echart v-if="echartsOption" :chart-id="type+title" :option="echartsOption" @onClick="chartChange" /> -->
           </div>
         </div>
         <div v-if="title ==='缺陷'" class="statistics-chart">
@@ -57,9 +62,13 @@
 
 <script>
 import normalEchart from '@/components/chart/normalEchart'
+import statusStayChart from '@/components/chart/statusStayChart'
 export default {
   name: 'StatisticsSectionVue',
-  components: { normalEchart },
+  components: {
+    normalEchart,
+    statusStayChart
+  },
   props: {
     searchForm: { // 搜索项的信息
       type: Object,
@@ -95,6 +104,7 @@ export default {
       echartsOption2: null,
       totalTask: 0, // 所有总数
       totalIdList: 0, // 所有总数的idList
+      itemType: '0', // 0: 未上线的需求分布  1: 本周状态流入图
       tips: {
         '需求': [
           '交付日期为今天,且状态仍未变更为“已上线”的需求数量(不包含当前状态为hold的需求)。',
@@ -143,10 +153,14 @@ export default {
           this.getChart(requestChart, '3')
           this.getChart(requestChart, '5')
         } else {
-          this.getChart(requestChart)
+          this.getChart(requestChart, this.itemType)
         }
       }
     },
+    onChangeTagRadio(e) {
+      const { requestChart } = this.requestObj
+      this.getChart(requestChart, this.itemType)
+    },
     async getData(requestUrl) { // 获取顶部数据
       const res = await requestUrl({ teamSearchInfo: this.searchForm })
       if (res.code === 200) {
@@ -165,18 +179,16 @@ export default {
       }
     },
     async getChart(requestUrl, type) { // 获取图表数据
-      if (type) {
-        const res = await requestUrl({ teamSearchInfo: this.searchForm, type: type })
-        if (type === '3') {
-          this.echartsOption = this.setChart(res.data)
-        } else if (type === '5') {
-          this.echartsOption2 = this.setChart(res.data)
-        }
+      const res = await requestUrl({ teamSearchInfo: this.searchForm, type: type })
+      if (type === '3') {
+        this.echartsOption = this.setChart(res.data)
+      } else if (type === '5') {
+        this.echartsOption2 = this.setChart(res.data)
       } else {
-        const res = await requestUrl({ teamSearchInfo: this.searchForm })
+        const res = await requestUrl({ teamSearchInfo: this.searchForm, type })
         this.totalTask = res.data.total
         this.totalIdList = res.data.idList
-        this.echartsOption = this.setChart(res.data)
+        this.echartsOption = { ...res.data, type: this.itemType }
       }
     },
     setChart(chartData) { // 设置图表options
@@ -204,8 +216,17 @@ export default {
       this.changeData(this.totalIdList, `未上线的`)
     },
     chartChange(params) { // 点击图表产生触发列表更改
+      let idList = params.data.idList || []
+      // 本周需求状态流入图需要特殊处理。循环出对应下标的idlist
+      if (this.itemType === '1') {
+        // console.log(this.echartsOption.xaxis)
+        const dataIndex = params.dataIndex
+        this.echartsOption.yaxis.forEach(t => {
+          idList = [...idList, ...t.idList[dataIndex]]
+        })
+      }
       this.clickItem = -1
-      this.changeData(params.data.idList, params.name)
+      this.changeData(idList, params.name)
     },
     changeData(idList, name) { // 点击顶部数据触发列表更改
       this.$emit('change', this.title, idList, name)