requireStatistics.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. <template>
  2. <div @click="openDrawer = false, drawer = false">
  3. <el-container class="defect-container">
  4. <el-header class="defect-main" style="height: auto;">
  5. <el-form :model="chartForm" class="demo-form-inline" :inline="true">
  6. <el-form-item label="时间:">
  7. <div class="date-select">
  8. <span :class="[dateType==='week'?'date-active':'']" class="date-item" @click.stop="dateType='week';setDate('week')">本周</span>
  9. <span :class="[dateType==='month'?'date-active':'']" class="date-item" @click.stop="dateType='month';setDate('month')">本月</span>
  10. <span :class="[dateType==='year'?'date-active':'']" class="date-item" @click.stop="dateType='year';setDate('year')">本年</span>
  11. </div>
  12. <el-date-picker
  13. v-model="stratAndEnd"
  14. type="daterange"
  15. align="right"
  16. unlink-panels
  17. range-separator="至"
  18. start-placeholder="开始日期"
  19. end-placeholder="结束日期"
  20. size="small"
  21. value-format="yyyy.MM.dd"
  22. :default-time="['00:00:00','23:59:59']"
  23. @change="dateType = ''"
  24. />
  25. </el-form-item>
  26. </el-form>
  27. <el-form :model="chartForm" class="demo-form-inline" :inline="true">
  28. <el-form-item label="团队:">
  29. <el-select
  30. v-model="chartForm.team"
  31. placeholder="请选择"
  32. size="small"
  33. clearable
  34. filterable
  35. multiple
  36. >
  37. <el-option-group
  38. v-for="group in teamOptions"
  39. :key="group.label"
  40. :label="group.label"
  41. >
  42. <el-option
  43. v-for="item in group.options"
  44. :key="item.teamId"
  45. :label="item.teamName"
  46. :value="item.teamId"
  47. />
  48. </el-option-group>
  49. </el-select>
  50. </el-form-item>
  51. <el-form-item label="需求方向:">
  52. <el-cascader
  53. v-model="chartForm.rqmtOrntIds"
  54. size="small"
  55. clearable
  56. collapse-tags
  57. :props="{
  58. value: 'id',
  59. label: 'rqmtOrntName',
  60. children: 'childRqmtOrnts',
  61. multiple: true
  62. }"
  63. :options="moduleList"
  64. placeholder="请选择"
  65. />
  66. </el-form-item>
  67. <el-form-item>
  68. <el-button type="primary" size="mini" @click="onSubmit">查询</el-button>
  69. </el-form-item>
  70. </el-form>
  71. <div class="data-total">
  72. <div v-for="(item,index) in Summary" :key="'Summary'+index" class="data-item" :class="['item'+ (index + 1)]">
  73. <article>
  74. <div class="item-top">
  75. <div class="item-circle">
  76. <img v-show="index === 0" src="../../../src/assets/defect_images/add.png">
  77. <img v-show="index === 1" src="../../../src/assets/defect_images/repair.png">
  78. <img v-show="index === 2" src="../../../src/assets/defect_images/reopen.png">
  79. <img v-show="index === 3" src="../../../src/assets/defect_images/reopen.png">
  80. </div>
  81. <span>{{ item.label }}</span>
  82. <el-tooltip v-if="index === 0" class="item" effect="dark" content="统计区间内,新建的需求数量" placement="top-start">
  83. <i class="el-icon-info" />
  84. </el-tooltip>
  85. <el-tooltip v-if="index === 1" class="item" effect="dark" content="需求最近一次更新状态为“PRD评审通过”在统计区间内,并且当前状态是“PRD评审通过”及之后状态的需求数量" placement="top-start">
  86. <i class="el-icon-info" />
  87. </el-tooltip>
  88. <el-tooltip v-if="index === 2" class="item" effect="dark" content="需求最近一次更新状态为“已上线”在统计区间内,并且当前状态是“已上线”及之后状态的需求数量" placement="top-start">
  89. <i class="el-icon-info" />
  90. </el-tooltip>
  91. <el-tooltip v-if="index === 3" class="item" effect="dark" content="需求最近一次更新状态为“Hold”在统计区间内,并且当前状态为“Hold”的需求数量" placement="top-start">
  92. <i class="el-icon-info" />
  93. </el-tooltip>
  94. </div>
  95. <div class="item-title" @click.stop="getRequiredNum(item)">{{ item.total }}</div>
  96. <div class="item-line" />
  97. <div v-show="Number(item.relativeRatio)>=0" class="item-up">环比:<i class="el-icon-caret-top" />{{ item.relativeRatio }}%</div>
  98. <div v-show="Number(item.relativeRatio)<0" class="item-down">环比:<i class="el-icon-caret-bottom" />{{ item.relativeRatio.substring(1,item.relativeRatio.length) }}%</div>
  99. <div v-show="item.relativeRatio === '--'" class="item-down">环比:{{ item.relativeRatio }}%</div>
  100. </article>
  101. </div>
  102. </div>
  103. <div class="chart-item bottom-padding">
  104. <h3>状态累积流量图</h3>
  105. <status-chart :chart-data="cumulativeData" @code="statusAccumulate" @clone="openDrawer = false" />
  106. </div>
  107. </el-header>
  108. <el-main class="charts-main">
  109. <el-tabs v-model="activeTab" class="tab-change" @tab-click="onSubmit">
  110. <el-tab-pane v-for="item in countTitle" :key="'countTitle'+item.code" :name="item.code+''">
  111. <span slot="label" class="tab-item">{{ item.msg }}</span>
  112. </el-tab-pane>
  113. </el-tabs>
  114. <div class="chart-item">
  115. <h3 v-show="activeTab === '1'">新增趋势图</h3>
  116. <h3 v-show="activeTab === '2'">上线趋势图</h3>
  117. <h3 v-show="activeTab === '3'">PRD评审趋势图</h3>
  118. <h3 v-show="activeTab === '5'">技术准入趋势图</h3>
  119. <tendency-chart :chart-data="tendencyData" @code="getTrendChart" @clone="openDrawer = false" />
  120. </div>
  121. <div class="chart-item">
  122. <h3>周期统计<span>(根据排期计算)</span></h3>
  123. <!-- <div class="chart-item-tip">
  124. <i class="el-icon-warning-outline" />
  125. <span>仅统计状态已变更“已排期”且排期不为空的需求</span>
  126. </div> -->
  127. <cycle-statistic :chart-data="cycleData" @clickCount="getClickItem" />
  128. </div>
  129. <div class="chart-item">
  130. <h3>周期分布图<span>(根据排期计算)</span></h3>
  131. <!-- <div class="chart-item-tip">
  132. <i class="el-icon-warning-outline" />
  133. <span>仅统计状态已变更“已排期”且排期不为空的需求;横坐标表示需求交付日期,纵坐标代表研发交付周期(研发、联调、上线类型排期的总周期)</span>
  134. </div> -->
  135. <development-cycle
  136. :chart-data="developmentCycleData"
  137. type="require"
  138. :graph-type.sync="graphType"
  139. :graph-type-list="graphTypeList"
  140. @change="getDevelopmentCycle()"
  141. />
  142. </div>
  143. <div class="chart-item">
  144. <h3>人力统计<span>(根据排期计算)</span></h3>
  145. <cycle-statistic :chart-data="peopleData" :show-tips="false" @clickCount="getPeopleList" />
  146. </div>
  147. <div class="chart-item">
  148. <h3>人力分布图<span>(根据排期计算)</span></h3>
  149. <development-cycle
  150. id="101"
  151. :chart-data="developmentPeopleData"
  152. type="require"
  153. :graph-type.sync="peopleType"
  154. :graph-type-list="peopleTypeList"
  155. @change="getDevelopeopleData()"
  156. />
  157. </div>
  158. <div class="chart-item">
  159. <h3>需求分布图</h3>
  160. <distribution-chart
  161. :chart-data="distributeData"
  162. :status-list="distributeStatusList"
  163. :status.sync="distributeStatus"
  164. :active-tab="activeTab"
  165. @change="getDistributeData()"
  166. @code="clickCodeData"
  167. @state="getStatusType"
  168. @clone="openDrawer = false"
  169. />
  170. </div>
  171. <div class="chart-item">
  172. <h3>状态停留分布图</h3>
  173. <status-stay-chart :chart-data="statusStayData" @code="statusStayChart" @clone="openDrawer = false" />
  174. </div>
  175. <div class="chart-item">
  176. <h3>需求方向分布图</h3>
  177. <belong-chart :chart-data="orntDistributeData" @code="statusOrntDistributeData" @clone="openDrawer = false" />
  178. </div>
  179. <div class="chart-item">
  180. <h3>排期发生变更的需求(<span class="strong-font">{{ changeTotal }}</span>个)</h3>
  181. <change-require-chart :chart-data="changeRequireData" type-name="需求" />
  182. </div>
  183. <div class="chart-item" @click.stop>
  184. <h3>缺陷统计</h3>
  185. <bug-list :chart-data="bugListData" @requireBug="queryData" />
  186. </div>
  187. </el-main>
  188. <div @click.stop>
  189. <require-drawer v-if="drawer" :drawer="drawer" :data="requireList" @clone="clone" />
  190. <drawer-all v-if="openDrawer" :drawer="openDrawer" :data="requireList" :status="reqStatus" @clone="clone" />
  191. </div>
  192. </el-container>
  193. </div>
  194. </template>
  195. <script>
  196. import moment from 'moment'
  197. moment.locale('zh-cn')
  198. import { mapGetters } from 'vuex'
  199. import { settingQueryBizRqmtOrntList } from '@/api/requirement'
  200. import { teamQueryTeamInfoList } from '@/api/configure'
  201. import {
  202. getRequireCountTitleEnum,
  203. getSummary,
  204. getCumulativeFlowDiagram,
  205. getRequireCountTrend,
  206. getRequirePeriodicData,
  207. getRequireRdDeliveryPeriodicData,
  208. getDistributeData,
  209. getStatusStayData,
  210. getOrntDistributeData,
  211. getReqUnlockData,
  212. getBugStatisticData,
  213. getManpowerStatistics,
  214. getManpowerDistributedData
  215. } from '@/api/statisticsApi/requireStatistics'
  216. import requireDrawer from './components/requireDrawer'
  217. import drawerAll from './components/drawerAll'
  218. import statusChart from './components/statusChart'
  219. import tendencyChart from './components/tendencyChart'
  220. import cycleStatistic from './components/cycleStatistic'
  221. import developmentCycle from './components/developmentCycle'
  222. import distributionChart from './components/distributionChart'
  223. import statusStayChart from './components/statusStayChart'
  224. import belongChart from './components/belongChart'
  225. import changeRequireChart from './components/changeRequireChart'
  226. import bugList from './components/bugList'
  227. export default {
  228. components: {
  229. statusChart,
  230. tendencyChart,
  231. cycleStatistic,
  232. developmentCycle,
  233. distributionChart,
  234. statusStayChart,
  235. belongChart,
  236. changeRequireChart,
  237. bugList,
  238. requireDrawer,
  239. drawerAll
  240. },
  241. data() {
  242. return {
  243. drawer: false,
  244. openDrawer: false,
  245. requireList: {},
  246. reqStatus: '',
  247. bugCountTimeType: 1, // 获取趋缺陷势图数据接口入参:1本周 2本月 3本年
  248. timeTypeList: [ // 日期选择
  249. { code: 1, label: '周' },
  250. { code: 2, label: '月' },
  251. { code: 3, label: '年' }
  252. ],
  253. countTitle: [], // 趋势图的动态title
  254. teamOptions: [], // 团队列表
  255. chartForm: {}, // 筛选表单
  256. stratAndEnd: [], // 开始结束日期
  257. dateType: 'week', // 时间选择类型
  258. moduleList: [], // 需求方向列表
  259. Summary: [], // 顶部数据
  260. activeTab: '1', // tab标签
  261. cumulativeData: null, // 需求状态累计流数据
  262. tendencyData: null, // 趋势图数据
  263. cycleData: [], // 周期统计数据
  264. peopleData: [], // 人力统计数据
  265. graphType: 1, // 周期分布图选项
  266. graphTypeList: [ // 周期分布图选项列表
  267. { code: 1, label: '产品技术侧总周期' },
  268. { code: 2, label: '产品侧总周期' },
  269. { code: 3, label: '技术侧总周期' },
  270. { code: 4, label: '研发交付周期' },
  271. { code: 5, label: '研发周期' },
  272. { code: 6, label: '测试周期 ' }
  273. ],
  274. peopleType: -1, // 周期分布图选项
  275. peopleTypeList: [ // 人力分布图选项列表
  276. { code: -1, label: '排期使用人力' },
  277. { code: 0, label: '开发类型排期使用人力' },
  278. { code: 1, label: '用例类型排期使用人力' },
  279. { code: 2, label: '联调类型排期使用人力' },
  280. { code: 3, label: '提测类型排期使用人力' },
  281. { code: 4, label: '测试类型排期使用人力 ' },
  282. { code: 5, label: '准出类型排期使用人力 ' },
  283. { code: 6, label: '上线类型排期使用人力 ' },
  284. { code: 7, label: '其他 ' }
  285. ],
  286. developmentCycleData: [], // 研发交付周期分布数据
  287. developmentPeopleData: [], // 人力分布图
  288. distributeStatus: 1, // 需求分布图需求状态
  289. distributeStatusList: [
  290. { code: 1, label: '需求状态' },
  291. { code: 2, label: '需求等级' },
  292. { code: 3, label: '需求类型' },
  293. { code: 4, label: 'pm' },
  294. { code: 5, label: '跟版客户端' }
  295. ], // 需求分布图需求状态列表
  296. orntDistributeData: null, // 所属需求方向数据
  297. distributeData: null, // 需求分布图数据
  298. statusStayData: null, // 状态停留图数据
  299. moduleDistribute: null, // 模块分布图数据
  300. changeRequireData: null, // 排期变更需求数据
  301. changeTotal: 0, // 变更总数
  302. bugListData: {} // 缺陷统计数据
  303. }
  304. },
  305. computed: {
  306. ...mapGetters(['bizId']),
  307. globalParams: { // 通用接口参数
  308. get() {
  309. const rqmtOrntIds = this.chartForm.rqmtOrntIds
  310. const team = this.chartForm.team
  311. const params = {
  312. startTime: this.stratAndEnd[0] || null,
  313. endTime: this.stratAndEnd[1] || null,
  314. bizId: this.bizId,
  315. teamIds: team && team.length > 0 ? team : null,
  316. rqmtOrntIds: rqmtOrntIds && rqmtOrntIds.length > 0 ? rqmtOrntIds : null
  317. }
  318. return params
  319. }
  320. },
  321. timeType: {
  322. get() {
  323. let timeType = 0
  324. switch (this.dateType) {
  325. case 'week':
  326. timeType = 1
  327. break
  328. case 'month':
  329. timeType = 2
  330. break
  331. case 'year':
  332. timeType = 3
  333. break
  334. default:
  335. timeType = 0
  336. break
  337. }
  338. return timeType
  339. }
  340. }
  341. },
  342. watch: {
  343. bizId: {
  344. handler(newV) {
  345. if (newV === -1) return
  346. this.init()
  347. },
  348. immediate: true
  349. }
  350. },
  351. created() {
  352. this.$store.state.data.status = true
  353. },
  354. methods: {
  355. async init() {
  356. await this.getRequireCountTitleEnum()
  357. this.setDate(this.dateType)
  358. this.getTeamList()
  359. this.getRequireDirection()
  360. },
  361. onSubmit() {
  362. if (this.activeTab === '2' && this.distributeStatus === 1) {
  363. this.distributeStatus = 2
  364. }
  365. this.getSummary()
  366. this.getCumulativeFlowDiagram()
  367. this.getRequireCountTrend()
  368. this.getCycleData()
  369. this.getDevelopmentCycle()
  370. this.getPeopleData()
  371. this.getDevelopeopleData()
  372. this.getOrntDistributeData()
  373. this.getDistributeData()
  374. this.getStatusStayData()
  375. this.getReqUnlockData()
  376. this.getBugStatisticData()
  377. },
  378. setDate(type) { // 日期筛选
  379. this.drawer = false
  380. let startDate = null
  381. let endDate = null
  382. switch (type) {
  383. case 'week':
  384. startDate = moment().startOf('week').format('YYYY.MM.DD')
  385. endDate = moment().endOf('week').format('YYYY.MM.DD')
  386. this.bugCountTimeType = this.timeTypeList[0].code
  387. break
  388. case 'month':
  389. startDate = moment().startOf('month').format('YYYY.MM.DD')
  390. endDate = moment().endOf('month').format('YYYY.MM.DD')
  391. this.bugCountTimeType = this.timeTypeList[1].code
  392. break
  393. case 'year':
  394. startDate = moment().startOf('year').format('YYYY.MM.DD')
  395. endDate = moment().endOf('year').format('YYYY.MM.DD')
  396. this.bugCountTimeType = this.timeTypeList[2].code
  397. break
  398. }
  399. this.stratAndEnd = [startDate, endDate]
  400. this.onSubmit()
  401. },
  402. async getRequireCountTitleEnum() { // 趋势图的动态title枚举
  403. const res = await getRequireCountTitleEnum({ bizId: this.bizId })
  404. if (res.code === 200) {
  405. this.countTitle = res.data || []
  406. this.activeTab = `${res.data[0].code}`
  407. }
  408. },
  409. async getRequireDirection() { // 需求方向列表
  410. const res = await settingQueryBizRqmtOrntList(this.bizId)
  411. if (res.code === 200) {
  412. this.moduleList = this.getRequireData(res.data)
  413. }
  414. },
  415. getRequireData(data) {
  416. for (let i = 0; i < data.length; i++) {
  417. data[i].childRqmtOrnts.length < 1 ? delete data[i].childRqmtOrnts : this.getRequireData(data[i].childRqmtOrnts)
  418. }
  419. return data
  420. },
  421. async getTeamList() { // 获取我的团队和所有团队
  422. const myRes = await teamQueryTeamInfoList({ type: 0 })// 我的团队
  423. const allRes = await teamQueryTeamInfoList({ type: 1 })// 所有团队
  424. this.teamOptions = [
  425. { label: '我的团队', options: [...myRes.data.list] },
  426. { label: '全部团队', options: [...allRes.data.list] }
  427. ]
  428. },
  429. async getSummary() { // 获取顶部数据
  430. const res = await getSummary(this.globalParams)
  431. if (res.code === 200) this.Summary = res.data || []
  432. },
  433. async getRequireCountTrend() { // 趋势图日期变动
  434. const params = {
  435. ...this.globalParams,
  436. type: Number(this.activeTab),
  437. timeType: this.timeType
  438. }
  439. const res = await getRequireCountTrend(params)
  440. if (res.code === 200) this.tendencyData = res.data
  441. },
  442. async getCumulativeFlowDiagram() { // 需求状态累计流图
  443. const params = {
  444. ...this.globalParams,
  445. timeType: this.timeType
  446. }
  447. const res = await getCumulativeFlowDiagram(params)
  448. if (res.code === 200) this.cumulativeData = res.data
  449. },
  450. async getPeopleData() { // 人力统计数据
  451. const params = {
  452. ...this.globalParams,
  453. timeType: this.timeType,
  454. type: Number(this.activeTab)
  455. }
  456. const res = await getManpowerStatistics(params)
  457. if (res.code === 200) this.peopleData = res.data
  458. },
  459. async getDevelopeopleData() { // 需求人力分布图
  460. const params = {
  461. ...this.globalParams,
  462. type: Number(this.activeTab),
  463. graphType: this.peopleType
  464. }
  465. const res = await getManpowerDistributedData(params)
  466. if (res.code === 200) {
  467. res.data.length > 0
  468. ? this.developmentPeopleData = res.data
  469. : this.developmentPeopleData = [moment().format('YYYY-MM-DD'), '0']
  470. }
  471. },
  472. async getCycleData() { // 周期统计数据
  473. const params = {
  474. ...this.globalParams,
  475. type: Number(this.activeTab)
  476. }
  477. const res = await getRequirePeriodicData(params)
  478. if (res.code === 200) this.cycleData = res.data
  479. },
  480. async getDevelopmentCycle() { // 获取研发交付周期分布数据
  481. const params = {
  482. ...this.globalParams,
  483. type: Number(this.activeTab),
  484. graphType: this.graphType
  485. }
  486. const res = await getRequireRdDeliveryPeriodicData(params)
  487. if (res.code === 200) {
  488. res.data.length > 0
  489. ? this.developmentCycleData = res.data
  490. : this.developmentCycleData = [moment().format('YYYY-MM-DD'), '0']
  491. }
  492. },
  493. getStatusType(e) {
  494. this.reqStatus = e
  495. },
  496. async getDistributeData() { // 获取需求分布图
  497. this.openDrawer = false
  498. const params = {
  499. ...this.globalParams,
  500. type: Number(this.activeTab),
  501. distributeType: this.distributeStatus
  502. }
  503. const res = await getDistributeData(params)
  504. if (res.code === 200) this.distributeData = res.data
  505. },
  506. async getStatusStayData() { // 状态停留时长分布
  507. const params = {
  508. ...this.globalParams,
  509. type: Number(this.activeTab)
  510. }
  511. const res = await getStatusStayData(params)
  512. if (res.code === 200) this.statusStayData = res.data
  513. },
  514. async getOrntDistributeData() { // 获取需求方向分布
  515. const params = {
  516. ...this.globalParams,
  517. type: Number(this.activeTab)
  518. }
  519. const res = await getOrntDistributeData(params)
  520. if (res.code === 200) this.orntDistributeData = this.handlerData(res.data)
  521. },
  522. handlerData(arr) { // 处理需求方向分布图数据
  523. const bfs = (arr) => {
  524. for (const item of arr) {
  525. if (item.children && item.children.length > 0) {
  526. bfs(item.children)
  527. } else {
  528. delete item.children
  529. }
  530. }
  531. }
  532. bfs(arr)
  533. return { children: arr, name: '需求方向分布' }
  534. },
  535. async getReqUnlockData() { // 排期发生变更的需求
  536. const params = {
  537. ...this.globalParams,
  538. type: Number(this.activeTab),
  539. distributeType: this.distributeStatus
  540. }
  541. const res = await getReqUnlockData(params)
  542. if (res.code === 200) {
  543. this.changeRequireData = res.data || []
  544. this.changeTotal = this.changeRequireData.length
  545. }
  546. },
  547. async getBugStatisticData() { // 缺陷统计
  548. const params = {
  549. ...this.globalParams,
  550. type: Number(this.activeTab)
  551. }
  552. const res = await getBugStatisticData(params)
  553. if (res.code === 200) this.bugListData = res.data
  554. },
  555. mapData(data) {
  556. const arr = []
  557. data.map(item => {
  558. arr.push(item.label.substr(2))
  559. })
  560. return arr
  561. },
  562. getRequiredNum(value) {
  563. this.drawer = true
  564. value.typeStr = '需求'
  565. this.requireList = value
  566. },
  567. getPeopleList(value, data) {
  568. console.log(value, data, '点击')
  569. value.title = '人力统计数据'
  570. value.xaxis = this.mapData(data)
  571. value.yaxis = data
  572. this.requireList = value
  573. this.openDrawer = true
  574. },
  575. statusOrntDistributeData(value, data) {
  576. if (value.data === undefined) {
  577. this.clone()
  578. return
  579. }
  580. value.title = '需求方向分布图数据'
  581. value.xaxis = ['全部']
  582. this.requireList = { ...value, ...data, name: value.data.data ? value.data.data.name : value.data._origin.name }
  583. this.openDrawer = true
  584. },
  585. getTrendChart(value, option, data) {
  586. const titArr = ['新增趋势图', '上线趋势图', 'PRD评审趋势图', '占位', '技术准入趋势图']
  587. value.title = titArr[Number(this.activeTab) - 1] + '数据'
  588. value.toType = '需求'
  589. this.requireList = { ...value, ...data }
  590. this.openDrawer = true
  591. },
  592. getClickItem(value, data) {
  593. value.title = '周期统计数据'
  594. value.toType = '需求'
  595. value.xaxis = this.mapData(data)
  596. value.yaxis = data
  597. this.requireList = value
  598. this.openDrawer = true
  599. },
  600. statusAccumulate(value, option, data) { // 状态累积流量图
  601. value.title = '状态累积流量图数据'
  602. value.toType = '需求'
  603. value.towTimeLine = option.legend.data
  604. value.statusList = this.cumulativeData
  605. this.requireList = { ...value, xaxis: data[0].dayTime }
  606. this.openDrawer = true
  607. },
  608. queryData(value) { // 需求bug 浮层数据
  609. value.title = '缺陷统计数据'
  610. value.xaxis = ['全部', 'P0', 'P1', 'P2', 'P3']
  611. this.requireList = value
  612. this.openDrawer = true
  613. window.log({ c: 'statistic', d: 'requirement_statistic_defect_statistics' })
  614. },
  615. clickCodeData(value) {
  616. value.title = '需求分布图数据'
  617. value.toType = '需求'
  618. this.requireList = { ...value, ...this.distributeData }
  619. this.openDrawer = true
  620. window.log({ c: 'statistic', d: 'requirement_statistic_demand_distribution' })
  621. },
  622. statusStayChart(value, list, data) {
  623. value.title = '状态停留分布图数据'
  624. value.toType = '需求'
  625. value.towTimeLine = list
  626. value.statusList = data
  627. this.requireList = { ...value, xaxis: data.xaxis }
  628. this.openDrawer = true
  629. window.log({ c: 'statistic', d: 'requirement_statistic_state_stay' })
  630. },
  631. clone(v) {
  632. this.drawer = v
  633. this.openDrawer = false
  634. }
  635. }
  636. }
  637. </script>
  638. <style lang="scss" scoped>
  639. .defect-container {
  640. width: 100%;
  641. height:100%;
  642. background:#F2F3F6;
  643. display: inline-block;
  644. color: #666666;
  645. h3 {
  646. font-size: 18px;
  647. margin: 0;
  648. padding: 0;
  649. span {
  650. font-size: 14px;
  651. color: #666666;
  652. }
  653. }
  654. .defect-main {
  655. padding: 20px 20px 0 20px;
  656. height:100%;
  657. width:auto;
  658. background:#ffffff;
  659. margin: 10px;
  660. border-radius: 4px;
  661. .date-select {
  662. line-height: 20px;
  663. display: inline-block;
  664. .date-item {
  665. display: inline-block;
  666. width: 40px;
  667. text-align: center;
  668. cursor: pointer;
  669. border-radius: 2px;
  670. }
  671. .date-active {
  672. color: #FFFFFF;
  673. background-color: #409EFF;
  674. }
  675. }
  676. }
  677. }
  678. .data-total {
  679. display: grid;
  680. width: 100%;
  681. margin: auto;
  682. grid-template-columns: repeat(4,22%);
  683. grid-gap: 4%;
  684. padding-bottom: 40px;
  685. ul,li{
  686. padding:0;margin:0;list-style:none
  687. }
  688. .data-item {
  689. position: relative;
  690. width: 100%;
  691. border-radius: 8px;
  692. article {
  693. display: flex;
  694. flex-direction: column;
  695. align-items: flex-start;
  696. color: #FFFFFF;
  697. }
  698. .item-top {
  699. width: 100%;
  700. display: flex;
  701. align-items: center;
  702. padding: 10px 20px;
  703. font-size: 13px;
  704. .item-circle {
  705. height: 36px;
  706. width: 36px;
  707. border-radius: 50%;
  708. background:rgba(255,255,255,0.24);
  709. margin-right: 10px;
  710. display: flex;
  711. justify-content: center;
  712. align-items: center;
  713. img {
  714. height: 20px;
  715. width: 20px;
  716. }
  717. }
  718. span {
  719. margin-right: 5px;
  720. }
  721. }
  722. .item-line {
  723. width: 100%;
  724. border-bottom:1px solid rgba(255,255,255,0.2);
  725. }
  726. .item-title {
  727. font-size: 40px;
  728. padding: 5% 20px;
  729. cursor: pointer;
  730. }
  731. .item-up,.item-down {
  732. font-size: 13px;
  733. padding: 10px 20px 0 20px;
  734. margin-bottom: 20px;
  735. }
  736. .item-up i {
  737. color:#F32850
  738. }
  739. .item-down i {
  740. color:#9FFF39
  741. }
  742. }
  743. .item1 {
  744. background-image: url('../../../src/assets/defect_images/数据1.png');
  745. background-size: 100% 100%;
  746. background-position: 50% 50%;
  747. box-shadow:0px 50px 24px -25px rgba(64,137,255,0.30);
  748. }
  749. .item2 {
  750. background-image: url('../../../src/assets/defect_images/数据2.png');
  751. background-size: 100% 100%;
  752. background-position: 50% 50%;
  753. box-shadow:0px 50px 24px -25px rgba(78,188,250,0.40);
  754. }
  755. .item3 {
  756. background-image: url('../../../src/assets/defect_images/数据3.png');
  757. background-size: 100% 100%;
  758. background-position: 50% 50%;
  759. box-shadow:0px 50px 24px -25px rgba(255,136,134,0.30);
  760. }
  761. .item4 {
  762. background-image: url('../../../src/assets/defect_images/数据4.png');
  763. background-size: 100% 100%;
  764. background-position: 50% 50%;
  765. box-shadow:0px 50px 24px -25px rgba(83,97,255,0.30);
  766. }
  767. }
  768. .bottom-padding {
  769. padding-bottom: 30px;
  770. }
  771. .charts-main {
  772. padding-bottom: 20px;
  773. width:auto;
  774. background:#ffffff;
  775. margin: 10px;
  776. border-radius: 4px;
  777. .chart-item {
  778. margin-bottom: 30px;
  779. }
  780. .tab-change {
  781. overflow: hidden;
  782. }
  783. .chart-item-tip {
  784. padding: 6px 10px;
  785. margin-top: 5px;
  786. font-size: 12px;
  787. color: #444444;
  788. background: rgba(230, 162, 61, 0.1);
  789. border: 2px;
  790. i {
  791. margin-right: 10px;
  792. }
  793. }
  794. }
  795. .strong-font {
  796. color: #F01A1A !important;
  797. font-size: 18px !important;
  798. }
  799. /deep/.el-tabs__nav-wrap:after {
  800. background-color: #E4E7ED !important;
  801. }
  802. </style>