123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <template>
  2. <div
  3. class="project-list"
  4. direction="column">
  5. <div v-loading="loading" class="nav-box">
  6. <xr-header
  7. :icon-color="projectColor || '#4AB8B8'"
  8. class="xr-header"
  9. icon-class="wk wk-project">
  10. <span slot="label">{{ projectName }}</span>
  11. <el-popover
  12. v-if="showSet"
  13. slot="label"
  14. v-model="projectHandleShow"
  15. placement="bottom-start"
  16. width="182">
  17. <div class="project-list-popover-btn-list">
  18. <members-dep
  19. :user-checked-data="membersList"
  20. :close-dep="true"
  21. @popoverSubmit="userSelectChange">
  22. <p
  23. v-if="permission.setTaskOwnerUser && projectData.is_open != 1 && permission.setWork"
  24. slot="membersDep"
  25. @click="projectHandleShow = false">添加项目成员</p>
  26. </members-dep>
  27. <project-settings
  28. v-if="permission.setWork"
  29. :work-id="work_id"
  30. :title="projectName"
  31. :color="projectColor"
  32. :is-open="projectData.is_open"
  33. :add-members-data="membersList"
  34. :permission="permission"
  35. @close="projectHandleShow = false"
  36. @submite="setSubmite"
  37. @handle="projectSettingsHandle"
  38. @click="projectHandleShow = false"/>
  39. <p v-if="permission.excelImport" @click="taskImportShow = true">导入任务</p>
  40. <p v-if="permission.excelExport" @click="exportClick">导出任务</p>
  41. <p
  42. v-if="permission.archiveTask && permission.setWork"
  43. @click="archiveProject">归档项目</p>
  44. <p
  45. v-if="permission.deleteTask && permission.setWork"
  46. @click="deleteProject">删除项目</p>
  47. <p v-if="projectData.is_open == 0" @click="exitProject">退出项目</p>
  48. </div>
  49. <i
  50. slot="reference"
  51. class="wk wk-manage set-img" />
  52. </el-popover>
  53. <!-- 人员列表 -->
  54. <i
  55. slot="ft"
  56. class="wk wk-s-seas ft-img"
  57. @click="membersShow = true" />
  58. <span
  59. v-show="screeningButtonShow"
  60. slot="ft"
  61. class="ft-btn"
  62. @click="screeningShow = true">
  63. <i class="wk wk-screening ft-img" />
  64. <span class="ft-label">任务筛选</span>
  65. </span>
  66. <!-- 筛选 -->
  67. </xr-header>
  68. <div class="nav">
  69. <el-tabs
  70. v-model="activeName"
  71. @tab-click="tabClick">
  72. <el-tab-pane
  73. name="task-board">
  74. <el-dropdown slot="label" trigger="click" @command="tabShowType = $event">
  75. <span class="el-dropdown-link" >
  76. {{ tabShowType | showTypeName }}<i class="el-icon-arrow-down el-icon--right"/>
  77. </span>
  78. <el-dropdown-menu slot="dropdown">
  79. <el-dropdown-item command="board">看板视图</el-dropdown-item>
  80. <el-dropdown-item command="list">列表视图</el-dropdown-item>
  81. <el-dropdown-item command="user">负责人视图</el-dropdown-item>
  82. </el-dropdown-menu>
  83. </el-dropdown>
  84. </el-tab-pane>
  85. <el-tab-pane
  86. label="附件"
  87. name="attachment"/>
  88. <el-tab-pane
  89. label="任务统计"
  90. name="task-statistical"/>
  91. <el-tab-pane
  92. label="归档任务"
  93. name="archiving-task"/>
  94. </el-tabs>
  95. </div>
  96. </div>
  97. <div class="content">
  98. <keep-alive>
  99. <component
  100. :is="showComponent"
  101. :condition-data="taskConditionObj"
  102. :work-id="work_id"
  103. :show-type="tabShowType"
  104. :permission="permission"/>
  105. </keep-alive>
  106. </div>
  107. <!-- 筛选 -->
  108. <task-screening
  109. v-if="screeningShow"
  110. :work-id="work_id"
  111. :data="taskConditionObj"
  112. @change="taskScreeningChange"
  113. @close="screeningShow = false"/>
  114. <!-- 人员列表 -->
  115. <members
  116. :work-id="work_id"
  117. :list="membersList"
  118. :is-open="projectData.is_open"
  119. :permission="permission"
  120. :visible.sync="membersShow"
  121. @handle="membersHandle"/>
  122. <!-- 任务导入 -->
  123. <task-import
  124. :work-id="work_id"
  125. :show.sync="taskImportShow"
  126. @success="taskImportSuccess"
  127. />
  128. </div>
  129. </template>
  130. <script>
  131. import {
  132. workWorkReadAPI,
  133. workWorkDeleteAPI,
  134. workWorkLeaveAPI,
  135. workWorkOwnerListAPI,
  136. workTaskExportAPI,
  137. workWorkArchiveAPI,
  138. workWorkAddUserGroupAPI
  139. } from '@/api/pm/project'
  140. import TaskBoard from './components/TaskBoard'
  141. import TaskListBoard from './components/TaskListBoard'
  142. import Attachment from './components/Attachment'
  143. import TaskStatistical from './components/TaskStatistical'
  144. import ArchivingTask from './components/ArchivingTask'
  145. import ProjectSettings from './components/ProjectSettings'
  146. import TaskScreening from './components/TaskScreening'
  147. import Members from './components/Members'
  148. import TaskImport from '../components/TaskImport' // 任务导入
  149. import MembersDep from '@/components/SelectEmployee/MembersDep'
  150. import XrHeader from '@/components/XrHeader'
  151. import { downloadExcelWithResData } from '@/utils'
  152. export default {
  153. components: {
  154. TaskBoard,
  155. TaskListBoard,
  156. Attachment,
  157. TaskStatistical,
  158. ArchivingTask,
  159. ProjectSettings,
  160. TaskScreening,
  161. Members,
  162. TaskImport,
  163. MembersDep,
  164. XrHeader
  165. },
  166. filters: {
  167. showTypeName(value) {
  168. return {
  169. board: '看板视图',
  170. list: '列表视图',
  171. user: '负责人视图'
  172. }[value]
  173. }
  174. },
  175. data() {
  176. return {
  177. // 项目ID
  178. loading: false,
  179. tabShowType: 'board',
  180. work_id: '',
  181. projectName: '',
  182. projectColor: '',
  183. projectData: {
  184. is_open: 0
  185. },
  186. taskConditionObj: {
  187. userIds: [],
  188. timeId: '',
  189. tagIds: []
  190. },
  191. activeName: 'task-board',
  192. // 项目设置
  193. projectHandleShow: false,
  194. // 人员列表
  195. membersShow: false,
  196. membersList: [],
  197. // 是否显示筛选
  198. screeningButtonShow: true,
  199. screeningShow: false,
  200. // 任务导入展示
  201. taskImportShow: false,
  202. // 权限
  203. permission: {}
  204. }
  205. },
  206. computed: {
  207. // 展示项目设置按钮
  208. showSet() {
  209. return (this.permission.setTaskOwnerUser && this.projectData.is_open != 1) ||
  210. this.permission.setWork ||
  211. this.permission.excelImport ||
  212. this.permission.excelExport ||
  213. this.permission.archiveTask ||
  214. this.permission.deleteTask ||
  215. this.projectData.is_open == 0
  216. },
  217. // tabs 下内容视图的组件
  218. showComponent() {
  219. if (this.activeName == 'task-board') {
  220. if (this.tabShowType == 'list') {
  221. return 'TaskListBoard'
  222. }
  223. return this.activeName
  224. }
  225. return this.activeName
  226. }
  227. },
  228. beforeRouteUpdate(to, from, next) {
  229. this.work_id = to.params.id
  230. this.membersShow = false
  231. this.screeningShow = false
  232. this.getDetail()
  233. this.getMemberList()
  234. next()
  235. },
  236. created() {
  237. this.activeName = 'task-board'
  238. // 当页面刷新时重新获取路由信息
  239. this.work_id = this.$route.params.id
  240. this.getDetail()
  241. this.getMemberList()
  242. },
  243. methods: {
  244. /**
  245. * 获取项目详情
  246. */
  247. getDetail() {
  248. workWorkReadAPI({
  249. work_id: this.work_id
  250. })
  251. .then(res => {
  252. const data = res.data
  253. this.projectData = data
  254. this.projectColor = data.color
  255. this.projectName = data.name
  256. this.permission = data.auth || {}
  257. })
  258. .catch(() => { })
  259. },
  260. tabClick(val) {
  261. this.screeningButtonShow = this.activeName == 'task-board'
  262. },
  263. /**
  264. * 获取列表
  265. */
  266. getMemberList() {
  267. workWorkOwnerListAPI({
  268. work_id: this.work_id
  269. })
  270. .then(res => {
  271. this.membersList = res.data || []
  272. this.$bus.$emit('members-update', this.membersList)
  273. })
  274. .catch(() => {})
  275. },
  276. /**
  277. * 编辑成员
  278. */
  279. userSelectChange(members, dep) {
  280. workWorkAddUserGroupAPI({
  281. work_id: this.work_id,
  282. owner_user_id: members.map(item => item.id)
  283. })
  284. .then(res => {
  285. this.membersList = res.data || []
  286. this.$bus.$emit('members-update', this.membersList)
  287. this.$message.success('添加成功')
  288. })
  289. .catch(() => {})
  290. },
  291. /**
  292. * 删除项目
  293. */
  294. deleteProject() {
  295. this.$confirm(
  296. '确定要删除项目吗?删除后此项目中的所有任务将一并彻底删除,无法恢复',
  297. '提示',
  298. {
  299. confirmButtonText: '确定',
  300. cancelButtonText: '取消',
  301. type: 'warning'
  302. }
  303. )
  304. .then(() => {
  305. workWorkDeleteAPI({ work_id: this.work_id })
  306. .then(res => {
  307. this.$message({
  308. type: 'success',
  309. message: '删除成功!'
  310. })
  311. this.$bus.$emit('delete-project', this.work_id)
  312. this.$router.go(-1)
  313. })
  314. .catch(() => {})
  315. })
  316. .catch(() => {
  317. this.$message({
  318. type: 'info',
  319. message: '已取消删除'
  320. })
  321. })
  322. },
  323. /**
  324. * 退出项目
  325. */
  326. exitProject() {
  327. this.$confirm('确认退出' + ' "' + this.projectName + '"', '提示', {
  328. confirmButtonText: '确定',
  329. cancelButtonText: '取消',
  330. type: 'warning'
  331. })
  332. .then(() => {
  333. workWorkLeaveAPI({ work_id: this.work_id })
  334. .then(res => {
  335. this.$message({
  336. type: 'success',
  337. message: '退出成功!'
  338. })
  339. this.$bus.$emit('delete-project', this.work_id)
  340. })
  341. .catch(() => {
  342. })
  343. })
  344. .catch(() => {
  345. this.$message({
  346. type: 'info',
  347. message: '取消操作'
  348. })
  349. })
  350. },
  351. /**
  352. * 归档项目
  353. */
  354. archiveProject() {
  355. this.$confirm('确认归档项目' + ' "' + this.projectName + '"', '提示', {
  356. confirmButtonText: '确定',
  357. cancelButtonText: '取消',
  358. type: 'warning'
  359. })
  360. .then(() => {
  361. workWorkArchiveAPI({ work_id: this.work_id, status: 3 }) // 状态 1启用 2 删除 3归档
  362. .then(res => {
  363. this.$message({
  364. type: 'success',
  365. message: '归档成功'
  366. })
  367. this.$bus.$emit('delete-project', this.work_id)
  368. this.$router.go(-1)
  369. })
  370. .catch(() => {})
  371. })
  372. .catch(() => {
  373. this.$message({
  374. type: 'info',
  375. message: '取消操作'
  376. })
  377. })
  378. },
  379. /**
  380. * 项目设置更新数据
  381. */
  382. setSubmite(name, color, is_open) {
  383. if (this.projectData.is_open != is_open) {
  384. this.getDetail()
  385. this.getMemberList()
  386. } else {
  387. this.projectColor = color
  388. this.projectName = name
  389. this.$bus.$emit('project-setting', name, this.work_id)
  390. }
  391. },
  392. /**
  393. * 项目设置
  394. */
  395. projectSettingsHandle(type, data) {
  396. if (type == 'member') {
  397. this.getMemberList()
  398. }
  399. },
  400. /**
  401. * 成员设置
  402. */
  403. membersHandle(type, data) {
  404. if (type == 'member') {
  405. this.$bus.$emit('members-update', data)
  406. this.membersList = data
  407. }
  408. },
  409. /**
  410. * 审批导出
  411. */
  412. exportClick() {
  413. this.projectHandleShow = false
  414. this.loading = true
  415. workTaskExportAPI({
  416. work_id: this.work_id,
  417. search: this.taskConditionObj.search,
  418. owner_user_id: this.taskConditionObj.userIds,
  419. time_type: this.taskConditionObj.timeId,
  420. label_id: this.taskConditionObj.tagIds
  421. })
  422. .then(res => {
  423. downloadExcelWithResData(res)
  424. this.loading = false
  425. })
  426. .catch(() => {
  427. this.loading = false
  428. })
  429. },
  430. /**
  431. * 任务导入成功
  432. */
  433. taskImportSuccess() {
  434. this.$bus.$emit('work-task-import')
  435. },
  436. /**
  437. * 任务筛选
  438. */
  439. taskScreeningChange(userIds, timeId, tagIds, search) {
  440. this.taskConditionObj = {
  441. userIds,
  442. timeId,
  443. tagIds,
  444. search
  445. }
  446. }
  447. }
  448. }
  449. </script>
  450. <style scoped lang="scss">
  451. .project-list {
  452. height: 100%;
  453. overflow: hidden;
  454. .nav-box {
  455. margin-bottom: 15px;
  456. background: #fff;
  457. border-radius: $xr-border-radius-base;
  458. border: 1px solid $xr-border-color-base;
  459. .xr-header {
  460. padding: 10px 15px;
  461. }
  462. .ft-img {
  463. color: #999;
  464. cursor: pointer;
  465. }
  466. .ft-btn {
  467. margin-left: 25px;
  468. color: #999;
  469. cursor: pointer;
  470. .ft-img {
  471. margin-right: 2px;
  472. }
  473. .ft-label {
  474. font-size: 12px;
  475. }
  476. }
  477. .set-img {
  478. margin-left: 15px;
  479. font-size: 14px;
  480. color: #ccc;
  481. cursor: pointer;
  482. }
  483. .ft-btn:hover {
  484. color: $xr-color-primary;
  485. .ft-img {
  486. color: $xr-color-primary;
  487. }
  488. }
  489. .ft-img:hover,
  490. .set-img:hover {
  491. color: $xr-color-primary;
  492. }
  493. .nav {
  494. margin-left: 64px;
  495. .el-tabs /deep/ .el-tabs__header {
  496. margin-bottom: 0;
  497. .el-tabs__nav-wrap::after {
  498. height: 0;
  499. }
  500. }
  501. }
  502. }
  503. .content {
  504. height: calc(100% - 105px);
  505. overflow-y: auto;
  506. position: relative;
  507. }
  508. }
  509. // 设置
  510. .project-list-popover-btn-list {
  511. margin: 0 -12px;
  512. p {
  513. height: 40px;
  514. line-height: 40px;
  515. cursor: pointer;
  516. padding-left: 32px;
  517. }
  518. p:hover {
  519. background: #f7f8fa;
  520. color: #2362FB;
  521. }
  522. }
  523. .slide-fade-enter-active,
  524. .slide-fade-leave-active {
  525. will-change: transform;
  526. transition: all 0.35s ease;
  527. }
  528. .slide-fade-enter,
  529. .slide-fade-leave-to {
  530. transform: translateX(100%);
  531. }
  532. // 项目图
  533. .wukong-subproject {
  534. font-size: 27px;
  535. margin-right: 8px;
  536. }
  537. </style>