index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <template>
  2. <z-paging class="hc-task-page" ref="pageRef" v-model="taskList" @query="getTaskList">
  3. <template #top>
  4. <view class="hc-paging-top-bar">
  5. <hc-nav-bar class="task-nav-bar">
  6. <view class="segmented-bar">
  7. <template v-for="item in taskTypeData">
  8. <view class="task-tab-item" :class="item.key === taskType?'task-cur':''" @click="taskTypeChange(item)">{{item.name}}</view>
  9. </template>
  10. </view>
  11. <view class="more-bar" v-if="taskType === 1 && taskList.length > 0" @click="moreBarClick">
  12. <text class="i-ri-more-2-fill icon"/>
  13. </view>
  14. </hc-nav-bar>
  15. <!--条件筛选-->
  16. <view class="controls-bar-box">
  17. <view class="controls-bar">
  18. <view class="left">
  19. <text class="i-ri-filter-fill icon" :class="isControlsFilter?'cur':''" @click="dateFilterClick"/>
  20. <text class="i-ri-filter-off-fill icon" @click="dateFilterClear"/>
  21. </view>
  22. <view class="right">
  23. <text class="i-ri-sort-desc icon" :class="searchForm.ordType === 1?'cur':''" @click="changeOrdType(1)"/>
  24. <text class="i-ri-sort-asc icon" :class="searchForm.ordType === 2?'cur':''" @click="changeOrdType(2)"/>
  25. </view>
  26. </view>
  27. <view class="controls-filter" v-if="isControlsFilter">
  28. <view class="search-form-date">
  29. <picker class="search-date-input" mode="date" :value="searchForm.startTime" @change="startDateChange">
  30. <view class="content">
  31. <view class="text">{{searchForm.startTime??'点此选择开始日期'}}</view>
  32. <text class="i-ri-close-circle-line icon" v-if="searchForm.startTime" @click.stop="startDateClear"/>
  33. </view>
  34. </picker>
  35. </view>
  36. <view class="search-form-date">
  37. <picker class="search-date-input" mode="date" :value="searchForm.endTime" @change="endDateChange">
  38. <view class="content">
  39. <view class="text">{{searchForm.endTime??'点此选择结束日期'}}</view>
  40. <text class="i-ri-close-circle-line icon" v-if="searchForm.endTime" @click.stop="endDateClear"/>
  41. </view>
  42. </picker>
  43. </view>
  44. <button class="search-form-btn" type="primary" size="mini" @click="searchClick">查询</button>
  45. </view>
  46. </view>
  47. </view>
  48. </template>
  49. <!--任务列表-->
  50. <uni-card v-for="item in taskList" padding="0" :class="item.check?'is-check':''" @click="taskItemClick(item)">
  51. <view class="py-3 text-30 text-black">{{item.taskName}}</view>
  52. <view slot="actions" class="card-actions no-border">
  53. <view class="card-actions-item">
  54. <view class="item-icon-check" v-if="showCheck">
  55. <uni-icons type="checkbox-filled" size="26" color="#ee5b20" v-if="item.check"/>
  56. <uni-icons type="checkbox" size="26" color="#9a9a9a" v-else/>
  57. </view>
  58. <text>{{item.startTime}}提交的申请</text>
  59. </view>
  60. <view class="card-actions-item">
  61. <uni-icons type="calendar" size="18" color="#EE5B20"/>
  62. <text class="card-actions-item-text" style="color: #EE5B20;">审批</text>
  63. </view>
  64. </view>
  65. </uni-card>
  66. <template #bottom>
  67. <hc-tabbars class="hc-paging-bottom-bar" v-if="showCheck">
  68. <view class="show-check-tabbars">
  69. <view class="check-bar">
  70. <view class="check-box" @click="allCheckClick">
  71. <text class="text">全选</text>
  72. <uni-icons type="checkbox-filled" size="26" color="#ee5b20" v-if="isAllCheck"/>
  73. <uni-icons type="checkbox" size="26" color="#9a9a9a" v-else/>
  74. </view>
  75. <view class="text-box">
  76. <text class="text">共勾选</text>
  77. <text class="text" style="color: #ee5b20;">{{itemCheckIndex}}</text>
  78. <text class="text">条任务</text>
  79. </view>
  80. </view>
  81. <view class="btn-bar">
  82. <button class="check-btn" size="mini" @click="batchApproval">批量审批</button>
  83. <button class="check-btn" size="mini" @click="cancelTaskClick">批量废除</button>
  84. <button class="check-btn cancel" size="mini" @click="cancelCheckClick">取消操作</button>
  85. </view>
  86. </view>
  87. </hc-tabbars>
  88. </template>
  89. </z-paging>
  90. </template>
  91. <script setup>
  92. import {nextTick, ref, watch} from "vue";
  93. import {onLoad} from '@dcloudio/uni-app'
  94. import mainApi from '~api/tasks/data';
  95. import {errorToast, successToast} from "@/utils/tools";
  96. import {arrToKey, getArrValue, getObjValue} from "js-fast-way";
  97. import {useAppStore} from "@/store";
  98. //初始变量
  99. const store = useAppStore()
  100. const projectId = ref(store.projectId);
  101. const contractId = ref(store.contractId);
  102. const pageRef = ref(null)
  103. onLoad(() => {
  104. })
  105. //顶部类型切换
  106. const taskType = ref(1)
  107. const taskTypeData = [
  108. {key: 1, name: '我的审批'},
  109. {key: 2, name: '我发起的'},
  110. {key: 3, name: '已办结的'}
  111. ]
  112. const taskTypeChange = ({key}) => {
  113. taskType.value = key
  114. searchClick()
  115. }
  116. //批量操作
  117. const showCheck = ref(false)
  118. const moreBarClick = () => {
  119. showCheck.value = !showCheck.value
  120. }
  121. //日期选择器弹出框
  122. const isControlsFilter = ref(false)
  123. //监听顶部高度变化
  124. watch(isControlsFilter, (res) => {
  125. nextTick(() => {
  126. pageRef.value?.updatePageScrollTopHeight()
  127. })
  128. })
  129. //监听底部高度变化
  130. watch(showCheck, (res) => {
  131. nextTick(() => {
  132. pageRef.value?.updatePageScrollBottomHeight()
  133. })
  134. })
  135. const dateFilterClick = () => {
  136. isControlsFilter.value = !isControlsFilter.value
  137. }
  138. const dateFilterClear = () => {
  139. isControlsFilter.value = false
  140. searchForm.value.startTime = null
  141. searchForm.value.endTime = null
  142. searchClick()
  143. }
  144. //开启日期选择完毕
  145. const startDateChange = (e) => {
  146. const val = e.detail.value, endTime = searchForm.value.endTime
  147. if (endTime && val && val > endTime) {
  148. errorToast('开始日期不能大于结束日期', 2000)
  149. return false
  150. } else {
  151. searchForm.value.startTime = val
  152. }
  153. }
  154. const startDateClear = () => {
  155. searchForm.value.startTime = null
  156. }
  157. //结束日期选择完毕
  158. const endDateChange = (e) => {
  159. const val = e.detail.value, startTime = searchForm.value.startTime
  160. if (startTime && val && val < startTime) {
  161. errorToast('结束日期不能小于开始日期', 2000)
  162. return false
  163. } else {
  164. searchForm.value.endTime = val
  165. }
  166. }
  167. const endDateClear = () => {
  168. searchForm.value.endTime = null
  169. }
  170. //条件搜索
  171. const searchClick = () => {
  172. pageRef.value?.reload()
  173. }
  174. //排序切换
  175. const changeOrdType = (type) => {
  176. searchForm.value.ordType = type
  177. searchClick()
  178. }
  179. //搜索表单
  180. const searchForm = ref({
  181. startTime: null, endTime: null, ordType: 1
  182. })
  183. //获取任务列表数据
  184. const taskList = ref([])
  185. const getTaskList = async (pageNo, pageSize) => {
  186. let task_type = taskType.value, res = {};
  187. uni.showLoading({title: '获取数据中...', mask: true});
  188. if (task_type === 1) {
  189. const { data } = await mainApi.queryUserToDoTaskList({
  190. projectId: projectId.value,
  191. contractId: contractId.value,
  192. ...searchForm.value,
  193. current: pageNo,
  194. size: pageSize,
  195. })
  196. res = getObjValue(data)
  197. } else if (task_type === 2) {
  198. const { data } = await mainApi.queryUserStartFlow({
  199. projectId: projectId.value,
  200. contractId: contractId.value,
  201. ...searchForm.value,
  202. current: pageNo,
  203. size: pageSize,
  204. })
  205. res = getObjValue(data)
  206. } else if (task_type === 3) {
  207. const { data } = await mainApi.queryUserDoneTaskList({
  208. projectId: projectId.value,
  209. contractId: contractId.value,
  210. ...searchForm.value,
  211. current: pageNo,
  212. size: pageSize,
  213. })
  214. res = getObjValue(data)
  215. }
  216. uni.hideLoading();
  217. pageRef.value?.complete(getArrValue(res?.records));
  218. if (isAllCheck.value) {
  219. isAllCheck.value = itemCheckIndex.value === taskList.value.length
  220. }
  221. }
  222. //任务被点击
  223. const itemCheckIndex = ref(0)
  224. const taskItemClick = (item) => {
  225. if (showCheck.value) {
  226. const check = !item.check, list = taskList.value
  227. if (check) {
  228. itemCheckIndex.value++
  229. } else {
  230. itemCheckIndex.value--
  231. }
  232. item.check = check
  233. isAllCheck.value = list.length === itemCheckIndex.value
  234. } else {
  235. toTaskDetail([item])
  236. }
  237. }
  238. //全选
  239. const isAllCheck = ref(false)
  240. const allCheckClick = () => {
  241. uni.showLoading({title: '处理中...', mask: true});
  242. const list = taskList.value, isCheck = !isAllCheck.value
  243. for (let i = 0; i < list.length; i++) {
  244. list[i].check = isCheck;
  245. }
  246. itemCheckIndex.value = isCheck ? list.length : 0
  247. isAllCheck.value = isCheck
  248. uni.hideLoading();
  249. }
  250. //取消操作
  251. const cancelCheckClick = () => {
  252. const list = taskList.value
  253. for (let i = 0; i < list.length; i++) {
  254. list[i].check = false;
  255. }
  256. itemCheckIndex.value = 0
  257. showCheck.value = false
  258. }
  259. //批量审批
  260. const batchApproval = () => {
  261. let rows = taskList.value.filter((item) => {
  262. return item.check
  263. })
  264. if (rows.length <= 0) {
  265. errorToast('请选择需要审批的任务')
  266. return false
  267. }
  268. //路由跳转
  269. toTaskDetail(rows)
  270. }
  271. //跳转任务详情
  272. const toTaskDetail = (rows) => {
  273. uni.navigateTo({
  274. url: '/pages/task/detail',
  275. events: {
  276. finish: () => {
  277. searchClick();
  278. }
  279. },
  280. success: (res) => {
  281. res.eventChannel.emit('data', {
  282. rows: rows,
  283. //是否可以审批
  284. isTask: taskType.value === 1
  285. })
  286. }
  287. });
  288. }
  289. //批量废除
  290. const popupRef = ref(null)
  291. const argument = ref('')
  292. const cancelTaskList = ref([])
  293. const cancelTaskClick = () => {
  294. cancelTaskList.value = []
  295. let rows = taskList.value.filter((item) => {
  296. return item.check
  297. })
  298. if (rows.length <= 0) {
  299. errorToast('请选择需要废除的任务')
  300. return false
  301. }
  302. cancelTaskList.value = rows
  303. argument.value = ''
  304. popupRef.value?.open()
  305. }
  306. //确认废除
  307. const confirmRepeal = () => {
  308. if (!argument.value) {
  309. errorToast('请先填写废除理由')
  310. return false
  311. }
  312. batchCompleteApprovalTaskApi(cancelTaskList.value)
  313. }
  314. //批量废除接口
  315. const batchCompleteApprovalTaskApi = async (rows) => {
  316. uni.showLoading({title: '批量废除中...', mask: true});
  317. let taskIds = arrToKey(rows, 'taskId', ',')
  318. let approvalType = arrToKey(rows, 'approvalType', ',')
  319. let formDataId = arrToKey(rows, 'formDataId', ',')
  320. let parallelProcessInstanceIds = arrToKey(rows, 'parallelProcessInstanceId', ',')
  321. const {error, code, msg} = await mainApi.batchCompleteApprovalTask({
  322. flag: 'NO',
  323. comment: argument.value,
  324. taskIds: taskIds,
  325. approvalType: approvalType,
  326. formDataId: formDataId,
  327. parallelProcessInstanceIds: parallelProcessInstanceIds,
  328. })
  329. uni.hideLoading();
  330. if (!error && code === 200) {
  331. successToast('废除成功')
  332. cancelClick()
  333. searchClick()
  334. } else {
  335. errorToast(`废除失败:${msg}`)
  336. }
  337. }
  338. //取消废除
  339. const cancelClick = () => {
  340. popupRef.value?.close()
  341. argument.value = ''
  342. }
  343. </script>
  344. <style lang="scss" scoped>
  345. page {
  346. background: #EFEFF4;
  347. height: 100%;
  348. }
  349. </style>
  350. <style lang="scss">
  351. @import "@/style/task/index.scss";
  352. </style>