demand.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. <template>
  2. <!-- 表头 -->
  3. <div class="schedule-list">
  4. <el-table v-if="tableHeader === false" max-height="38px" :data="datas" class="tableHeader" border size="mini" :header-cell-style="{ background: 'rgba(247,247,247,1)', color: 'rgb(74, 74, 74)', fontSize: '14px', fontWeight: '500'}" @selection-change="changeCheckout(1)">
  5. <el-table-column v-if="locking" type="selection" width="50" align="center" />
  6. <el-table-column prop="date" label="任务" width="300" />
  7. <el-table-column prop="type" label="类型" min-width="70" />
  8. <el-table-column prop="desc" label="描述" min-width="150" />
  9. <el-table-column prop="seperateDaysNoHoliday" label="排期" min-width="160" />
  10. <el-table-column prop="dayLength" label="时长" min-width="50" />
  11. <el-table-column prop="peopleList" label="参与人员" min-width="150" />
  12. <el-table-column label="操作" width="120" />
  13. </el-table>
  14. <div v-if="tableHeader === true" class="Layout_space_between" style="height: 40px;;border: 1px solid #EBEEF5;">
  15. <div class="Layout_flex_start" style="width: 90%">
  16. <el-checkbox v-model="checkAlls" style="padding: 17.5px; line-height: 20px; border-right: 1px solid #EBEEF5" @change="changeCheckout(checkAlls)" />
  17. <div style="margin: 0 30px 0 10px" class="endCheck"> 已选择 <span style="color:rgba(64,158,255,1) ">{{ taskList.length }}</span> 个</div>
  18. <div class="endCheck cursorPo" @click="clickAddScheduling(1)"><i class="el-icon-document" /> 添加排期</div>
  19. </div>
  20. <div class="endCheck cursorPo" @click="Deselect">取消选择</div>
  21. </div>
  22. <!-- 表头 -->
  23. <!-- 任务表格 -->
  24. <el-table ref="taskList" :data="tableData" :cell-class-name="addClass" :header-cell-style="{ background: 'rgba(247,247,247,1)', color: 'rgb(74, 74, 74)', fontSize: '14px', fontWeight: '500'}" border :show-header="false" @selection-change="handleSelectionChange">
  25. <el-table-column v-if="locking" type="selection" width="50" align="center" />
  26. <el-table-column label="任务" width="300" align="left">
  27. <template slot-scope="scope">
  28. <div v-if="!scope.row.vsInput">
  29. <div class="templatName">
  30. <el-tooltip class="item" effect="dark" :content="scope.row.moduleInfoName" placement="top">
  31. <span>{{ scope.row.moduleInfoName === null ? "" : scope.row.moduleInfoName.substring(0,9) }}</span>
  32. </el-tooltip>
  33. <span v-if="scope.row.involveAppString !== null" class="el-involveApp">{{ scope.row.involveAppString }}</span>
  34. </div>
  35. <div class="Layout_space_between" @mouseover="scope.row.vVisible = true" @mouseout="scope.row.vVisible = false">
  36. <div class="Layout_flex_start">
  37. <div class="templatTaskName cursorPo" @click="clickTemplatTaskName(scope.row.id)">{{ scope.row.name }}</div>
  38. <el-tooltip v-if="locking" class="item" effect="dark" :content="scope.row.isScheduleLocked === 1? '点击解锁排期' : '点击锁定排期'" placement="top">
  39. <div :class="scope.row.isScheduleLocked === 1 ? 'el-icon-lock' : 'el-icon-unlock'" @click="changeSchedule(scope.row)" />
  40. </el-tooltip>
  41. </div>
  42. <div v-if="locking" v-show="scope.row.vVisible" class="iconEdit"><i class="el-icon-edit-outline iconPadding cursorPo" @click="editTask(scope.row)" /> <i v-show="scope.row.isScheduleLocked === 0" class="el-icon-circle-plus-outline cursorPo" @click="clickAddScheduling(2,scope.row)" /></div>
  43. </div>
  44. <div class="templatCreator">
  45. 开发负责人:{{ scope.row.rdObject.name !== null? scope.row.rdObject.name: '无' }} 测试负责人: {{ scope.row.qaObject.name !== null?scope.row.qaObject.name: '无' }}
  46. </div>
  47. </div>
  48. <el-input v-if="scope.row.vsInput" ref="taskName" v-model="taskName" type="textarea" rows="4" placeholder="请输入内容" maxlength="150" show-word-limit @blur="changeTaskName(scope.row)" />
  49. </template>
  50. </el-table-column>
  51. <el-table-column label="任" style="padding: 20px;">
  52. <template slot-scope="scope">
  53. <schedule-list :id="scope.row.id" ref="taskSchedule" :locking="locking" :select-task-list="taskList" :required-list="taskScheduleLists(scope.row.id)" @listByTask="listByTask(newID)" />
  54. </template>
  55. </el-table-column>
  56. </el-table>
  57. <!-- 任务表格 -->
  58. <!-- 日期详情 -->
  59. <el-row><span class="demandLayout">交付日期:</span><span class="demandeta">{{ dataList.endTime }}</span></el-row>
  60. <el-row><span class="demandLayout">排期:</span><span class="demandeta">{{ dataList.startTime || '' }} ~ {{ dataList.endTime }}</span></el-row>
  61. <el-row :gutter="20">
  62. <el-col v-for="(item, index) in scheduleDetail" :key="index" :span="6"><span class="demandLayout">{{ index }}:</span><span class="demandeta">{{ item.startTime }} ~ {{ item.endTime }}</span></el-col>
  63. </el-row>
  64. <el-row><span class="demandLayout">预计上线版本:</span> <span v-for="item in preOnlineVersion" :key="item" class="demandeta">{{ item }}</span></el-row>
  65. <!-- 日期详情 -->
  66. <!-- 排期锁定弹窗 -->
  67. <schedule ref="ScheduleEvent" :visible.sync="scheduleVisble" :name="'任务'" :is-schedule-locked="isScheduleLocked" :require-id="Number(taskId)" @updataData="listByTask(newID)" />
  68. <!-- 排期锁定弹窗 -->
  69. </div>
  70. </template>
  71. <script>
  72. import { EncryptId } from '@/utils/crypto-js.js'
  73. import { listByRequire } from '@/api/requirement.js'
  74. import scheduleList from '@/views/projectManage/components/scheduleList.vue'
  75. import '@/styles/PublicStyle/index.scss' // 通用css
  76. import { taskUpdate } from '@/api/taskIndex'
  77. import schedule from '@/views/projectManage/schedule' // 排期锁定弹窗
  78. export default {
  79. components: {
  80. scheduleList,
  81. schedule
  82. },
  83. props: {
  84. id: {
  85. type: [String, Number],
  86. default: () => null,
  87. required: false
  88. }
  89. },
  90. data() {
  91. return {
  92. requirementId: -1,
  93. tableData: [],
  94. checkAlls: false,
  95. taskScheduleList: [],
  96. scheduleList: [],
  97. datas: [{
  98. date: '',
  99. type: '',
  100. desc: '',
  101. seperateDaysNoHoliday: '',
  102. dayLength: '',
  103. peopleList: ''
  104. }],
  105. newID: '',
  106. isScheduleLocked: '', // 当前排期的状态
  107. taskId: '', // taskID
  108. scheduleVisble: false, // 排期锁定
  109. userInformation: localStorage.getItem('username'),
  110. userNames: localStorage.getItem('realname'),
  111. taskList: [], // 全选list
  112. tableHeader: false, // 表头切换
  113. taskName: '', // taskname
  114. scheduleDetail: {}, // 用例/开发/提测/测试/准出/上线
  115. preOnlineVersion: [], // 预计上线版本
  116. dataList: {}, // 排期
  117. taskScheduleEvent: [], // 排期类型
  118. locking: true, // 查看历史记录锁定能
  119. isDelete: false // 删除排期操作
  120. }
  121. },
  122. watch: {
  123. id: {
  124. handler(newV, old) {
  125. if (newV === -1) return
  126. this.newID = newV
  127. this.listByTask(newV)
  128. },
  129. immediate: true
  130. }
  131. },
  132. methods: {
  133. async listByTask(id) { // 获取排期列表
  134. this.taskList = []
  135. this.scheduleVisble = false
  136. const res = await listByRequire(id)
  137. if (res.code === 200) {
  138. this.$nextTick(() => {
  139. this.tableData = res.data.taskDetailList // 任务list
  140. this.dataList = res.data // 排期
  141. this.scheduleList = res.data.scheduleDetailRespons || []
  142. this.scheduleDetail = res.data.timeInfos // 用例/开发/提测/测试/准出/上线
  143. this.preOnlineVersion = res.data.preOnlineVersion // 预计上线版本
  144. this.taskScheduleEvent = res.data.scheduleDetailRespons // 排期详情
  145. this.tableData = this.tableData.map(item => ({
  146. ...item,
  147. vVisible: false,
  148. vsInput: false
  149. }))
  150. })
  151. }
  152. },
  153. addClass({ row, column, rowIndex, columnIndex }) {
  154. if (columnIndex === 2) {
  155. return 'cell-grey'
  156. }
  157. },
  158. lockingchange() {
  159. this.locking = true
  160. },
  161. changeSchedule(ele) { // 修改锁定状态
  162. if (this.dataList.isScheduleLocked === 1 && ele.isScheduleLocked === 1) {
  163. this.$message({ message: '无法解锁,请先变更归属需求的排期状态为未锁定状态!', type: 'error', duration: 3000, offset: 150 })
  164. } else {
  165. this.isScheduleLocked = ele.isScheduleLocked
  166. this.taskId = ele.id
  167. this.scheduleVisble = true
  168. }
  169. },
  170. async changeTaskName(val) { // 修改taskname
  171. val.vsInput = false
  172. val.vVisible = false
  173. val.name = this.taskName.split(' ').join('').length === 0 ? val.name : this.taskName
  174. const taskInfoDO = val
  175. const user = { name: this.userNames, ename: this.userInformation, id: '' }
  176. const res = await taskUpdate({ taskInfoDO, user })
  177. if (res.code === 200) {
  178. this.$message({ message: '已修改任务名称', type: 'success', duration: 1000, offset: 150 })
  179. }
  180. },
  181. clickAddScheduling(index, ele) { // 模拟调用自组件方法
  182. if (index === 2) {
  183. this.taskList = []
  184. this.taskList.push(ele)
  185. }
  186. const taskA = []
  187. this.taskList.map(item => {
  188. if (item.isScheduleLocked === 1) {
  189. taskA.push(item.taskIdSting)
  190. }
  191. })
  192. if (taskA.length !== 0) {
  193. this.$message({ message: '任务 ' + taskA + ' 的排期已锁定,请先解锁排期后再添加排期', type: 'warning', offset: 150 })
  194. return
  195. }
  196. this.$refs.taskSchedule.addSchedule()
  197. },
  198. clickTemplatTaskName(id) { // 任务名称店家跳转
  199. const bizId_id = EncryptId(`${this.bizId}_${id}`)
  200. const { href } = this.$router.resolve({ name: '任务详情', query: { bizId_id: bizId_id }})
  201. window.open(href, '_blank')
  202. },
  203. editTask(val) { // 点击修改taskName
  204. val.vsInput = true
  205. this.taskName = val.name
  206. this.$nextTick(() => {
  207. this.$refs.taskName.focus()
  208. })
  209. },
  210. changeCheckout(rows) {
  211. if (rows) {
  212. this.tableData.forEach(row => {
  213. this.$refs.taskList.toggleRowSelection(row, true)
  214. })
  215. } else {
  216. this.$refs.taskList.clearSelection()
  217. }
  218. },
  219. Deselect() { // 取消选择
  220. this.taskList.forEach(row => {
  221. this.$refs.taskList.clearSelection()// 调用这个方法
  222. })
  223. this.tableHeader = false
  224. this.taskList = []
  225. },
  226. handleSelectionChange(val) {
  227. this.taskList = val
  228. this.taskList.length === this.tableData.length ? this.checkAlls = true : this.checkAlls = false
  229. if (this.taskList.length > 0) {
  230. this.tableHeader = true
  231. } else {
  232. this.tableHeader = false
  233. }
  234. },
  235. taskScheduleLists(id) {
  236. for (var key in this.taskScheduleEvent) {
  237. if (id === Number(key)) {
  238. return this.taskScheduleEvent[key]
  239. }
  240. }
  241. }
  242. }
  243. }
  244. </script>
  245. <style lang="scss" scoped>
  246. .templatName {
  247. font-size:12px;
  248. font-family:MicrosoftYaHei;
  249. line-height:14px;
  250. color:rgba(102,102,102,1);
  251. opacity:1;
  252. margin: 5px 0;
  253. }
  254. .templatTaskName {
  255. font-size:14px;
  256. font-family:MicrosoftYaHei;
  257. line-height:23px;
  258. color:rgba(51,51,51,1);
  259. margin-right: 5px;
  260. opacity:1;
  261. }
  262. .cursorPo:hover {
  263. color:#409EFF;
  264. cursor: pointer;
  265. }
  266. .templatCreator {
  267. font-size:12px;
  268. font-family:MicrosoftYaHei;
  269. line-height:14px;
  270. color:rgba(102,102,102,1);
  271. opacity:1;
  272. margin: 5px 0;
  273. }
  274. .demandLayout {
  275. display: inline-block;
  276. // width: 100px;
  277. margin: 10px 0;
  278. font-size:12px;
  279. line-height:14px;
  280. color:rgba(102,102,102,1);
  281. opacity:1;
  282. }
  283. .demandeta {
  284. font-size:12px;
  285. font-family:MicrosoftYaHei;
  286. line-height:14px;
  287. color:rgba(51,51,51,1);
  288. opacity:1;
  289. }
  290. .iconEdit {
  291. width:67px;
  292. background:rgba(245,245,245,1);
  293. opacity:1;
  294. padding: 0 10px;
  295. border-radius:20px;
  296. display: flex;
  297. justify-content: space-between;
  298. }
  299. .tableHeader {
  300. >>> .el-table__empty-block{
  301. display: none;
  302. }
  303. }
  304. .iconPadding {
  305. margin-right: 5px;
  306. }
  307. .schedule-list {
  308. /deep/ .el-table td {
  309. padding: 0;
  310. }
  311. }
  312. .schedule-list {
  313. margin: 0 20px;
  314. padding: 0;
  315. }
  316. >>>.el-table, .el-table__expanded-cell{
  317. background:rgba(248,248,248,0.6);
  318. }
  319. .el-involveApp {
  320. border:1px solid rgba(64,158,255,1);
  321. border-radius:20px;
  322. font-size:10px;
  323. font-family:MicrosoftYaHei;
  324. line-height:12px;
  325. padding: 0 5px;
  326. margin-left: 5px;
  327. color:rgba(64,158,255,1);
  328. opacity:1;
  329. }
  330. .endCheck {
  331. font-size:14px;
  332. font-family:Microsoft Sans Serif;
  333. font-weight:400;
  334. line-height:16px;
  335. margin-right: 10px;
  336. color:rgba(102,102,102,1);
  337. opacity:1;
  338. }
  339. </style>
  340. <style>
  341. .cell-grey .cell {
  342. padding: 0 !important;
  343. }
  344. .el-tooltip__popper.is-dark {
  345. background:rgba(121,132,150,0.8);
  346. color: #FFF;
  347. }
  348. </style>