unClaimList.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <route lang="json5" type="page">
  2. {
  3. layout: 'default',
  4. style: {
  5. navigationBarTitleText: '任务单',
  6. navigationStyle: 'custom',
  7. disableScroll: true,
  8. 'app-plus': {
  9. bounce: 'none',
  10. },
  11. },
  12. }
  13. </route>
  14. <template>
  15. <view class="unclaim-container">
  16. <!-- 导航栏 -->
  17. <NavBar title="任务单" />
  18. <!-- 查询视图 -->
  19. <view class="query-view-wrapper">
  20. <QueryView
  21. ref="queryViewRef"
  22. :equip-type="equipType"
  23. :query-type="defaultTypeValue"
  24. @query-action="queryAction"
  25. />
  26. </view>
  27. <!-- 筛选条件栏 -->
  28. <view class="filter-bar">
  29. <RadioFilterBar
  30. v-model="rightType"
  31. :options="rightTypeList"
  32. type="radio"
  33. @change="handleRightRefresh"
  34. />
  35. <RadioFilterBar
  36. v-model="showTodayOnly"
  37. :options="todayOnlyOptions"
  38. type="checkbox"
  39. :margin-left="'15px'"
  40. @change="handleShowTodayOnly"
  41. />
  42. </view>
  43. <!-- 列表 -->
  44. <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
  45. <view v-for="(item, index) in listData" :key="item.id" class="task-cell">
  46. <TaskItem
  47. :ref="setItemRef(item.id)"
  48. :item="item"
  49. @claim-task="handleClaimTask"
  50. @btn-tap="handleBtnTap"
  51. @safety-check="handleSafetyCheck"
  52. @update-contact="handleUpdateContact"
  53. @pdf-detail="handlePdfDetail"
  54. />
  55. </view>
  56. <view v-if="loading" class="loading-text">加载中...</view>
  57. <view v-if="!hasMore && listData.length > 0" class="no-more-text">没有更多了</view>
  58. <view v-if="!loading && listData.length === 0" class="empty-text">
  59. <text>暂无数据</text>
  60. </view>
  61. </scroll-view>
  62. <!-- 修改联系人弹窗 -->
  63. <UpdateContactPopup
  64. v-if="showUpdateContactPopup"
  65. :popup-data="currentOrderInfo"
  66. @hide="closeUpdateContactPopup"
  67. @refresh="refreshList"
  68. />
  69. </view>
  70. </template>
  71. <script lang="ts" setup>
  72. import { ref, reactive, onMounted, onUnmounted } from 'vue'
  73. import { onShow } from '@dcloudio/uni-app'
  74. import dayjs from 'dayjs'
  75. import QueryView from './components/query/QueryView.vue'
  76. import TaskItem from './components/TaskItem.vue'
  77. import UpdateContactPopup from './components/UpdateContactPopup.vue'
  78. import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
  79. import { useConfigStore } from '@/store/config'
  80. import { TaskOrderFuncName, requestFunc } from '@/api/ApiRouter/taskOrder'
  81. import {
  82. SecurityCheckFuncName,
  83. requestFunc as securityCheckRequestFunc,
  84. } from '@/api/ApiRouter/taskOrderSecurityCheck'
  85. import NavBar from '@/components/NavBar/NavBar.vue'
  86. defineOptions({
  87. name: 'unClaimList',
  88. })
  89. // 状态
  90. const queryViewRef = ref<any>(null)
  91. const listData = ref<any[]>([])
  92. const loading = ref(false)
  93. const hasMore = ref(true)
  94. const params = reactive({
  95. pageNo: 1,
  96. pageSize: 5,
  97. taskStatus: '',
  98. showTodayOnly: true,
  99. })
  100. const showTodayOnly = ref(true)
  101. const rightType = ref('')
  102. const rightTypeList = [
  103. { value: '全部', id: '' },
  104. { value: '待认领', id: '100' },
  105. { value: '已认领', id: '400' },
  106. ]
  107. const todayOnlyOptions = [{ value: '仅看今天', id: 'today' }]
  108. const defaultTypeValue = {}
  109. const itemRefs = reactive<Record<string, any>>({})
  110. const showUpdateContactPopup = ref(false)
  111. const currentOrderInfo = ref<any>({})
  112. const configStore = useConfigStore()
  113. const equipType = configStore.getEquipType()
  114. // 设置组件引用
  115. const setItemRef = (itemId: string) => (ref: any) => {
  116. if (ref) {
  117. itemRefs[itemId] = ref
  118. } else {
  119. delete itemRefs[itemId]
  120. }
  121. }
  122. // 获取查询参数
  123. const getQueryParams = () => {
  124. const queryData = queryViewRef.value?.getQueryParams() || {}
  125. if (params.showTodayOnly) {
  126. return {
  127. ...queryData,
  128. checkDate: [dayjs().format('YYYY-MM-DD 00:00:00'), dayjs().format('YYYY-MM-DD 23:59:59')],
  129. }
  130. }
  131. return queryData
  132. }
  133. // 获取列表数据
  134. const fetchList = async (refresh = false) => {
  135. if (loading.value) return
  136. const queryData = {
  137. ...getQueryParams(),
  138. taskStatus: params.taskStatus,
  139. pageNo: refresh ? 1 : params.pageNo + 1,
  140. }
  141. params.pageNo = queryData.pageNo
  142. loading.value = true
  143. try {
  144. const responseResult = await requestFunc(TaskOrderFuncName.ConfirmList, equipType, queryData)
  145. const newList = responseResult?.data?.list || []
  146. if (refresh) {
  147. listData.value = newList
  148. } else {
  149. listData.value = [...listData.value, ...newList]
  150. }
  151. hasMore.value = newList.length >= params.pageSize
  152. } catch (error) {
  153. console.error('获取列表失败:', error)
  154. } finally {
  155. loading.value = false
  156. }
  157. }
  158. // 加载更多
  159. const loadMore = () => {
  160. if (!loading.value && hasMore.value) {
  161. fetchList(false)
  162. }
  163. }
  164. // 刷新列表
  165. const refreshList = () => {
  166. params.pageNo = 1
  167. fetchList(true)
  168. }
  169. // 查询动作
  170. const queryAction = () => {
  171. refreshList()
  172. }
  173. // 筛选刷新
  174. const handleRightRefresh = (value: string | number | boolean) => {
  175. rightType.value = value as string
  176. params.taskStatus = rightType.value
  177. refreshList()
  178. }
  179. // 切换仅看今天
  180. const handleShowTodayOnly = (value: string | number | boolean) => {
  181. showTodayOnly.value = value as boolean
  182. params.showTodayOnly = showTodayOnly.value
  183. refreshList()
  184. }
  185. // 认领任务
  186. const handleClaimTask = async (id: string, isClaim: boolean) => {
  187. try {
  188. const result = await requestFunc(TaskOrderFuncName.TaskConfirm, equipType, {
  189. id,
  190. confirm: isClaim,
  191. })
  192. if (result?.code === 0 && result?.data) {
  193. uni.showToast({ title: `${isClaim ? '认领' : '取消认领'}成功`, icon: 'success' })
  194. refreshList()
  195. } else {
  196. const msg = result?.msg || `${isClaim ? '认领' : '取消认领'}失败`
  197. uni.showToast({ title: msg, icon: 'error' })
  198. }
  199. } catch (error) {
  200. console.error('认领任务失败:', error)
  201. uni.showToast({ title: '认领失败', icon: 'error' })
  202. }
  203. }
  204. const businessTypeMap: Record<string, number> = { FWD: 100, JYRS: 200 }
  205. // 按钮点击(服务单/受理单/检验结果告知)
  206. const handleBtnTap = async (type: 'FWD' | 'JYRS', taskOrder: any) => {
  207. // 检查网络状态
  208. const networkType = uni.getNetworkType()
  209. if (networkType === 'none') {
  210. return uni.showToast({ title: '无网络连接,请联网重试', icon: 'error' })
  211. }
  212. try {
  213. // const res = await requestFunc(TaskOrderFuncName.TaskOrderDetail, equipType, {
  214. // id: taskOrder.id,
  215. // })
  216. // if (!res?.data) {
  217. // uni.showToast({ title: res?.msg || '获取详情失败', icon: 'error' })
  218. // return
  219. // }
  220. // const signFileRespVOList = res.data.signFileRespVOList || []
  221. // const targetBusinessType = businessTypeMap[type]
  222. // const currentBusinessType =
  223. // signFileRespVOList.find((row: any) => row.businessType === targetBusinessType) || {}
  224. const { unitContact, unitPhone, receiverEmail } = taskOrder
  225. // if (currentBusinessType.isSignature === '1') {
  226. // uni.navigateTo({
  227. // url: `/pages/sign-detail/index?orderId=${taskOrder.id}&type=${type}&unitContact=${unitContact || ''}&unitPhone=${unitPhone || ''}&receiverEmail=${receiverEmail || ''}`,
  228. // })
  229. // return
  230. // }
  231. uni.navigateTo({
  232. url: `/pages/sign/index?orderId=${taskOrder.id}&type=${type}&unitContact=${unitContact || ''}&unitPhone=${unitPhone || ''}&receiverEmail=${receiverEmail || ''}`,
  233. })
  234. } catch (error) {
  235. console.error('获取详情失败:', error)
  236. }
  237. }
  238. // 安全检查记录
  239. const handleSafetyCheck = async (taskOrder: any) => {
  240. // 检查网络状态
  241. const networkType = uni.getNetworkType()
  242. if (networkType === 'none') {
  243. return uni.showToast({ title: '无网络连接,请联网重试', icon: 'error' })
  244. }
  245. try {
  246. const res = await securityCheckRequestFunc(SecurityCheckFuncName.getTemplate, equipType, {
  247. orderId: taskOrder.id,
  248. })
  249. // 跳转到 WebView 编辑器
  250. uni.navigateTo({
  251. url: `/pages/securityCheck/securityCheckEditor?businessType=AQJC&orderId=${taskOrder.id}&templateId=${res.data.templateId}&useOnline=1&mode=create`,
  252. })
  253. } catch (configError) {
  254. console.error('获取葡萄城配置信息失败:', configError)
  255. uni.showToast({ title: '获取配置信息失败,请重试', icon: 'error' })
  256. }
  257. }
  258. // 修改联系人
  259. const handleUpdateContact = (item: any) => {
  260. currentOrderInfo.value = item
  261. showUpdateContactPopup.value = true
  262. }
  263. // 关闭修改联系人弹窗
  264. const closeUpdateContactPopup = () => {
  265. showUpdateContactPopup.value = false
  266. currentOrderInfo.value = {}
  267. }
  268. // PDF 详情(告知单/服务单/受理单)
  269. const handlePdfDetail = (businessType: any, signFilePdf: string, orderId: string) => {
  270. const businessTypeTitle = businessType === 200 ? '告知单' : '服务单/受理单'
  271. uni.navigateTo({
  272. url: `/pages/sign/index?type=${businessType}&orderId=${orderId}&businessTypeTitle=${businessTypeTitle}`,
  273. })
  274. }
  275. // 页面显示时刷新(使用 onShow 替代 useDidShow)
  276. onShow((options) => {
  277. refreshList()
  278. })
  279. // 监听页面卸载
  280. onUnmounted(() => {
  281. // 触发更新事件
  282. uni.$emit('UpdateNum', ['unClaim', 'unDownload'])
  283. })
  284. // 暴露 onShow 给页面
  285. defineExpose({
  286. onShow,
  287. })
  288. </script>
  289. <style lang="scss" scoped>
  290. .unclaim-container {
  291. display: flex;
  292. flex-direction: column;
  293. height: 100vh;
  294. background-color: #f5f5f5;
  295. }
  296. .query-view-wrapper {
  297. flex-shrink: 0;
  298. }
  299. .list-scroll {
  300. flex: 1;
  301. overflow: hidden;
  302. }
  303. .loading-text,
  304. .no-more-text {
  305. padding: 15px;
  306. font-size: 14px;
  307. color: #999;
  308. text-align: center;
  309. }
  310. .empty-text {
  311. display: flex;
  312. flex-direction: column;
  313. align-items: center;
  314. justify-content: center;
  315. padding: 60px 0;
  316. font-size: 14px;
  317. color: #999;
  318. }
  319. .filter-bar {
  320. display: flex;
  321. justify-content: space-between;
  322. flex-shrink: 0;
  323. background-color: white;
  324. }
  325. </style>