taskViewDetail.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. <template>
  2. <div class="bg-project" @click="display = false">
  3. <el-container>
  4. <el-header class="main-header">
  5. <div class="top-page-title">
  6. <el-tooltip :disabled="form_query.name && form_query.name.length > 20 ? false : true" effect="dark" :content="form_query.name" placement="bottom">
  7. <div class="header-title">任务 : {{ form_query.name | ellipsis(10) }}</div>
  8. </el-tooltip>
  9. <el-dropdown placement="bottom" @command="updateStatus">
  10. <el-button size="mini" plainclass="el-dropdown-link drop_down">
  11. {{ getStatus.msg }}
  12. <i class="el-icon-arrow-down el-icon--right" />
  13. </el-button>
  14. <el-dropdown-menu slot="dropdown" align="center">
  15. <el-dropdown-item
  16. v-for="item in allStatus"
  17. :key="item.msg"
  18. :command="{value:item.code,label:item.msg}"
  19. :disabled="form_query.status === item.code? true: false"
  20. >{{ item.msg }}</el-dropdown-item>
  21. </el-dropdown-menu>
  22. </el-dropdown>
  23. </div>
  24. <div class="top-tabs">
  25. <el-tabs v-model="activeName">
  26. <el-tab-pane label="概览" name="1" />
  27. <el-tab-pane label="缺陷" name="2" />
  28. <el-tab-pane label="报告" name="3" />
  29. <el-tab-pane label="统计" name="4" />
  30. </el-tabs>
  31. </div>
  32. <div class="top-control">
  33. <el-dropdown placement="bottom">
  34. <i class="el-icon-circle-plus icon-add" />
  35. <el-dropdown-menu slot="dropdown">
  36. <el-dropdown-item @click.native="created_bug()">新建缺陷</el-dropdown-item>
  37. <el-dropdown-item @click.native="createReport(1, form_query)">新建提测报告</el-dropdown-item>
  38. <el-dropdown-item @click.native="createReport(2, form_query)">新建测试报告</el-dropdown-item>
  39. <el-dropdown-item @click.native="createReport(3, form_query)">新建准出报告</el-dropdown-item>
  40. </el-dropdown-menu>
  41. </el-dropdown>
  42. <div class="line" />
  43. <span style="vertical-align: bottom; cursor: pointer; color: #6F7C93;" @click.stop="setChild(), display = true"><img style="width: 24px; display: inline-block;" :src="image_url">&nbsp; {{ num }} &nbsp;</span>
  44. <div class="line" />
  45. <i class="el-icon-setting icon-delete" @click="open_created" />
  46. <div class="line" />
  47. <i class="el-icon-delete icon-delete" @click="deleteVisible = true" />
  48. </div>
  49. </el-header>
  50. <!-- 概览 -->
  51. <el-container v-show="activeName === '1'" class="is-vertical">
  52. <section class="main-section">
  53. <div class="el-main-title">
  54. <div class="title-left-icon" />
  55. <div class="title-left-name">基础信息</div>
  56. </div>
  57. <div class="detail-info">
  58. <el-form :inline="true" :model="form_query" class="demo-form-inline" label-position="right" label-width="100px">
  59. <el-form-item label="所属项目:">
  60. <el-select v-model="form_query.projectId" placeholder="请选择" @change="changeArea">
  61. <el-option v-for="(item,index) in belongProjectList" :key="item.name + index" :label="item.name" :value="item.id" />
  62. </el-select>
  63. </el-form-item>
  64. <el-form-item label="所属需求:">
  65. <el-select v-model="form_query.requireId" placeholder="请选择" @change="changeArea">
  66. <el-option v-for="(item,index) in requireList" :key="item.name + index" :label="item.name" :value="item.id" />
  67. </el-select>
  68. </el-form-item>
  69. <el-form-item label="所属模块:">
  70. <span class="module">{{ form_query.moduleInfoName }}</span>
  71. </el-form-item>
  72. </el-form>
  73. <el-form :inline="true" :model="form_query" class="demo-form-inline" label-position="right" label-width="100px">
  74. <el-form-item label="开发负责人:">
  75. <search-people :value.sync="form_query.rdOwner" @change="changeArea" />
  76. </el-form-item>
  77. <el-form-item label="测试负责人:">
  78. <search-people :value.sync="form_query.qaOwner" @change="changeArea" />
  79. </el-form-item>
  80. <el-form-item label="是否跟版:">
  81. <el-select v-model="form_query.followVersion" size="small" filterable placeholder="请选择" @change="changeArea">
  82. <el-option v-for="(item,index) in dependList" :key="item.msg + index" :label="item.msg" :value="item.code" />
  83. </el-select>
  84. </el-form-item>
  85. </el-form>
  86. <el-form :inline="true" :model="form_query" class="demo-form-inline" label-position="right" label-width="100px">
  87. <el-form-item label="跟版客户端:">
  88. <el-select v-if="form_query.followVersion === 1" v-model="form_query.involveApp" size="small" filterable placeholder="请选择" @change="changeArea">
  89. <el-option v-for="(item,index) in appClient" :key="item.msg + index" :label="item.msg" :value="item.code" />
  90. </el-select>
  91. </el-form-item>
  92. <el-form-item label="任务进度:">
  93. <div class="form-progress">
  94. <el-progress :percentage="Number(form_query.rate && form_query.rate.substring(0,4)) || 0" color="#409eff" />
  95. </div>
  96. </el-form-item>
  97. </el-form>
  98. </div>
  99. </section>
  100. <section class="main-section">
  101. <div class="el-main-title">
  102. <div class="title-left-icon" />
  103. <div class="title-left-name">任务计划</div>
  104. </div>
  105. <div>
  106. <schedule-list :id="taskId" :type-list="taskScheduleEvent" />
  107. </div>
  108. </section>
  109. <section class="main-section">
  110. <div class="el-main-title">
  111. <div class="title-left-icon" />
  112. <div class="title-left-name">任务描述</div>
  113. </div>
  114. <div>
  115. <text-area :id="'pro-desc'" :value.sync="form_query.description" :empty-text="'点击'" :input-button="'添加描述'" @change="changeArea" />
  116. </div>
  117. </section>
  118. <section class="main-section">
  119. <div class="el-main-title">
  120. <div class="title-left-icon" />
  121. <div class="title-left-name">评论</div>
  122. </div>
  123. <div class="detail-info">
  124. <ul class="comment-main">
  125. <li v-for="(item,index) in comments" :key="'comment'+index">
  126. <span class="comment-name">{{ item.commentInfo.name }}</span>
  127. <span class="comment-gmtCreater">{{ item.commentInfo.gmtCreater }}</span>
  128. <span class="comment-content">{{ item.commentInfo.content }}</span>
  129. </li>
  130. </ul>
  131. <el-input
  132. v-model="commentContent"
  133. type="textarea"
  134. placeholder="请输入评论内容"
  135. maxlength="300"
  136. show-word-limit
  137. :autosize="{ minRows: 3, maxRows: 5}"
  138. style="margin-bottom: 20px"
  139. />
  140. <el-row>
  141. <el-col :span="2" :offset="22"><el-button type="primary" size="small" @click="addComment">发表评论</el-button></el-col>
  142. </el-row>
  143. </div>
  144. </section>
  145. </el-container>
  146. <!-- 概览 -->
  147. <!-- 缺陷 -->
  148. <el-container v-show="activeName === '2'" class="is-vertical">
  149. <section class="main-section">
  150. <bugs-list />
  151. </section>
  152. </el-container>
  153. <!-- 缺陷 -->
  154. <!-- 报告 -->
  155. <el-container v-show="activeName === '3'" class="is-vertical">
  156. <section class="main-section">
  157. <report-list />
  158. </section>
  159. </el-container>
  160. <!-- 报告 -->
  161. <!-- 统计 -->
  162. <el-container v-if="activeName === '4'" class="is-vertical">
  163. <section class="main-section" />
  164. </el-container>
  165. <!-- 统计 -->
  166. <!-- 新建(bug) -->
  167. <createdBug v-if="bug_open" ref="createdBug" />
  168. <Test-report v-if="dialogTest" ref="TestReport" />
  169. <Daily-report v-if="dialogDaily" ref="DailyReport" />
  170. <Client-report v-if="dialogClient" ref="ClientReport" />
  171. <!-- 新建 -->
  172. <!-- 编辑 -->
  173. <open-dialog v-if="updateVisible" ref="task_createdUpdata" />
  174. <!-- 编辑 -->
  175. <!-- 删除 -->
  176. <el-dialog :visible.sync="deleteVisible" width="30%" center :close-on-click-modal="false">
  177. <div align="center">确定要删除此 {{ form_query.name }} 任务吗?</div>
  178. <span slot="footer" class="dialog-footer">
  179. <el-button @click="deleteVisible = false">关 闭</el-button>
  180. <el-button type="primary" @click="taskDelete()">确 定</el-button>
  181. </span>
  182. </el-dialog>
  183. <!-- 删除 -->
  184. <normal-dialog :show-dialog.sync="statusDialog" :title="'状态变更:已上线'" :width="'50%'" @confirm="confirmStatus()">
  185. <div class="dialog-change-status">
  186. <span>实际上线时间:</span>
  187. <el-date-picker v-model="changeStatusDate" type="date" style="width:100%;" placeholder="选择日期" format="yyyy-MM-dd HH:mm:ss" />
  188. </div>
  189. </normal-dialog>
  190. <drawer
  191. ref="drawer"
  192. title="项目成员"
  193. center
  194. :display.sync="display"
  195. width="28%"
  196. :delete="form_query"
  197. :types="false"
  198. :inner="true"
  199. :mask="false"
  200. @childValInput="childVal"
  201. @click.stop
  202. />
  203. </el-container>
  204. </div>
  205. </template>
  206. <script>
  207. const _ = require('lodash')
  208. import {
  209. taskGet,
  210. configShowTaskEnum,
  211. tasktaskDelete,
  212. taskUpdate,
  213. commentCreate,
  214. commentList,
  215. configShowRequirementVersionEnum
  216. } from '@/api/taskIndex'
  217. import { projectListProject } from '@/api/requirement.js'
  218. import searchPeople from '@/components/select/searchPeople'
  219. import textArea from '@/components/input/textArea'
  220. import drawer from '@/views/projectManage/Drawer'
  221. import image_url from '@/assets/home_images/home_u.png'
  222. import createdBug from '@/views/projectManage/bugList/file/createdBug'
  223. import normalDialog from '@/components/dialog/normalDialog'
  224. import openDialog from '@/views/projectManage/dialog_vue'
  225. import scheduleList from './components/scheduleList'
  226. import bugsList from './components/bugsList'
  227. import reportList from './components/reportList'
  228. import TestReport from '@/views/Platform/presentation/Templates/TestReport' // 提测
  229. import DailyReport from '@/views/Platform/presentation/Templates/DailyReport' // 日报
  230. import ClientReport from '@/views/Platform/presentation/Templates/ClientReport' // 准出
  231. export default {
  232. components: {
  233. searchPeople,
  234. normalDialog,
  235. textArea,
  236. drawer,
  237. createdBug,
  238. openDialog,
  239. scheduleList,
  240. bugsList,
  241. reportList,
  242. TestReport,
  243. DailyReport,
  244. ClientReport
  245. },
  246. filters: {
  247. ellipsis(value, num) {
  248. if (!value) return ''
  249. if (value.length > num) {
  250. return value.slice(0, num) + '...'
  251. }
  252. return value
  253. }
  254. },
  255. data() {
  256. return {
  257. activeName: '1', // 顶部tab切换
  258. userInformation: localStorage.getItem('username'),
  259. userNames: localStorage.getItem('realname'),
  260. textarea: '', // 评论
  261. taskId: Number(this.$route.query.id), // 任务id
  262. allStatus: [], // 任务所有状态
  263. belongProjectList: [], // 所属项目列表
  264. requireList: [], // 所属需求列表
  265. appClient: [], // 跟版客户端列表
  266. taskScheduleEvent: [], // 排期类型
  267. dependList: [{ msg: '否', code: 2 }, { msg: '是', code: 1 }], // 是否跟版
  268. statusDialog: false, // 修改状态弹框
  269. changeStatusDate: null, // 状态改变时间
  270. form_query: {},
  271. display: false, // 设置成员弹框
  272. num: 0, // 成员数量
  273. image_url: image_url, // 成员icon
  274. updateVisible: false, // 编辑任务弹框
  275. deleteVisible: false, // 删除任务弹框
  276. bug_open: false, // 新建缺陷弹框
  277. dialogTest: false, // 新建提测报告
  278. dialogDaily: false, // 新建日报报告
  279. dialogClient: false, // 新建准出报告
  280. iterationList: [], // 所属迭代列表
  281. commentContent: null, // 评论内容
  282. comments: [] // 评论列表
  283. }
  284. },
  285. computed: {
  286. getStatus() {
  287. return this.allStatus.find(item => item.code === this.form_query.status) || { msg: null }
  288. }
  289. },
  290. created() {
  291. this.taskGet()
  292. this.getTaskStatus()
  293. this.getBelongProject()
  294. this.getRequireList()
  295. this.getCommentList()
  296. this.$store.state.data.status = true
  297. this.$store.state.data.bizId = true
  298. },
  299. destroyed() {
  300. this.$store.state.data.status = false
  301. this.$store.state.data.bizId = false
  302. },
  303. methods: {
  304. async changeArea(e) { // area修改
  305. const taskInfoDO = _.cloneDeep(this.form_query)
  306. const user = {
  307. name: localStorage.getItem('username'),
  308. ename: localStorage.getItem('realname'),
  309. id: ''
  310. }
  311. const res = await taskUpdate({ taskInfoDO, user })
  312. if (res.code === 200) {
  313. this.$message({ message: '修改', type: 'success', duration: 1000, offset: 150 })
  314. }
  315. this.taskGet()
  316. },
  317. async getBelongProject() { // 获取所属项目列表
  318. const res = await projectListProject({ bizId: Number(localStorage.getItem('bizId')) })
  319. if (res.code === 200) {
  320. this.belongProjectList = res.data
  321. }
  322. },
  323. async getRequireList() { // 获取所属需求列表
  324. const res = await configShowRequirementVersionEnum({ bizId: Number(localStorage.getItem('bizId')) })
  325. if (res.code === 200) {
  326. this.requireList = res.data
  327. }
  328. },
  329. async getTaskStatus() { // 获取任务状态列表,跟版客户端列表
  330. const res = await configShowTaskEnum()
  331. if (res.code === 200) {
  332. this.allStatus = res.data.taskStatus
  333. this.taskScheduleEvent = res.data.taskScheduleEvent || []
  334. this.appClient = res.data.appClient.map(item => {
  335. return {
  336. ...item,
  337. code: `${item.code}`
  338. }
  339. })
  340. console.log(this.appClient)
  341. }
  342. },
  343. async taskGet() { // 获取任务详情
  344. const res = await taskGet(this.$route.query.id)
  345. if (res.code === 200) {
  346. this.form_query = res.data
  347. }
  348. },
  349. async getCommentList() { // 获取任务评论
  350. const res = await commentList({ type: 3, joinId: this.taskId })
  351. if (res.code === 200) {
  352. this.comments = res.data
  353. this.commentContent = ''
  354. }
  355. },
  356. async addComment() { // 发表任务评论
  357. if (this.commentContent.replace(/\s+/g, '') === '' || this.commentContent === null) {
  358. this.$message.warning('评论不能为空')
  359. return
  360. }
  361. const commentInfo = {
  362. joinId: this.taskId,
  363. content: this.commentContent,
  364. type: 3,
  365. fatherId: 0,
  366. name: this.userNames,
  367. email: this.userInformation
  368. }
  369. const user = { name: this.userNames, ename: this.userInformation, id: '' }
  370. const res = await commentCreate({ commentInfo, user })
  371. if (res.code === 200) {
  372. this.$message({ message: '评论成功', type: 'success', duration: 1000, offset: 150 })
  373. this.getCommentList()
  374. } else {
  375. this.$message.warning(res.msg)
  376. }
  377. },
  378. async updateStatus(e) { // 状态改变
  379. if (e.value === 5) { // 已上线
  380. this.statusDialog = true
  381. this.form_query.status = e.value
  382. } else {
  383. this.changeArea()
  384. }
  385. },
  386. async confirmStatus() { // 确认更改状态
  387. this.form_query.onlineRealTime = this.changeStatusDate
  388. this.changeArea()
  389. },
  390. childVal(val) {
  391. this.num = val
  392. },
  393. setChild() { // 设置成员
  394. this.$refs.drawer.getRoleList()
  395. },
  396. open_created() { // 编辑任务
  397. // 打开弹窗
  398. this.updateVisible = true
  399. this.$nextTick(() => {
  400. this.$refs.task_createdUpdata.init(3, [null, this.taskId])
  401. })
  402. },
  403. async taskDelete() { // 删除任务
  404. const user = { name: this.userNames, ename: this.userInformation, id: '' }
  405. const res = await tasktaskDelete(user, this.taskId)
  406. if (res.code === 200) {
  407. this.$message({ message: '删除成功', type: 'warning', duration: 1000, offset: 150 })
  408. }
  409. },
  410. created_bug() { // 缺陷创建
  411. this.bug_open = true
  412. this.$nextTick(() => {
  413. this.$refs.createdBug.init(1)
  414. })
  415. },
  416. createReport(e, ele) { // 创建报告
  417. switch (e) {
  418. case 1: // 提测
  419. this.dialogTest = true
  420. this.$nextTick(() => { this.$refs.TestReport.init(1, ele) })
  421. break
  422. case 2: // 日报
  423. this.dialogDaily = true
  424. this.$nextTick(() => { this.$refs.DailyReport.init(1) })
  425. break
  426. case 3:
  427. this.dialogClient = true
  428. this.$nextTick(() => { this.$refs.ClientReport.init(1, ele) })
  429. break
  430. }
  431. }
  432. }
  433. }
  434. </script>
  435. <style scoped lang="scss">
  436. @import '@/styles/detail-pages.scss';
  437. /deep/.el-button {
  438. cursor: pointer;
  439. }
  440. @include hide-open-header;
  441. .bg-project {
  442. @include bg-project;
  443. }
  444. .main-header {
  445. @include main-header;
  446. }
  447. .main-header::after {
  448. @include main-header-after;
  449. }
  450. .main-section {
  451. @include main-section;
  452. .detail-info {
  453. padding: 0 34px 20px 34px;
  454. /deep/.el-input__inner{
  455. border: 1px solid rgba(220,223,230,0)
  456. }
  457. /deep/.el-input__inner:hover{
  458. border: 1px solid rgba(220,223,230,1)
  459. }
  460. /deep/.is-focus .el-input__inner {
  461. border: 1px solid #409EFF;
  462. }
  463. /deep/.el-select{
  464. .el-input__suffix-inner {
  465. visibility: hidden;
  466. }
  467. }
  468. /deep/.el-select:hover{
  469. .el-input__suffix-inner {
  470. visibility: visible;
  471. }
  472. }
  473. .demo-form-inline {
  474. .el-form-item {
  475. width: 33%;
  476. margin-right: 0;
  477. }
  478. }
  479. .comment-main {
  480. list-style: none;
  481. padding: 0px;
  482. margin: 0 0 20px 0;
  483. li {
  484. list-style: none;
  485. padding: 0px;
  486. margin: 0px;
  487. }
  488. .comment-name {
  489. font-size:14px;
  490. color:#333B4A;
  491. }
  492. .comment-gmtCreater {
  493. margin-left:20px;
  494. color: #9B9B9B;
  495. font-size:12px
  496. }
  497. .comment-content {
  498. margin-left:20px;
  499. font-size:14px;
  500. color:#333B4A;
  501. margin-top: 10px;
  502. white-space: pre-line;
  503. }
  504. }
  505. .PRD-link {
  506. width: 50%;
  507. overflow: hidden;
  508. text-overflow:ellipsis;
  509. white-space: nowrap;
  510. }
  511. }
  512. }
  513. .module {
  514. width: 100%;
  515. overflow: hidden;
  516. }
  517. .dialog-change-status {
  518. margin: 2% 3%;
  519. display: flex;
  520. justify-content: space-between;
  521. align-items: center;
  522. white-space:nowrap;
  523. }
  524. .form-progress {
  525. width: 200px;
  526. padding-top: 12px;
  527. }
  528. </style>