taskOnline.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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="task-online-container">
  16. <!-- 导航栏 -->
  17. <NavBar title="在线录入" />
  18. <!-- 查询视图 -->
  19. <component
  20. :is="queryViewComponent"
  21. ref="queryViewRef"
  22. :query-type="defaultTypeValue"
  23. @query-action="queryAction"
  24. />
  25. <!-- 筛选条件栏 -->
  26. <RadioFilterBar
  27. v-if="equipType === EquipmentType.BOILER""
  28. v-model="rightType"
  29. :options="rightTypeList"
  30. type="radio"
  31. @change="handleRightType"
  32. />
  33. <!-- 列表 -->
  34. <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
  35. <view v-for="item in listData" :key="item.id" class="task-cell">
  36. <component
  37. :is="taskItemComponent"
  38. :ref="setItemRef(item.id)"
  39. :item="item"
  40. :user-id="userId"
  41. @claim-task="handleClaimTask"
  42. />
  43. </view>
  44. <view v-if="loading" class="loading-text">加载中...</view>
  45. <view v-if="!hasMore && listData.length > 0" class="no-more-text">没有更多了</view>
  46. <view v-if="!loading && listData.length === 0" class="empty-text">
  47. <text>暂无数据</text>
  48. </view>
  49. </scroll-view>
  50. </view>
  51. </template>
  52. <script lang="ts" setup>
  53. import { ref, reactive, computed, onMounted } from 'vue'
  54. import { useUserStore } from '@/store/user'
  55. import BoilerQueryView from './components/query/BoilerQueryView.vue'
  56. import PipeQueryView from './components/query/PipeQueryView.vue'
  57. import RadioFilterBar from '@/components/RadioFilterBar/RadioFilterBar.vue'
  58. import { useConfigStore } from '@/store/config'
  59. import { TaskOrderFuncName, requestFunc } from '@/api/ApiRouter/taskOrder'
  60. import NavBar from '@/components/NavBar/NavBar.vue'
  61. import BoilerTaskItem from './components/BoilerTaskItem.vue'
  62. import PipeTaskItem from './components/PipeTaskItem.vue'
  63. import { EquipmentType } from '@/utils/dictMap'
  64. import { onShow } from '@dcloudio/uni-app'
  65. defineOptions({
  66. name: 'taskOnline',
  67. })
  68. // 状态
  69. const queryViewRef = ref<any>(null)
  70. const listData = ref<any[]>([])
  71. const loading = ref(false)
  72. const hasMore = ref(true)
  73. const params = reactive({
  74. pageNo: 1,
  75. pageSize: 10,
  76. })
  77. const rightType = ref<'claim' | 'allot' | 'unclaim' | ''>('')
  78. const rightTypeList = [
  79. { value: '全部', id: '' },
  80. { value: '已认领', id: 'claim' },
  81. { value: '待认领', id: 'unclaim' },
  82. ]
  83. const userStore = useUserStore()
  84. const userInfo = computed(() => userStore.userInfo)
  85. const userId = computed(() => userInfo.value?.id || '')
  86. const equipType = useConfigStore().getEquipType()
  87. const taskItemComponent = computed(() => {
  88. switch (equipType) {
  89. case EquipmentType.BOILER:
  90. return BoilerTaskItem
  91. case EquipmentType.PIPE:
  92. return PipeTaskItem
  93. default:
  94. return null
  95. }
  96. })
  97. const queryViewComponent = computed(() => {
  98. switch (equipType) {
  99. case EquipmentType.BOILER:
  100. return BoilerQueryView
  101. case EquipmentType.PIPE:
  102. return PipeQueryView
  103. default:
  104. return null
  105. }
  106. })
  107. // 默认查询参数
  108. const defaultTypeValue = computed(() => ({
  109. orderNo: '',
  110. taskStatusList: [400, 500, 510],
  111. }))
  112. const itemRefs = reactive<Record<string, any>>({})
  113. // 设置组件引用
  114. const setItemRef = (itemId: string) => (ref: any) => {
  115. if (ref) {
  116. itemRefs[itemId] = ref
  117. } else {
  118. delete itemRefs[itemId]
  119. }
  120. }
  121. // 获取查询参数
  122. const getQueryParams = () => {
  123. const queryData = queryViewRef.value?.getQueryParams() || {}
  124. const statusData = handleRightRefresh()
  125. return {
  126. ...params,
  127. ...queryData,
  128. ...statusData,
  129. }
  130. }
  131. // 获取筛选条件
  132. const handleRightRefresh = () => {
  133. const result: Record<string, any> = {}
  134. switch (rightType.value) {
  135. case 'claim':
  136. result.isClaim = 'claim'
  137. break
  138. case 'unclaim':
  139. result.isClaim = 'unclaim'
  140. break
  141. default:
  142. result.isClaim = null
  143. break
  144. }
  145. return result
  146. }
  147. // 获取列表数据
  148. const fetchList = async (refresh = false) => {
  149. if (loading.value) return
  150. params.pageNo = refresh ? 1 : params.pageNo + 1
  151. const queryData = getQueryParams()
  152. loading.value = true
  153. try {
  154. const responseResult = await requestFunc(TaskOrderFuncName.TaskEquipList, equipType, queryData)
  155. const newList = responseResult?.data?.list || []
  156. if (refresh) {
  157. listData.value = newList
  158. } else {
  159. listData.value = [...listData.value, ...newList]
  160. }
  161. hasMore.value = newList.length >= params.pageSize
  162. } catch (error) {
  163. console.error('获取列表失败:', error)
  164. } finally {
  165. loading.value = false
  166. }
  167. }
  168. // 加载更多
  169. const loadMore = () => {
  170. if (!loading.value && hasMore.value) {
  171. fetchList(false)
  172. }
  173. }
  174. // 刷新列表
  175. const refreshList = () => {
  176. params.pageNo = 1
  177. fetchList(true)
  178. }
  179. // 查询动作
  180. const queryAction = () => {
  181. refreshList()
  182. }
  183. // 切换筛选类型
  184. const handleRightType = (value: string | number | boolean) => {
  185. rightType.value = value as 'claim' | 'allot' | 'unclaim' | ''
  186. refreshList()
  187. }
  188. // 设备认领/取消认领
  189. const handleClaimTask = async (id: string, isClaim: boolean) => {
  190. try {
  191. let result = null
  192. if (isClaim) {
  193. result = await requestFunc(TaskOrderFuncName.EquipmentConfirmClaim, equipType, { id })
  194. } else {
  195. result = await requestFunc(TaskOrderFuncName.EquipmentCancelClaim, equipType, { id })
  196. }
  197. if (result?.code === 0 && result?.data) {
  198. uni.showToast({ title: `${isClaim ? '认领' : '取消认领'}成功`, icon: 'success' })
  199. itemRefs[id]?.setIsClaim(isClaim)
  200. refreshList()
  201. } else {
  202. const msg = result?.msg || `${isClaim ? '设备认领' : '取消认领'}失败`
  203. uni.showToast({ title: msg, icon: 'error' })
  204. }
  205. } catch (error) {
  206. console.error('认领任务失败:', error)
  207. uni.showToast({ title: '操作失败', icon: 'error' })
  208. }
  209. }
  210. onShow(() => {
  211. refreshList()
  212. })
  213. </script>
  214. <style lang="scss" scoped>
  215. .task-online-container {
  216. display: flex;
  217. flex-direction: column;
  218. height: 100vh;
  219. background-color: #f5f5f5;
  220. }
  221. .list-scroll {
  222. flex: 1;
  223. overflow: hidden;
  224. }
  225. .loading-text,
  226. .no-more-text {
  227. padding: 15px;
  228. font-size: 14px;
  229. color: #999;
  230. text-align: center;
  231. }
  232. .empty-text {
  233. display: flex;
  234. flex-direction: column;
  235. align-items: center;
  236. justify-content: center;
  237. padding: 60px 0;
  238. color: #999;
  239. font-size: 14px;
  240. }
  241. </style>