taskList.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <template>
  2. <div>
  3. <el-row v-if="!showHeader" class="select-main" type="flex" align="center">
  4. <el-col :span="2" class="flex-align-center">
  5. <el-checkbox v-model="planChecked" class="plan-checked" @change="changeCheck" />
  6. </el-col>
  7. <el-col :span="3" class="item-checked">已选择<span style="color: #409EFF">{{ curcentChecked }}</span>个</el-col>
  8. <el-col :span="1" class="item-click">|</el-col>
  9. <el-col :span="2" class="item-click click-blue" @click.native="addSechedule()">添加排期</el-col>
  10. <el-col :span="2" class="item-click click-blue" @click.native="handlePlan('test')">提测</el-col>
  11. <el-col :span="2" class="item-click click-blue" @click.native="handlePlan('allow')">准出</el-col>
  12. <el-col :span="4" class="item-click click-blue" @click.native="handlePlan('daily')">建立测试日报</el-col>
  13. <el-col :span="4" class="item-click" @click.native="handlePlan('cancel')">取消选择</el-col>
  14. </el-row>
  15. <el-table
  16. ref="planTable"
  17. :data="all_task"
  18. style="width: 100%;"
  19. size="mini"
  20. row-key="id"
  21. :expand-row-keys="expandArr"
  22. :header-cell-style="{ color: 'rgb(74, 74, 74)', fontSize: '14px', fontWeight: '500', textAlign: 'center' }"
  23. show-overflow-tooltip="true"
  24. :show-header="showHeader"
  25. :header-row-style="{height: '50px'}"
  26. @selection-change="handleSelectionChange"
  27. >
  28. <el-table-column type="selection" width="55" align="center" />
  29. <el-table-column type="expand" width="40">
  30. <template slot="header">
  31. <div class="expand"><i v-show="!allChange" class="el-icon-plus" @click="expandAll(true)" /></div>
  32. <div class="expand"><i v-show="allChange" class="el-icon-minus" @click="expandAll(false)" /></div>
  33. </template>
  34. <template slot-scope="props">
  35. <schedule-list :id="props.row.id" :type-list="taskScheduleEvent" />
  36. </template>
  37. </el-table-column>
  38. <el-table-column label="优先级" prop="priority" width="90" sortable align="center">
  39. <template slot-scope="scope" style="text-align: center;">
  40. <span class="div_priority" :class="scope.row.priorityString">
  41. {{ scope.row.priorityString }}
  42. </span>
  43. </template>
  44. </el-table-column>
  45. <el-table-column label="任务名称" width="200" align="center" show-overflow-tooltip>
  46. <template slot-scope="scope"><span class="task-title" @click="link_task(scope.row.id)">{{ scope.row.name }}</span></template>
  47. </el-table-column>
  48. <el-table-column label="所属模块" width="150" align="center" show-overflow-tooltip>
  49. <template slot-scope="scope">{{ scope.row.moduleInfoName }}</template>
  50. </el-table-column>
  51. <el-table-column label="状态" width="105" align="center">
  52. <template slot-scope="scope">
  53. <el-select
  54. v-model="scope.row.status"
  55. :class="{
  56. 'status_color': scope.row.status === 0,
  57. 'status_color1': scope.row.status === 1,
  58. 'status_color4': scope.row.status === 3,
  59. 'status_color6': scope.row.status === 2,
  60. 'status_color7': scope.row.status === 4,
  61. 'status_color2': scope.row.status === 5
  62. }"
  63. class="btns"
  64. size="mini"
  65. @change="changeStatus(scope.row)"
  66. >
  67. <el-option v-for="item in allStatus" :key="item.code" :label="item.msg" :value="item.code" />
  68. </el-select>
  69. </template>
  70. </el-table-column>
  71. <el-table-column label="跟版客户端" width="120" align="center" show-overflow-tooltip>
  72. <template slot-scope="scope">{{ scope.row.app }}</template>
  73. </el-table-column>
  74. <el-table-column label="开发负责人" width="100" align="center" show-overflow-tooltip>
  75. <template slot-scope="scope">{{ scope.row.rdObject ? scope.row.rdObject.name : '' }}</template>
  76. </el-table-column>
  77. <el-table-column label="测试负责人" width="100" align="center" show-overflow-tooltip>
  78. <template slot-scope="scope">{{ scope.row.qaObject ? scope.row.qaObject.name : '' }}</template>
  79. </el-table-column>
  80. <el-table-column label="任务进度" min-width="150" align="center">
  81. <template slot-scope="scope">
  82. <el-progress :percentage="Number(scope.row.rate && scope.row.rate.substring(0,4))" color="#409eff" />
  83. </template>
  84. </el-table-column>
  85. </el-table>
  86. <TestReport v-if="dialogTestReport" ref="TestReport" />
  87. <DailyReport v-if="dialogDailyReport" ref="DailyReport" />
  88. <ClientReport v-if="dialogClientReport" ref="ClientReport" />
  89. <task-dialog v-if="showTaskDialog" :show.sync="showTaskDialog" :task-id="taskId.id" :status-name="taskId.statusString" @getList="get_allTask" />
  90. <normal-dialog :show-dialog.sync="statusDialog" :title="'状态变更:已上线'" :width="'50%'" @confirm="confirmStatus()">
  91. <div class="dialog-change-status">
  92. <span>实际上线时间:</span>
  93. <el-date-picker v-model="changeStatusDate" type="date" style="width:100%;" placeholder="选择日期" format="yyyy-MM-dd HH:mm:ss" />
  94. </div>
  95. </normal-dialog>
  96. <!-- 批量排期 -->
  97. <modify-schedule
  98. v-if="visibleSchedule"
  99. :visible.sync="visibleSchedule"
  100. :select-task-list="selectTaskList"
  101. title="新建排期"
  102. @update="get_allTask()"
  103. />
  104. </div>
  105. </template>
  106. <script>
  107. import TestReport from '@/views/Platform/presentation/Templates/TestReport' // 提测
  108. import DailyReport from '@/views/Platform/presentation/Templates/DailyReport' // 日报
  109. import ClientReport from '@/views/Platform/presentation/Templates/ClientReport' // 准出
  110. import { getTaskByRequireId } from '@/api/requirement'
  111. import { taskUpdate } from '@/api/projectViewDetails'
  112. import { configShowTaskEnum } from '@/api/taskIndex'
  113. import scheduleList from './scheduleList'
  114. import modifySchedule from './modifySchedule'
  115. import normalDialog from '@/components/dialog/normalDialog'
  116. import '@/styles/PublicStyle/index.scss'
  117. import taskDialog from '@/views/projectManage/taskList/dialog/taskDialog' // 任务状态修改(已上线/已提测/已准出)
  118. export default {
  119. components: {
  120. normalDialog,
  121. TestReport,
  122. DailyReport,
  123. ClientReport,
  124. scheduleList,
  125. taskDialog,
  126. modifySchedule
  127. },
  128. data() {
  129. return {
  130. changeData: new Map(),
  131. allChange: false, // 是否全展开
  132. expandArr: [], // 展开行数组
  133. showTaskDialog: false, // 状态弹窗
  134. inputValue: '',
  135. all_task: [], // 任务列表
  136. allStatus: [], // 任务所有状态
  137. taskScheduleEvent: [], // 排期类型
  138. showHeader: true, // 任务列表的表头是否显示
  139. curcentList: [], // 当前已选择的列表
  140. curcentChecked: 0, // 当前已选择的数量
  141. planChecked: false,
  142. planHandleType: '', // 任务列表操作类型
  143. dialogTestReport: false, // 提测
  144. dialogDailyReport: false, // 日报
  145. dialogClientReport: false, // 准出
  146. statusDialog: false, // 修改状态弹框
  147. changeStatusDate: null, // 状态改变时间
  148. nowChangeTask: null, // 当前正在改变的任务对象
  149. taskId: '', // 将要修改状态的任务id
  150. visibleSchedule: false, // 排期弹框
  151. selectTaskList: [] // 已选任务的id
  152. }
  153. },
  154. watch: {
  155. value: {
  156. handler(newV, oldV) {
  157. this.inputValue = newV
  158. },
  159. immediate: true
  160. }
  161. },
  162. created() {
  163. this.getTaskStatus()
  164. this.get_allTask()
  165. },
  166. methods: {
  167. async get_allTask() { // 获取全部任务
  168. const res = await getTaskByRequireId({
  169. id: this.$route.query.id
  170. })
  171. if (res.code === 200 && res.data) {
  172. console.log(res)
  173. this.all_task = res.data.taskDetails || []
  174. // for (const [key, value] of Object.entries(res.data[0])) {
  175. // console.log(`${key}: ${value}`)
  176. // }
  177. }
  178. },
  179. async getTaskStatus() { // 获取任务状态列表
  180. const res = await configShowTaskEnum()
  181. if (res.code === 200) {
  182. this.allStatus = res.data.taskStatus
  183. this.taskScheduleEvent = res.data.taskScheduleEvent || []
  184. }
  185. },
  186. changeCheck(val) {
  187. if (val) {
  188. this.all_task.forEach(row => {
  189. this.$refs.planTable.toggleRowSelection(row, true)
  190. })
  191. } else {
  192. this.$refs.planTable.clearSelection()
  193. }
  194. },
  195. expandAll(isEx) { // 全部展开
  196. this.allChange = isEx
  197. isEx ? this.expandArr = this.all_task.map(item => item.id) : this.expandArr = []
  198. },
  199. async changeStatus(e) { // 状态改变
  200. if (e.status === 2 || e.status === 4 || e.status === 5) {
  201. this.taskId = e
  202. this.allStatus.map(item => {
  203. item.code === e.status ? this.taskId.statusString = item.msg : ''
  204. })
  205. this.showTaskDialog = true
  206. this.nowChangeTask = e
  207. return
  208. } else {
  209. const user = {
  210. name: localStorage.getItem('username'),
  211. ename: localStorage.getItem('realname'),
  212. id: ''
  213. }
  214. const taskInfoDO = e
  215. const resTask = await taskUpdate({ taskInfoDO, user })
  216. if (resTask.code === 200) {
  217. this.$message({ message: '修改成功', type: 'success', offset: 150 })
  218. }
  219. }
  220. },
  221. async confirmStatus() { // 确认更改状态
  222. const user = {
  223. name: localStorage.getItem('username'),
  224. ename: localStorage.getItem('realname'),
  225. id: ''
  226. }
  227. const taskInfoDO = this.nowChangeTask
  228. taskInfoDO.onlineRealTime = this.changeStatusDate
  229. const resTask = await taskUpdate({ taskInfoDO, user })
  230. if (resTask.code === 200) {
  231. this.$message({ message: '修改成功', type: 'success', offset: 150 })
  232. }
  233. },
  234. handleSelectionChange(val) { // 任务列表删选操作
  235. val.length > 0 ? this.showHeader = false : this.showHeader = true
  236. this.curcentChecked = val.length
  237. this.curcentList = val
  238. if (val.length === this.all_task.length) {
  239. this.planChecked = true
  240. }
  241. },
  242. handlePlan(type) { // 任务列表操作
  243. this.planHandleType = type
  244. switch (type) {
  245. case 'test':
  246. this.filtrateTest()
  247. break
  248. case 'allow':
  249. this.filtrateAllow()
  250. break
  251. case 'daily':
  252. this.filtrateDaily()
  253. break
  254. case 'cancel':
  255. this.$refs.planTable.clearSelection()
  256. break
  257. }
  258. },
  259. addSechedule() {
  260. this.visibleSchedule = true
  261. this.selectTaskList = this.curcentList
  262. },
  263. filtrateTest() { // 提测筛选
  264. this.dialogTestReport = true
  265. this.$nextTick(() => {
  266. this.$refs.TestReport.init(7, this.curcentList.map(item => { return item.id }))
  267. })
  268. },
  269. filtrateAllow() { // 准出筛选
  270. this.dialogClientReport = true
  271. this.$nextTick(() => {
  272. this.$refs.ClientReport.init(7, this.curcentList.map(item => { return item.id }))
  273. })
  274. },
  275. filtrateDaily() { // 建立日报
  276. this.dialogDailyReport = true
  277. this.$nextTick(() => {
  278. this.$refs.DailyReport.init(7, this.curcentList.map(item => { return item.id }))
  279. })
  280. },
  281. link_task(id) { // 跳转到任务详情页
  282. this.$router.push({ name: '任务详情', query: { id: id }})
  283. }
  284. }
  285. }
  286. </script>
  287. <style lang="scss" scoped>
  288. @mixin setStatus($color) {
  289. input {
  290. color:$color;
  291. border: 1px solid $color;
  292. }
  293. >>> .el-select__caret{
  294. color:$color;
  295. }
  296. >>> .el-input__inner{
  297. color:$color;
  298. border-color: $color;
  299. }
  300. >>> .el-input__inner:focus {
  301. border-color: $color;
  302. }
  303. }
  304. >>>.el-row .el-col {
  305. margin: 10px 0;
  306. }
  307. .task-title {
  308. cursor: pointer;
  309. }
  310. .P0 {
  311. background-color: #F56C6C;
  312. }
  313. .P1 {
  314. background-color: #FF8952;
  315. }
  316. .P2 {
  317. background-color: #F5E300;
  318. }
  319. .P3 {
  320. background-color: #7ED321;
  321. }
  322. .P4 {
  323. background-color: #61D3B8;
  324. }
  325. .P5 {
  326. background-color: #69B3FF;
  327. }
  328. .P6 {
  329. background-color: #BDBDBD;
  330. }
  331. .status0 {
  332. @include setStatus(#409EFF)
  333. }
  334. .status1 {
  335. @include setStatus(#FF8952)
  336. }
  337. .status3 {
  338. @include setStatus(#13C2C2)
  339. }
  340. .status5 {
  341. @include setStatus(#7ED321)
  342. }
  343. .expand i {
  344. border:1px solid #DCDFE6;
  345. }
  346. >>>.el-table__expand-icon{
  347. font-size: 14px;
  348. .el-icon{
  349. margin: 0;
  350. transform: translate(-50%, -50%);
  351. border:1px solid #DCDFE6;
  352. }
  353. }
  354. >>>.el-table__expand-icon .el-icon-arrow-right::before{
  355. content: "\E6D9";
  356. }
  357. >>>.el-table__expand-icon--expanded .el-icon-arrow-right::before{
  358. content: "\E6D8";
  359. }
  360. >>>.el-table__expand-icon--expanded {
  361. transform: rotate(180deg);
  362. }
  363. >>>.el-table__expanded-cell {
  364. background-color: #FFFFFF;
  365. padding: 0;
  366. }
  367. >>>.el-table__expanded-cell:hover {
  368. background-color: #FFFFFF !important;
  369. }
  370. .div_priority {
  371. text-align: center;
  372. color: #ffffff;
  373. padding: inherit;
  374. border-radius: 4px;
  375. width: 40px;
  376. display: inline-block;
  377. }
  378. .plan-checked {
  379. padding-left: 21px;
  380. }
  381. .select-main {
  382. height: 50px;
  383. border-bottom: 1px solid #DCDFE6;
  384. .flex-align-center {
  385. display: flex;
  386. align-items: center;
  387. }
  388. .item-checked {
  389. color: #606266;
  390. font-size: 14px;
  391. display: flex;
  392. align-items: center;
  393. justify-content: left;
  394. cursor: pointer;
  395. }
  396. .item-click{
  397. color: #606266;
  398. font-size: 14px;
  399. display: flex;
  400. align-items: center;
  401. justify-content: center;
  402. cursor: pointer;
  403. }
  404. .click-blue {
  405. color: #409EFF;
  406. }
  407. }
  408. .descr {
  409. display: flex;
  410. justify-content: flex-start;
  411. }
  412. .planList >>> .el-table th>.cell {
  413. padding-left: 14px;
  414. padding-right: 14px;
  415. }
  416. .dialog-change-status {
  417. margin: 2% 3%;
  418. display: flex;
  419. justify-content: space-between;
  420. align-items: center;
  421. white-space:nowrap;
  422. }
  423. </style>