all.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. <template>
  2. <div class="user-management-container">
  3. <div class="side-layout">
  4. <div class="tree-side">
  5. <span class="type">操作类型</span>
  6. <div
  7. :style="{
  8. color: queryForm.overdueDays != '' ? '#999999' : '#1D66DC',
  9. 'margin-top': '20px',
  10. cursor: 'pointer',
  11. }"
  12. @click="search('')">
  13. <i class="el-icon-message-solid" style="margin-right: 10px"></i>
  14. 全部督办
  15. </div>
  16. <div
  17. :style="{
  18. color: queryForm.overdueDays != '1' ? '#999999' : '#1D66DC',
  19. 'margin-top': '20px',
  20. cursor: 'pointer',
  21. }"
  22. @click="search('1')">
  23. <i class="el-icon-video-play" style="margin-right: 10px"></i>
  24. 超期1天
  25. </div>
  26. <div
  27. :style="{
  28. color: queryForm.overdueDays != '3' ? '#999999' : '#1D66DC',
  29. 'margin-top': '20px',
  30. cursor: 'pointer',
  31. }"
  32. @click="search('3')">
  33. <i class="el-icon-folder-checked" style="margin-right: 10px"></i>
  34. 超期3天
  35. </div>
  36. <div
  37. :style="{
  38. color: queryForm.overdueDays != '5' ? '#999999' : '#1D66DC',
  39. 'margin-top': '20px',
  40. cursor: 'pointer',
  41. }"
  42. @click="search('5')">
  43. <i class="el-icon-warning-outline" style="margin-right: 10px"></i>
  44. 超期5天
  45. </div>
  46. <div
  47. :style="{
  48. color: queryForm.overdueDays != '>5' ? '#999999' : '#1D66DC',
  49. 'margin-top': '20px',
  50. cursor: 'pointer',
  51. }"
  52. @click="search('>5')">
  53. <i class="el-icon-remove-outline" style="margin-right: 10px"></i>
  54. 超期5天以上
  55. </div>
  56. </div>
  57. <div class="tree-table">
  58. <vab-query-form>
  59. <vab-query-form-top-panel>
  60. <el-form :inline="true" :model="queryForm" @submit.native.prevent>
  61. <el-form-item label="负责人">
  62. <el-select
  63. v-model="queryForm.mainUserId"
  64. clearable
  65. filterable
  66. placeholder="请选择负责人"
  67. @keyup.enter.native="queryData">
  68. <el-option v-for="user in users" :key="user.id" :label="user.nickName" :value="user.id" />
  69. </el-select>
  70. </el-form-item>
  71. <el-form-item label="督办人">
  72. <el-select
  73. v-model="queryForm.supervisorUserId"
  74. clearable
  75. filterable
  76. placeholder="请选择督办人"
  77. @keyup.enter.native="queryData">
  78. <el-option v-for="user in users" :key="user.id" :label="user.nickName" :value="user.id" />
  79. </el-select>
  80. </el-form-item>
  81. <el-form-item label="发起人">
  82. <el-select
  83. v-model="queryForm.createdById"
  84. clearable
  85. filterable
  86. placeholder="请选择发起人"
  87. @keyup.enter.native="queryData">
  88. <el-option v-for="user in users" :key="user.id" :label="user.nickName" :value="user.id" />
  89. </el-select>
  90. </el-form-item>
  91. <el-form-item>
  92. <el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
  93. <el-button icon="el-icon-refresh-right" @click="reset">重置</el-button>
  94. </el-form-item>
  95. </el-form>
  96. </vab-query-form-top-panel>
  97. <vab-query-form-left-panel :span="12">
  98. <el-button v-permissions="['plat:task:add']" icon="el-icon-plus" type="primary" @click="handleAdd">
  99. 添加
  100. </el-button>
  101. </vab-query-form-left-panel>
  102. <vab-query-form-right-panel :span="12">
  103. <!-- <el-button icon="el-icon-download" @click="exportData" /> -->
  104. <table-tool :columns="columns" :show-columns.sync="showColumns" table-type="taskTable" />
  105. </vab-query-form-right-panel>
  106. </vab-query-form>
  107. <!-- 主页面 -->
  108. <el-table
  109. ref="table"
  110. v-loading="listLoading"
  111. border
  112. :data="list"
  113. :height="height"
  114. :row-class-name="tableRowClassName"
  115. width="100%">
  116. <el-table-column
  117. v-for="(item, index) in showColumns"
  118. :key="index"
  119. align="center"
  120. :label="item.label"
  121. :prop="item.prop"
  122. show-overflow-tooltip
  123. :sortable="item.sortable"
  124. :width="item.width">
  125. <template #default="{ row }">
  126. <el-button v-if="item.prop === 'taskTitle'" class="link-button" type="text" @click="showDetail(row)">
  127. {{ row.taskTitle }}
  128. </el-button>
  129. <span v-else-if="item.prop === 'taskType'">
  130. {{ typeMap[row.taskType] }}
  131. </span>
  132. <span v-else-if="item.prop === 'source'">
  133. {{ selectDictLabel(sourceOptions, row.source) }}
  134. </span>
  135. <span v-else-if="item.prop === 'taskStatus'">
  136. <span v-if="row.taskStatus === '10'">发起</span>
  137. <span v-if="row.taskStatus === '20'">进行中</span>
  138. <span v-if="row.taskStatus === '30'">流程完成</span>
  139. <span v-if="row.taskStatus === '40'">审批拒绝</span>
  140. <span v-if="row.taskStatus === '50'">撤销</span>
  141. </span>
  142. <span v-else-if="item.prop === 'isOverdue'">
  143. {{ isNotOverdue(parseTime(row['taskEndDate'], '{y}-{m}-{d} 23:59:59'), row) ? '否' : '是' }}
  144. </span>
  145. <span
  146. v-else-if="
  147. item.prop === 'mainUserId' || item.prop === 'supervisorUserId' || item.prop === 'watchUserId'
  148. ">
  149. {{ userMap[row[item.prop]] }}
  150. </span>
  151. <span v-else-if="item.prop === 'ownerUserId'">
  152. {{ generateTeamMembers(row[item.prop]) }}
  153. </span>
  154. <span
  155. v-else-if="item.prop === 'taskStartDate' || item.prop === 'taskEndDate' || item.prop === 'createdTime'">
  156. {{ parseTime(row[item.prop], '{y}-{m}-{d}') }}
  157. </span>
  158. <span v-else>{{ row[item.prop] }}</span>
  159. </template>
  160. </el-table-column>
  161. <template #empty>
  162. <el-image class="vab-data-empty" :src="require('@/assets/empty_images/data_empty.png')" />
  163. </template>
  164. </el-table>
  165. <el-pagination
  166. background
  167. :current-page="queryForm.pageNum"
  168. :layout="layout"
  169. :page-size="queryForm.pageSize"
  170. :total="total"
  171. @current-change="handleCurrentChange"
  172. @size-change="handleSizeChange" />
  173. </div>
  174. </div>
  175. <!-- 新建督办 -->
  176. <taskAdd ref="taskAdd" :do-refresh="doRefresh" :types="types" :users="users" />
  177. <!-- 查看详情 -->
  178. <taskDetail
  179. :do-refresh="doRefresh"
  180. :self-visible.sync="detailDialogVisible"
  181. :the-task="theTask"
  182. :type-map="typeMap"
  183. :user-map="userMap" />
  184. </div>
  185. </template>
  186. <script>
  187. import taskApi from '@/api/plat/task'
  188. import userApi from '@/api/system/user'
  189. import dictApi from '@/api/system/dict'
  190. import taskAdd from './components/TaskAdd.vue'
  191. import taskDetail from './components/TaskDetail.vue'
  192. import TableTool from '@/components/table/TableTool'
  193. import downloadFileByByte from '@/utils/base64ToFile'
  194. export default {
  195. name: 'AllTask',
  196. components: { taskAdd, taskDetail, TableTool },
  197. data() {
  198. return {
  199. // 判断当前督办是否可以进行操作
  200. taskMap: {},
  201. height: this.$baseTableHeight(2),
  202. // 各督办数量统计
  203. statisticsForm: {
  204. toDoNumber: 0,
  205. createNumber: 0,
  206. completedNumber: 0,
  207. },
  208. // 督办详情查看
  209. detailDialogVisible: false,
  210. // 新建弹窗控制
  211. addDialogVisible: false,
  212. // 展示的督办数据
  213. theTask: {},
  214. list: [],
  215. listLoading: true,
  216. layout: 'total, sizes, prev, pager, next, jumper',
  217. total: 0,
  218. queryForm: {
  219. pageNum: 1,
  220. pageSize: 10,
  221. taskTitle: undefined,
  222. source: '',
  223. operateType: '5',
  224. overdueDays: '',
  225. isOverdue: '',
  226. mainUserId: '',
  227. supervisorUserId: '',
  228. createdById: '',
  229. },
  230. // 用户信息
  231. userMap: {},
  232. users: [],
  233. // 类型信息
  234. typeMap: {},
  235. types: [],
  236. sourceOptions: [],
  237. // 自定义列表
  238. showColumns: [],
  239. columns: [
  240. {
  241. label: '督办标题',
  242. width: '280px',
  243. prop: 'taskTitle',
  244. sortable: false,
  245. disableCheck: true,
  246. },
  247. {
  248. label: '督办内容',
  249. width: '320px',
  250. prop: 'taskDesc',
  251. sortable: false,
  252. },
  253. // {
  254. // label: '督办类型',
  255. // width: '120px',
  256. // prop: 'taskType',
  257. // sortable: false,
  258. // },
  259. {
  260. label: '状态',
  261. width: '120px',
  262. prop: 'taskStatus',
  263. sortable: false,
  264. },
  265. // {
  266. // label: '事项来源',
  267. // width: '120px',
  268. // prop: 'source',
  269. // sortable: false,
  270. // },
  271. {
  272. label: '负责人',
  273. width: '120px',
  274. prop: 'mainUserId',
  275. sortable: false,
  276. },
  277. {
  278. label: '协办人',
  279. width: '180px',
  280. prop: 'ownerUserId',
  281. sortable: false,
  282. },
  283. {
  284. label: '督办人',
  285. width: '120px',
  286. prop: 'supervisorUserId',
  287. sortable: false,
  288. },
  289. {
  290. label: '监办人',
  291. width: '120px',
  292. prop: 'watchUserId',
  293. sortable: false,
  294. },
  295. {
  296. label: '发布时间',
  297. width: '120px',
  298. prop: 'taskStartDate',
  299. sortable: false,
  300. },
  301. {
  302. label: '要求完成时间',
  303. width: '120px',
  304. prop: 'taskEndDate',
  305. sortable: false,
  306. },
  307. {
  308. label: '提醒规则',
  309. width: '200px',
  310. prop: 'reminderRuleInfo',
  311. sortable: false,
  312. },
  313. // {
  314. // label: '创建时间',
  315. // width: '160px',
  316. // prop: 'createdTime',
  317. // sortable: false,
  318. // },
  319. {
  320. label: '是否超期',
  321. width: '120px',
  322. prop: 'isOverdue',
  323. sortable: false,
  324. },
  325. ],
  326. }
  327. },
  328. watch: {
  329. showColumns: function () {
  330. this.$nextTick(() => this.$refs.table.doLayout())
  331. },
  332. },
  333. async created() {
  334. if (this.$route.params.isOverdue) {
  335. this.queryForm.isOverdue = this.$route.params.isOverdue
  336. }
  337. this.queryForm.operateType = '5'
  338. this.statistics()
  339. await this.initData()
  340. this.fetchData()
  341. },
  342. activated() {
  343. if (this.$route.params.isOverdue) {
  344. this.queryForm.isOverdue = this.$route.params.isOverdue
  345. this.queryForm.operateType = '5'
  346. }
  347. this.statistics()
  348. this.fetchData()
  349. },
  350. methods: {
  351. // 获取我的待办
  352. async getMyTasks() {
  353. await taskApi
  354. .getTaskList({ pageNum: 1, pageSize: 9999, operateType: '1' })
  355. .then((res) => {
  356. if (res.data.list) {
  357. for (let item of res.data.list) {
  358. this.taskMap[item.id] = item
  359. }
  360. }
  361. })
  362. .catch((err) => {
  363. console.error(err)
  364. })
  365. },
  366. // 单元格样式控制
  367. tableRowClassName({ row, rowIndex }) {
  368. if (this.taskMap[row.id]) {
  369. return 'warning-row'
  370. }
  371. return ''
  372. },
  373. // 接收任务
  374. receiveTask(task) {
  375. this.$confirm('确定接收该督办?', '提示', {
  376. confirmButtonText: '确定',
  377. cancelButtonText: '取消',
  378. type: 'warning',
  379. }).then(async () => {
  380. let data = {
  381. taskId: task.id,
  382. step: 10,
  383. handleStatus: '10',
  384. }
  385. const { msg } = await taskApi.handleTask(data)
  386. this.$baseMessage(msg, 'success', 'vab-hey-message-success')
  387. this.doRefresh()
  388. })
  389. },
  390. // 判断是否没有超期
  391. isNotOverdue(date, row) {
  392. return new Date() <= new Date(date) || (row.taskStatus != '10' && row.taskStatus != '20')
  393. },
  394. // 刷新表数据和数量统计
  395. doRefresh() {
  396. this.fetchData()
  397. this.statistics()
  398. },
  399. // 统计各类型督办数量
  400. statistics() {
  401. taskApi
  402. .statisticsTaskNumber()
  403. .then((res) => {
  404. if (res.data.list) {
  405. this.statisticsForm = res.data.list
  406. }
  407. })
  408. .catch((err) => {
  409. console.error(err)
  410. })
  411. },
  412. // 数据导出
  413. exportData() {
  414. let exportFrom = JSON.parse(JSON.stringify(this.queryForm))
  415. exportFrom.columns = this.showColumns.map((item) => item.label)
  416. taskApi
  417. .exportTasks(exportFrom)
  418. .then((res) => {
  419. if (res.data.list.content) {
  420. downloadFileByByte(res.data.list.content, '督办数据.xlsx')
  421. }
  422. })
  423. .catch((err) => {
  424. console.error(err)
  425. })
  426. },
  427. // 重置查询数据
  428. reset() {
  429. this.queryForm.pageNum = 1
  430. this.queryForm.pageSize = 10
  431. this.queryForm.taskTitle = undefined
  432. this.queryForm.isOverdue = ''
  433. this.queryForm.operateType = '5'
  434. this.queryForm.overdueDays = ''
  435. this.queryForm.source = ''
  436. this.queryForm.mainUserId = ''
  437. this.queryForm.supervisorUserId = ''
  438. this.queryForm.createdById = ''
  439. this.queryData()
  440. },
  441. // 左侧操作栏搜索
  442. search(type) {
  443. this.queryForm.overdueDays = type
  444. this.queryData()
  445. },
  446. // 事项来源搜索
  447. searchSource(source) {
  448. this.queryForm.source = source
  449. this.queryData()
  450. },
  451. // 初始化数据
  452. async initData() {
  453. await dictApi
  454. .getDictDataList({ dictType: 'task_type', pageNum: 1, pageSize: 9999 })
  455. .then((res) => {
  456. if (res.data.list) {
  457. this.types = res.data.list
  458. for (let type of this.types) {
  459. this.typeMap[type.dictValue] = type.dictLabel
  460. }
  461. }
  462. })
  463. .catch((err) => {
  464. console.error(err)
  465. })
  466. await userApi
  467. .getList({ pageNum: 1, pageSize: 9999 })
  468. .then((res) => {
  469. if (res.data.list) {
  470. this.users = res.data.list
  471. for (let user of this.users) {
  472. this.userMap[user.id] = user.nickName
  473. }
  474. }
  475. })
  476. .catch((err) => {
  477. console.error(err)
  478. })
  479. this.getDicts('plat_task_source').then((response) => {
  480. this.sourceOptions = response.data.values || []
  481. })
  482. await this.getMyTasks()
  483. },
  484. // 显示详情数据
  485. showDetail(row) {
  486. if (this.taskMap[row.id]) {
  487. this.$store.state.task.theTask = { ...this.taskMap[row.id] }
  488. } else {
  489. this.$store.state.task.theTask = { ...row }
  490. }
  491. this.$router.push({
  492. path: '/plat/task/detail',
  493. query: {
  494. type: this.taskMap[row.id] ? '1' : '5',
  495. pageType: '5',
  496. },
  497. })
  498. },
  499. // 处理新增
  500. handleAdd() {
  501. // this.addDialogVisible = true
  502. this.$refs.taskAdd.selfVisible = true
  503. },
  504. // 更换页数据大小
  505. handleSizeChange(val) {
  506. this.queryForm.pageSize = val
  507. this.fetchData()
  508. },
  509. // 更换当前页
  510. handleCurrentChange(val) {
  511. this.queryForm.pageNum = val
  512. this.fetchData()
  513. },
  514. // 查询
  515. queryData() {
  516. this.queryForm.pageNum = 1
  517. this.fetchData()
  518. },
  519. // 获取数据
  520. fetchData() {
  521. this.listLoading = true
  522. let params = JSON.parse(JSON.stringify(this.queryForm))
  523. params.mainUserId += ''
  524. params.supervisorUserId += ''
  525. params.createdById += ''
  526. this.list = []
  527. taskApi
  528. .getTaskList(params)
  529. .then((res) => {
  530. if (res.data.list) {
  531. for (let item of res.data.list) {
  532. if (item.reminderRule == '') {
  533. item.reminderRuleInfo = '不提醒'
  534. } else {
  535. let rules = item.reminderRule.split(' ')
  536. if (rules[3] == '*') {
  537. item.reminderRuleInfo = '每天在' + rules[2] + ':' + rules[1] + ':' + rules[0] + '提醒'
  538. } else if (rules[3] == '?') {
  539. item.reminderRuleInfo =
  540. '每周周' + rules[4] + '在' + rules[2] + ':' + rules[1] + ':' + rules[0] + '提醒'
  541. } else {
  542. item.reminderRuleInfo =
  543. '每月' + rules[3] + '日在' + rules[2] + ':' + rules[1] + ':' + rules[0] + '提醒'
  544. }
  545. }
  546. }
  547. this.list = res.data.list
  548. }
  549. this.total = res.data.total
  550. this.listLoading = false
  551. this.$nextTick(() => this.$refs.table.doLayout())
  552. })
  553. .catch((err) => {
  554. this.listLoading = false
  555. console.error(err)
  556. })
  557. },
  558. // 协办人
  559. generateTeamMembers(ids) {
  560. if (!ids) {
  561. return ''
  562. } else {
  563. let names = ''
  564. let idArray = ids.split(',')
  565. for (let id of idArray) {
  566. if (names == '') {
  567. names = this.userMap[parseInt(id)]
  568. } else {
  569. names += ',' + this.userMap[parseInt(id)]
  570. }
  571. }
  572. return names
  573. }
  574. },
  575. },
  576. }
  577. </script>
  578. <style lang="scss" scoped>
  579. .type {
  580. font-weight: bold;
  581. }
  582. $base: '.list';
  583. .link-button {
  584. font-size: 14px;
  585. width: 100%;
  586. overflow: hidden;
  587. text-overflow: ellipsis;
  588. white-space: nowrap;
  589. }
  590. ::v-deep .el-table .warning-row {
  591. background: oldlace;
  592. }
  593. ::v-deep .el-table .danger-row {
  594. background: #f56c6c;
  595. }
  596. </style>