detail.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. <!--
  2. * @Author: wanglj 471442253@qq.com
  3. * @Date: 2023-01-10 13:41:07
  4. * @LastEditors: wanglj
  5. * @LastEditTime: 2023-01-10 18:00:55
  6. * @Description: file content
  7. * @FilePath: \opms_frontend\src\views\plat\task\detail.vue
  8. -->
  9. <template>
  10. <div class="detail">
  11. <el-row :gutter="10">
  12. <el-col :span="16">
  13. <div class="title">
  14. <p>督办详情</p>
  15. <h3>
  16. {{ theTask.taskTitle }}
  17. <span></span>
  18. </h3>
  19. </div>
  20. <header>
  21. <el-descriptions :colon="false" :column="6" direction="vertical">
  22. <el-descriptions-item content-class-name="my-content" label="督办类型" label-class-name="my-label">
  23. {{ typeMap[theTask.taskType] }}
  24. </el-descriptions-item>
  25. <el-descriptions-item content-class-name="my-content" label="状态" label-class-name="my-label">
  26. <span v-if="theTask.taskStatus === '10'">发起</span>
  27. <span v-else-if="theTask.taskStatus === '20'">进行中</span>
  28. <span v-else-if="theTask.taskStatus === '30'">流程完成</span>
  29. </el-descriptions-item>
  30. <el-descriptions-item content-class-name="my-content" label="超期" label-class-name="my-label">
  31. {{ isNotOverdue(parseTime(theTask.taskEndDate, '{y}-{m}-{d} 23:59:59')) ? '否' : '是' }}
  32. </el-descriptions-item>
  33. <el-descriptions-item content-class-name="my-content" label="发布时间" label-class-name="my-label">
  34. {{ parseTime(theTask.taskStartDate, '{y}-{m}-{d}') }}
  35. </el-descriptions-item>
  36. <el-descriptions-item content-class-name="my-content" label="要求完成时间" label-class-name="my-label">
  37. {{ parseTime(theTask.taskEndDate, '{y}-{m}-{d}') }}
  38. </el-descriptions-item>
  39. <el-descriptions-item content-class-name="my-content" label="督办内容" label-class-name="my-label">
  40. {{ theTask.taskDesc }}
  41. </el-descriptions-item>
  42. </el-descriptions>
  43. <el-descriptions :colon="false" :column="6" direction="vertical">
  44. <el-descriptions-item content-class-name="my-content" label="负责人" label-class-name="my-label">
  45. {{ userMap[theTask.mainUserId] }}
  46. </el-descriptions-item>
  47. <el-descriptions-item content-class-name="my-content" label="协办人" label-class-name="my-label">
  48. {{ teamNames }}
  49. </el-descriptions-item>
  50. <el-descriptions-item content-class-name="my-content" label="督办人" label-class-name="my-label">
  51. {{ userMap[theTask.supervisorUserId] }}
  52. </el-descriptions-item>
  53. <el-descriptions-item content-class-name="my-content" label="监办人" label-class-name="my-label">
  54. {{ userMap[theTask.watchUserId] }}
  55. </el-descriptions-item>
  56. <!-- <el-descriptions-item content-class-name="my-content" label="关联类型" label-class-name="my-label">
  57. <span v-show="theTask.targetType == '10'">客户</span>
  58. <span v-show="theTask.targetType == '20'">项目</span>
  59. <span v-show="theTask.targetType == '30'">合同</span>
  60. <span v-show="theTask.targetType == '40'">回款</span>
  61. </el-descriptions-item> -->
  62. <el-descriptions-item content-class-name="my-content" label="督办事项来源" label-class-name="my-label">
  63. {{ theTask.source }}
  64. </el-descriptions-item>
  65. </el-descriptions>
  66. </header>
  67. <el-form label-width="80px" :model="form" style="margin-top: 10px">
  68. <el-form-item label="进展情况">
  69. <el-button v-show="theTask.step === 20 && type == '1'" circle icon="el-icon-plus" @click="addProgress" />
  70. </el-form-item>
  71. <el-form-item label-width="0">
  72. <el-table border :data="progressList" max-height="300px">
  73. <el-table-column align="center" label="进展说明" prop="progDesc">
  74. <template #default="{ row }">
  75. <span v-if="row.id">{{ row.progDesc }}</span>
  76. <el-input v-else v-model="row.progDesc" placeholder="进展说明" style="width: 100%" />
  77. </template>
  78. </el-table-column>
  79. <el-table-column align="center" label="时间" prop="progDate">
  80. <template #default="{ row }">
  81. <span v-if="row.id">{{ parseTime(row.progDate) }}</span>
  82. <el-date-picker
  83. v-else
  84. v-model="row.progDate"
  85. style="width: 100%"
  86. value-format="yyyy-MM-dd HH:mm:ss" />
  87. </template>
  88. </el-table-column>
  89. <el-table-column align="center" label="附件" prop="progFile">
  90. <template #default="{ row }">
  91. <el-upload action="#" :http-request="uploadrequest" :show-file-list="false">
  92. <el-button
  93. v-permissions="['plat:task:enclosure:add']"
  94. size="mini"
  95. style="margin-left: 10px"
  96. slot="trigger"
  97. type="primary"
  98. @click="showUploadFileDialog(row)">
  99. 上传/更新
  100. </el-button>
  101. <el-button
  102. v-show="row.progFile"
  103. v-permissions="['plat:task:enclosure:look']"
  104. size="mini"
  105. style="margin-left: 10px"
  106. @click="showFile(row.progFile)">
  107. 查看附件
  108. </el-button>
  109. </el-upload>
  110. </template>
  111. </el-table-column>
  112. <el-table-column align="center" label="备注" prop="remark">
  113. <template #default="{ row }">
  114. <span v-if="row.id">{{ row.remark }}</span>
  115. <el-input v-else v-model="row.remark" placeholder="备注" style="width: 100%" />
  116. </template>
  117. </el-table-column>
  118. <el-table-column v-if="theTask.step < 30 && type == 1" align="center" label="操作">
  119. <template #default="{ row }">
  120. <el-button v-permissions="['plat:task:enclosure:delete']" type="text" @click="handleDel(row.$index)">
  121. 删除
  122. </el-button>
  123. </template>
  124. </el-table-column>
  125. </el-table>
  126. </el-form-item>
  127. <el-form-item v-if="theTask.approDate || theTask.step === 30" label="审批意见">
  128. <el-input v-if="theTask.step === 30" v-model="form.approDesc" placeholder="审批意见" />
  129. <span v-else>{{ theTask.approDesc }}</span>
  130. </el-form-item>
  131. <el-form-item v-if="theTask.approDate || theTask.step === 40" label="督办评价">
  132. <el-input v-if="theTask.step === 40" v-model="form.evaluateDesc" placeholder="督办评价" />
  133. <span v-else>{{ theTask.evaluateDesc }}</span>
  134. </el-form-item>
  135. </el-form>
  136. </el-col>
  137. <el-col :span="8">
  138. <div class="buttons">
  139. <el-button
  140. v-show="theTask.taskStatus === '10' && type == 1"
  141. v-permissions="['plat:task:detail:receive']"
  142. type="primary"
  143. @click="changeStatus(10, '10')">
  144. 接收
  145. </el-button>
  146. <el-button
  147. v-show="theTask.taskStatus === '20' && theTask.step === 20 && type == 1"
  148. v-permissions="['plat:task:detail:staging']"
  149. type="success"
  150. @click="changeStatus(15)">
  151. 暂存
  152. </el-button>
  153. <el-button
  154. v-show="theTask.taskStatus === '20' && theTask.step === 20 && type == 1"
  155. v-permissions="['plat:task:detail:submit']"
  156. type="primary"
  157. @click="changeStatus(20, '20')">
  158. 提交
  159. </el-button>
  160. <el-button
  161. v-show="theTask.step === 30 && type == 1"
  162. v-permissions="['plat:task:detail:adopt']"
  163. type="primary"
  164. @click="changeStatus(30, '30')">
  165. 审批通过
  166. </el-button>
  167. <el-button
  168. v-show="theTask.step === 30 && type == 1"
  169. v-permissions="['plat:task:detail:return']"
  170. type="danger"
  171. @click="changeStatus(30, '40')">
  172. 审批退回
  173. </el-button>
  174. <el-button
  175. v-show="theTask.step === 40 && type == 1"
  176. v-permissions="['plat:task:detail:adopt']"
  177. type="primary"
  178. @click="changeStatus(40, '30')">
  179. 审批通过
  180. </el-button>
  181. <el-button
  182. v-show="theTask.step === 40 && type == 1"
  183. v-permissions="['plat:task:detail:return']"
  184. type="danger"
  185. @click="changeStatus(40, '40')">
  186. 审批退回
  187. </el-button>
  188. <el-button @click="$router.go(-1)">返回</el-button>
  189. </div>
  190. <ul class="records">
  191. <li v-for="log in logList" :key="log.id">
  192. <vab-icon icon="record-circle-line" />
  193. <div class="text">
  194. <p class="action">
  195. <span>{{ log.nodeName }}</span>
  196. <span>{{ log.desc }}</span>
  197. </p>
  198. <p>
  199. <span>开始处理</span>
  200. <span>完成处理</span>
  201. </p>
  202. <p>
  203. <span>{{ log.startTime }}</span>
  204. <span>{{ log.endTime }}</span>
  205. </p>
  206. </div>
  207. </li>
  208. </ul>
  209. </el-col>
  210. </el-row>
  211. </div>
  212. </template>
  213. <script>
  214. import to from 'await-to-js'
  215. import taskApi from '@/api/plat/task'
  216. import userApi from '@/api/system/user'
  217. import asyncUploadFile from '@/utils/uploadajax'
  218. import dictApi from '@/api/system/dict'
  219. import axios from 'axios'
  220. export default {
  221. name: 'TaskDetail',
  222. data() {
  223. return {
  224. detail: {},
  225. // 督办进展
  226. progressList: [],
  227. // 日志
  228. logList: [],
  229. theTask: {},
  230. typeMap: {},
  231. userMap: {},
  232. teamNames: '',
  233. form: {
  234. comment: '',
  235. },
  236. type: '',
  237. // 选中进展
  238. theProp: {},
  239. }
  240. },
  241. async mounted() {
  242. this.type = this.$route.query.type
  243. await this.initData()
  244. this.theTask = this.$store.state.task.theTask
  245. this.open()
  246. },
  247. methods: {
  248. // 判断是否没有超期
  249. isNotOverdue(date) {
  250. return new Date() <= new Date(date)
  251. },
  252. // 打开弹窗
  253. open() {
  254. // 获取数据信息
  255. this.getProgressList()
  256. this.getLogList()
  257. this.teamNames = ''
  258. if (this.theTask.ownerUserId != '') {
  259. let ids = this.theTask.ownerUserId.split(',')
  260. for (let id of ids) {
  261. if (this.teamNames == '') {
  262. this.teamNames = this.userMap[parseInt(id)]
  263. } else {
  264. this.teamNames += ',' + this.userMap[parseInt(id)]
  265. }
  266. }
  267. }
  268. },
  269. // 初始化数据
  270. async initData() {
  271. const [err, [type, user]] = await to(
  272. Promise.all([dictApi.getDictDataList({ dictType: 'task_type' }), userApi.getList()])
  273. )
  274. if (err) return
  275. this.types = type.data.list
  276. for (let type of this.types) {
  277. this.typeMap[type.dictValue] = type.dictLabel
  278. }
  279. this.users = user.data.list
  280. for (let user of this.users) {
  281. this.userMap[user.id] = user.nickName
  282. }
  283. },
  284. // 获取进展信息
  285. getProgressList() {
  286. this.progressList = []
  287. taskApi
  288. .getTaskProgressList({ taskId: this.theTask.id + '' })
  289. .then((res) => {
  290. if (res.data.list) {
  291. this.progressList = res.data.list
  292. }
  293. })
  294. .catch((err) => {
  295. console.error(err)
  296. })
  297. },
  298. // 获取日志信息
  299. getLogList() {
  300. this.logList = []
  301. taskApi
  302. .getTaskLogList({ taskId: this.theTask.id + '' })
  303. .then((res) => {
  304. if (res.data.list) {
  305. this.logList = res.data.list
  306. }
  307. })
  308. .catch((err) => {
  309. console.error(err)
  310. })
  311. },
  312. // 改变督办状态
  313. changeStatus(step, status) {
  314. if (step == 30 && !this.form.approDesc) return this.$message.warning('请填写审批意见')
  315. else if (step == 40 && !this.form.evaluateDesc) return this.$message.warning('请填写督办意见')
  316. this.$confirm('确定修改督办状态?', '提示', {
  317. confirmButtonText: '确定',
  318. cancelButtonText: '取消',
  319. type: 'warning',
  320. }).then(async () => {
  321. // eslint-disable-next-line vue/no-mutating-props
  322. this.selfVisible = false
  323. let data = {
  324. taskId: this.theTask.id,
  325. step,
  326. handleStatus: status,
  327. handleDesc: '',
  328. progressList: this.progressList,
  329. }
  330. if (this.theTask.step == 30) data.handleDesc = this.form.approDesc
  331. else if (this.theTask.step == 40) data.handleDesc = this.form.evaluateDesc
  332. const { msg } = await taskApi.handleTask(data)
  333. this.$baseMessage(msg, 'success', 'vab-hey-message-success')
  334. this.$router.go(-1)
  335. })
  336. },
  337. // 查看附件
  338. showFile(path) {
  339. window.open(path, '_system')
  340. },
  341. // 添加进展
  342. addProgress() {
  343. this.progressList.push({
  344. progDesc: '',
  345. progDate: '',
  346. progFile: '',
  347. remark: '',
  348. })
  349. },
  350. handleDel(index) {
  351. this.progressList.splice(index, 1)
  352. },
  353. // 开始上传附件
  354. showUploadFileDialog(row) {
  355. this.theProp = row
  356. },
  357. // 上传
  358. uploadrequest(option) {
  359. let _this = this
  360. let url = process.env.VUE_APP_UPLOAD_WEED
  361. axios
  362. .post(url)
  363. .then(function (res) {
  364. if (res.data && res.data.fid && res.data.fid !== '') {
  365. option.action = `${process.env.VUE_APP_PROTOCOL}${res.data.publicUrl}/${res.data.fid}`
  366. asyncUploadFile(option).then(() => {
  367. _this.theProp.progFile = `${process.env.VUE_APP_PROTOCOL}${res.data.publicUrl}/${res.data.fid}`
  368. })
  369. } else {
  370. _this.$message({
  371. type: 'warning',
  372. message: '未上传成功!请重新上传!',
  373. })
  374. }
  375. })
  376. .catch(function () {
  377. _this.$message({
  378. type: 'warning',
  379. message: '未上传成功!请重新上传!',
  380. })
  381. })
  382. },
  383. },
  384. }
  385. </script>
  386. <style lang="scss" scoped>
  387. $base: '.detail';
  388. #{$base} {
  389. height: calc(100vh - 60px - 12px * 2 - 40px);
  390. display: flex;
  391. padding: 20px 40px;
  392. > .el-row {
  393. flex: 1;
  394. > .el-col {
  395. height: 100%;
  396. }
  397. }
  398. .title {
  399. p,
  400. h3 {
  401. margin: 0;
  402. }
  403. p {
  404. font-size: 14px;
  405. font-weight: 400;
  406. line-height: 22px;
  407. }
  408. h3 {
  409. font-size: 24px;
  410. font-weight: 500;
  411. line-height: 36px;
  412. color: #333;
  413. display: flex;
  414. justify-content: space-between;
  415. }
  416. }
  417. header {
  418. min-height: 134px;
  419. background: rgba(196, 196, 196, 0.5);
  420. border-radius: 4px;
  421. display: flex;
  422. flex-direction: column;
  423. align-items: center;
  424. padding: 7px 20px;
  425. margin-top: 16px;
  426. ::v-deep .el-descriptions__body {
  427. background: transparent;
  428. }
  429. ::v-deep .my-label {
  430. font-size: 14px;
  431. font-weight: 600;
  432. color: #1d66dc;
  433. }
  434. ::v-deep .my-content {
  435. font-size: 14px;
  436. font-weight: 600;
  437. color: #333;
  438. overflow: hidden;
  439. text-overflow: ellipsis;
  440. white-space: nowrap;
  441. }
  442. }
  443. .buttons {
  444. height: 60px;
  445. padding-top: 28px;
  446. text-align: right;
  447. }
  448. .add-pro {
  449. text-align: right;
  450. margin: 10px 0;
  451. }
  452. .records {
  453. padding: 10px 20px;
  454. height: calc(100% - 60px);
  455. overflow-y: auto;
  456. li {
  457. display: flex;
  458. align-items: center;
  459. i {
  460. font-size: 40px;
  461. margin-right: 10px;
  462. }
  463. .text {
  464. flex: 1;
  465. }
  466. p {
  467. height: 20px;
  468. line-height: 20px;
  469. display: flex;
  470. justify-content: space-between;
  471. font-weight: 500;
  472. &:first-child {
  473. font-weight: bold;
  474. }
  475. }
  476. & + li {
  477. margin-top: 10px;
  478. }
  479. }
  480. }
  481. }
  482. </style>