taskOnline.vue 7.0 KB

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