device-list.uvue 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. <template>
  2. <uni-navbar-lite :showLeft="true" title="设备清单"></uni-navbar-lite>
  3. <view class="list-page">
  4. <!-- 任务信息栏 -->
  5. <view class="task-info-bar" v-if="taskInfo.planName != null">
  6. <view class="task-info-item">
  7. <text class="task-info-label">任务:</text>
  8. <text class="task-info-value">{{ taskInfo.planName }}</text>
  9. </view>
  10. <view class="task-info-item" v-if="taskInfo.displayTime != null">
  11. <text class="task-info-label">时间:</text>
  12. <text class="task-info-value">{{ taskInfo.displayTime }}</text>
  13. </view>
  14. </view>
  15. <!-- 搜索栏 -->
  16. <!--<view class="search-bar">
  17. <view class="search-box">
  18. <image class="search-icon" src="/static/images/workbench/list/1.png" mode="aspectFit"></image>
  19. <input class="search-input" type="text" placeholder="搜索设备" v-model="keyword" @confirm="handleSearch" @blur="handleSearch" />
  20. <text v-if="keyword.length > 0" class="clear-icon" @click="clearSearch">✕</text>
  21. </view>
  22. </view>-->
  23. <!-- 列表内容 -->
  24. <common-list
  25. :dataList="dataList"
  26. :loading="loading"
  27. :refreshing="refreshing"
  28. :hasMore="hasMore"
  29. @refresh="handleRefresh"
  30. @loadMore="loadMore"
  31. @itemClick="handleView"
  32. >
  33. <template #default="{ item, index }">
  34. <view class="list-item">
  35. <view class="item-container">
  36. <view class="item-header">
  37. <text class="item-title">{{ (item as DeviceCheckTaskDetail).machineryName }}</text>
  38. <view class="task-badges">
  39. <text class="status-tag" :class="getTaskStatusClass(item)">
  40. {{ getTaskStatusText((item as DeviceCheckTaskDetail).taskStatus) }}
  41. </text>
  42. </view>
  43. </view>
  44. <view class="info-row">
  45. <view class="info-label">
  46. <text class="text-gray">设备编号: {{ (item as DeviceCheckTaskDetail).machinerySpec }}</text>
  47. </view>
  48. </view>
  49. <view class="info-row">
  50. <view class="info-label">
  51. <text class="text-gray">位置: {{ (item as DeviceCheckTaskDetail).machineryLocation }}</text>
  52. </view>
  53. </view>
  54. <view class="btn-group">
  55. <!-- 显示扫描按钮的逻辑:如果设备未完成检查,且是第一个未检查的设备,则启用;否则禁用 -->
  56. <view
  57. v-if="(item as DeviceCheckTaskDetail).taskStatus == '0'"
  58. :class="['btn-primary', isFirstUncompletedTask(item) ? '' : 'btn-disabled']"
  59. @click.stop="isFirstUncompletedTask(item) ? handleItemClick(item,'scan') : null"
  60. >
  61. <!-- <text class="btn-text">扫描二维码</text> -->
  62. <text class="btn-text">开始检查</text>
  63. </view>
  64. <view
  65. v-else
  66. class="btn-primary"
  67. @click.stop="handleItemClick(item,'detail')"
  68. >
  69. <text class="btn-text">查看</text>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </template>
  75. </common-list>
  76. </view>
  77. </template>
  78. <script setup lang="uts">
  79. import { ref, onBeforeUnmount, onMounted, reactive } from 'vue'
  80. import { onLoad, onShow } from '@dcloudio/uni-app';
  81. import type { SysDictData } from '../../types/dict'
  82. import {checkPermi, getUserInfo} from '../../utils/storage'
  83. import { getTaskInfo, updateTaskInfo } from '../../api/task/list.uts'
  84. import { getTaskDetails } from '../../api/task/detail.uts'
  85. import { getDictDataByType } from '../../api/dict/index'
  86. // 任务基础信息类型(参照GenTask实体类)
  87. type TaskInfoForDevice = {
  88. taskId: Number | null
  89. planId: Number | null
  90. planType: string | null
  91. planName: string | null
  92. taskDate: string | null
  93. startTime: string | null
  94. endTime: string | null
  95. subjects: string | null
  96. machineryTypeName: string | null
  97. machinerySpec: string | null
  98. machineryLocation: string | null
  99. machineryName: string | null
  100. machineries: string | null
  101. locations: string | null
  102. operator: string | null
  103. operatorId: Number | null
  104. status: string | null
  105. taskDesc: string | null
  106. sourceType: string | null
  107. locationCount: Number
  108. machineryCount: Number
  109. createTime: string | null
  110. updateTime: string | null
  111. // 前端计算字段
  112. planTypeText: string | null
  113. statusText: string | null
  114. displayTime: string | null
  115. taskCount: string | null
  116. checkType: string | null
  117. }
  118. // 设备检查任务明细类型(参照DvCheckTaskDetail实体类)
  119. type DeviceCheckTaskDetail = {
  120. detailId: Number | null
  121. taskId: Number | null
  122. machineryRecordId: Number | null
  123. machineryId: Number | null
  124. machineryTypeName: string | null
  125. machinerySpec: string | null
  126. machineryLocation: string | null
  127. machineryName: string | null
  128. subjectId: Number | null
  129. subjectCode: string | null
  130. subjectName: string | null
  131. locationRecordId: Number | null
  132. locationId: Number | null
  133. locationName: string | null
  134. locationCode: string | null
  135. sourceType: string | null
  136. orderNum: Number | null
  137. status: string | null
  138. imagesUrl: string | null
  139. videosUrl: string | null
  140. resultValue: string | null
  141. resultDesc: string | null
  142. remark: string | null
  143. attr1: string | null
  144. attr2: string | null
  145. attr3: Number | null
  146. attr4: Number | null
  147. // 任务状态字段
  148. taskStatus: string | null // 'completed' 表示已完成,其他值表示未完成
  149. }
  150. // 设备清单数据
  151. const dataList = ref<DeviceCheckTaskDetail[]>([])
  152. // 任务信息
  153. const taskInfo = ref<TaskInfoForDevice>({
  154. taskId: null,
  155. planId: null,
  156. planType: null,
  157. planName: null,
  158. taskDate: null,
  159. startTime: null,
  160. endTime: null,
  161. subjects: null,
  162. machineryTypeName: null,
  163. machinerySpec: null,
  164. machineryLocation: null,
  165. machineryName: null,
  166. machineries: null,
  167. locations: null,
  168. operator: null,
  169. operatorId: null,
  170. status: null,
  171. taskDesc: null,
  172. sourceType: null,
  173. locationCount: 0,
  174. machineryCount: 0,
  175. createTime: null,
  176. updateTime: null,
  177. // 前端计算字段
  178. planTypeText: null,
  179. statusText: null,
  180. displayTime: null,
  181. taskCount: null,
  182. checkType: null
  183. })
  184. // 当前任务ID
  185. const currentTaskId = ref<string>('')
  186. const page = ref<number>(1)
  187. const pageSize: number = 10
  188. const hasMore = ref<boolean>(true)
  189. const loadingShow = ref<boolean>(false)
  190. const loading = ref<boolean>(false)
  191. const refreshing = ref<boolean>(false)
  192. const total = ref<number>(0)
  193. const taskStatusDictList = ref<SysDictData[]>([]) // 任务状态字典列表
  194. const dictLoaded = ref<boolean>(false) // 字典加载状态
  195. // 不再需要设备检查状态管理,使用taskStatus字段
  196. // 判断当前设备是否是第一个未完成的任务
  197. const isFirstUncompletedTask = (item: any | null): boolean => {
  198. if (item == null) return false
  199. const deviceItem = item as DeviceCheckTaskDetail
  200. // 如果任务已经完成,则返回false
  201. if (deviceItem.taskStatus == '2') {
  202. return false
  203. }
  204. // 查找第一个未完成的任务
  205. for (let i = 0; i < dataList.value.length; i++) {
  206. const device = dataList.value[i] as DeviceCheckTaskDetail
  207. if (device.taskStatus != '2') {
  208. // 返回当前设备是否是第一个未完成的任务
  209. return device.detailId == deviceItem.detailId
  210. }
  211. }
  212. // 如果所有任务都已完成,返回false
  213. return false
  214. }
  215. // 添加防重复刷新的标志
  216. const isRefreshing = ref<boolean>(false)
  217. // 添加刷新时间戳,用于防抖
  218. const lastRefreshTime = ref<number>(0)
  219. // 获取设备状态样式
  220. const getDeviceStatusClass = (item: any | null): string => {
  221. if (item == null) return ''
  222. const deviceItem = item as DeviceCheckTaskDetail
  223. const rawStatus = deviceItem.status
  224. if (rawStatus==null) return ''
  225. // 返回对应的状态类名
  226. return `status-${rawStatus}`
  227. }
  228. // 获取任务状态文本
  229. const getTaskStatusText = (taskStatus: string | null): string => {
  230. if (taskStatus == null || taskStatus.length == 0) return ''
  231. if (dictLoaded.value != true) {
  232. return taskStatus
  233. }
  234. const dictItem = taskStatusDictList.value.find((dict: SysDictData) => dict.dictValue == taskStatus)
  235. return dictItem != null && dictItem.dictLabel != null ? dictItem.dictLabel : taskStatus
  236. }
  237. // 获取任务状态字典列表
  238. const loadTaskStatusDictList = async (): Promise<void> => {
  239. try {
  240. const result = await getDictDataByType('dv_task_status')
  241. const resultObj = result as UTSJSONObject
  242. if (resultObj['code'] == 200) {
  243. const data = resultObj['data'] as any[]
  244. const dictData: SysDictData[] = []
  245. if (data.length > 0) {
  246. for (let i = 0; i < data.length; i++) {
  247. const item = data[i] as UTSJSONObject
  248. const dictItem: SysDictData = {
  249. dictValue: item['dictValue'] as string | null,
  250. dictLabel: item['dictLabel'] as string | null,
  251. dictCode: null,
  252. dictSort: null,
  253. dictType: null,
  254. cssClass: null,
  255. listClass: null,
  256. isDefault: null,
  257. status: null,
  258. default: null,
  259. createTime: null,
  260. remark: null
  261. }
  262. dictData.push(dictItem)
  263. }
  264. }
  265. taskStatusDictList.value = dictData
  266. dictLoaded.value = true
  267. }
  268. } catch (e: any) {
  269. console.error('获取任务状态字典失败:', e.message)
  270. dictLoaded.value = true
  271. }
  272. }
  273. // 获取任务状态样式
  274. const getTaskStatusClass = (item: any | null): string => {
  275. if (item == null) return ''
  276. const deviceItem = item as DeviceCheckTaskDetail
  277. const taskStatus = deviceItem.taskStatus
  278. if (taskStatus==null) return ''
  279. // 返回对应的任务状态类名
  280. return `taskStatus-${taskStatus}`
  281. }
  282. // 获取显示时间
  283. const getDisplayTime = (item: TaskInfoForDevice): string | null => {
  284. if (item.taskDate == null || item.taskDate.length == 0) return null
  285. if (item.startTime != null && item.startTime.length > 0 && item.endTime != null && item.endTime.length > 0) {
  286. return `${item.taskDate} ${item.startTime}-${item.endTime}`
  287. }
  288. return item.taskDate
  289. }
  290. // 根据dataList中的taskStatus更新taskInfo的status
  291. const updateTaskInfoStatus = async (): Promise<void> => {
  292. if (dataList.value.length == 0) return;
  293. let completedCount = 0;
  294. for (let i = 0; i < dataList.value.length; i++) {
  295. const item = dataList.value[i] as DeviceCheckTaskDetail;
  296. if (item.taskStatus == '2') {
  297. completedCount++;
  298. }
  299. }
  300. let newStatus = '0';
  301. // 全部完成
  302. if (completedCount == dataList.value.length) {
  303. newStatus = '2';
  304. }
  305. // 部分完成
  306. else if (completedCount > 0) {
  307. newStatus = '1';
  308. }
  309. // 全部未完成
  310. else {
  311. newStatus = '0';
  312. }
  313. // 只有状态发生变化时才调用接口更新
  314. if (taskInfo.value.status != newStatus) {
  315. taskInfo.value.status = newStatus;
  316. console.log(`任务状态更新: 总数${dataList.value.length}, 完成${completedCount}, 设置状态为${newStatus}`);
  317. // 调用后端接口更新任务状态
  318. try {
  319. const updateData: UTSJSONObject = {
  320. 'taskId': taskInfo.value.taskId,
  321. 'status': newStatus
  322. } as UTSJSONObject;
  323. await updateTaskInfo(updateData);
  324. console.log('任务状态已同步到后端');
  325. } catch (error) {
  326. console.error('更新任务状态失败:', error);
  327. // 如果更新失败,可以考虑回滚状态或给出提示
  328. }
  329. }
  330. }
  331. // 加载真实数据
  332. const loadData = async (isRefresh: boolean | null, disablePullDown: boolean | null): Promise<void> => {
  333. const shouldRefresh = isRefresh != null ? isRefresh : false
  334. const shouldDisablePullDown = disablePullDown != null ? disablePullDown : false
  335. if (currentTaskId.value == null || currentTaskId.value.length == 0) {
  336. return
  337. }
  338. loading.value = true
  339. if (shouldRefresh && !shouldDisablePullDown) {
  340. page.value = 1
  341. refreshing.value = true
  342. } else if (shouldRefresh && shouldDisablePullDown) {
  343. page.value = 1
  344. refreshing.value = false
  345. } else {
  346. refreshing.value = false
  347. }
  348. try {
  349. // 获取设备清单数据
  350. const result = await getTaskDetails(currentTaskId.value)
  351. // 提取响应数据
  352. const resultObj = result as UTSJSONObject
  353. const code = resultObj['code'] as number
  354. const responseData = resultObj['rows'] as any[]
  355. const responseTotal = resultObj['total'] as number
  356. if (code == 200) {
  357. // 将 any[] 转换为 DeviceCheckTaskDetail[]
  358. const newData: DeviceCheckTaskDetail[] = []
  359. for (let i = 0; i < responseData.length; i++) {
  360. const item = responseData[i] as UTSJSONObject
  361. const deviceItem: DeviceCheckTaskDetail = {
  362. detailId: item['detailId'] != null ? (item['detailId'] as Number) : null,
  363. taskId: item['taskId'] != null ? (item['taskId'] as Number) : null,
  364. machineryRecordId: item['machineryRecordId'] != null ? (item['machineryRecordId'] as Number) : null,
  365. machineryId: item['machineryId'] != null ? (item['machineryId'] as Number) : null,
  366. machineryTypeName: item['machineryTypeName'] as string | null,
  367. machinerySpec: item['machinerySpec'] as string | null,
  368. machineryLocation: item['machineryLocation'] as string | null,
  369. machineryName: item['machineryName'] as string | null,
  370. subjectId: item['subjectId'] != null ? (item['subjectId'] as Number) : null,
  371. subjectCode: item['subjectCode'] as string | null,
  372. subjectName: item['subjectName'] as string | null,
  373. locationRecordId: item['locationRecordId'] != null ? (item['locationRecordId'] as Number) : null,
  374. locationId: item['locationId'] != null ? (item['locationId'] as Number) : null,
  375. locationName: item['locationName'] as string | null,
  376. locationCode: item['locationCode'] as string | null,
  377. sourceType: item['sourceType'] as string | null,
  378. orderNum: item['orderNum'] != null ? (item['orderNum'] as Number) : null,
  379. status: item['status'] as string | null,
  380. imagesUrl: item['imagesUrl'] as string | null,
  381. videosUrl: item['videosUrl'] as string | null,
  382. resultValue: item['resultValue'] as string | null,
  383. resultDesc: item['resultDesc'] as string | null,
  384. remark: item['remark'] as string | null,
  385. attr1: item['attr1'] as string | null,
  386. attr2: item['attr2'] as string | null,
  387. attr3: item['attr3'] != null ? (item['attr3'] as Number) : null,
  388. attr4: item['attr4'] != null ? (item['attr4'] as Number) : null,
  389. // 任务状态字段
  390. //taskStatus: item['taskStatus'] != null ? (item['taskStatus'] as string) : '0',
  391. taskStatus: item['taskStatus'] as string | null,
  392. }
  393. newData.push(deviceItem)
  394. }
  395. if (shouldRefresh) {
  396. dataList.value = newData
  397. } else {
  398. dataList.value = [...dataList.value, ...newData]
  399. }
  400. total.value = responseTotal
  401. hasMore.value = dataList.value.length < responseTotal
  402. } else {
  403. const msg = resultObj['msg'] as string | null
  404. uni.showToast({
  405. title: msg ?? '加载失败',
  406. icon: 'none'
  407. })
  408. }
  409. } catch (e: any) {
  410. uni.showToast({
  411. title: e.message ?? '加载失败',
  412. icon: 'none'
  413. })
  414. } finally {
  415. loading.value = false
  416. if (shouldRefresh) {
  417. refreshing.value = false
  418. setTimeout(() => {
  419. isRefreshing.value = false
  420. }, 50)
  421. }
  422. }
  423. }
  424. // 加载任务基础信息
  425. const loadTaskInfo = async (): Promise<void> => {
  426. if (currentTaskId.value == null || currentTaskId.value.length == 0) {
  427. return
  428. }
  429. try {
  430. const result = await getTaskInfo(currentTaskId.value)
  431. // 提取响应数据
  432. const resultObj = result as UTSJSONObject
  433. const code = resultObj['code'] as number
  434. const taskData = resultObj['data'] as UTSJSONObject
  435. if (code == 200) {
  436. // 将返回的数据转换为TaskInfo类型
  437. const newTaskInfo: TaskInfoForDevice = {
  438. taskId: taskData['taskId'] != null ? (taskData['taskId'] as Number) : null,
  439. planId: taskData['planId'] != null ? (taskData['planId'] as Number) : null,
  440. planType: taskData['planType'] as string | null,
  441. planName: taskData['planName'] as string | null,
  442. taskDate: taskData['taskDate'] as string | null,
  443. startTime: taskData['startTime'] as string | null,
  444. endTime: taskData['endTime'] as string | null,
  445. subjects: taskData['subjects'] as string | null,
  446. machineryTypeName: taskData['machineryTypeName'] as string | null,
  447. machinerySpec: taskData['machinerySpec'] as string | null,
  448. machineryLocation: taskData['machineryLocation'] as string | null,
  449. machineryName: taskData['machineryName'] as string | null,
  450. machineries: taskData['machineries'] as string | null,
  451. locations: taskData['locations'] as string | null,
  452. operator: taskData['operator'] as string | null,
  453. operatorId: taskData['operatorId'] != null ? (taskData['operatorId'] as Number) : null,
  454. status: taskData['status'] as string | null,
  455. taskDesc: taskData['taskDesc'] as string | null,
  456. sourceType: taskData['sourceType'] as string | null,
  457. locationCount: taskData['locationCount'] != null ? (taskData['locationCount'] as Number) : 0,
  458. machineryCount: taskData['machineryCount'] != null ? (taskData['machineryCount'] as Number) : 0,
  459. createTime: taskData['createTime'] as string | null,
  460. updateTime: taskData['updateTime'] as string | null,
  461. // 前端计算字段初始化
  462. planTypeText: null,
  463. statusText: null,
  464. displayTime: null,
  465. taskCount: null,
  466. checkType: null
  467. }
  468. taskInfo.value = newTaskInfo
  469. // 计算前端显示字段
  470. taskInfo.value.displayTime = getDisplayTime(taskInfo.value)
  471. } else {
  472. const msg = resultObj['msg'] as string | null
  473. uni.showToast({
  474. title: msg ?? '获取任务信息失败',
  475. icon: 'none'
  476. })
  477. }
  478. } catch (e: any) {
  479. uni.showToast({
  480. title: e.message ?? '获取任务信息失败',
  481. icon: 'none'
  482. })
  483. }
  484. }
  485. // 下拉刷新
  486. const handleRefresh = async (): Promise<void> => {
  487. console.log("handleRefresh被触发")
  488. const now = Date.now();
  489. if (now - lastRefreshTime.value < 1000) {
  490. refreshing.value = false;
  491. return;
  492. }
  493. lastRefreshTime.value = now;
  494. if (loading.value || isRefreshing.value) {
  495. refreshing.value = false;
  496. return;
  497. }
  498. isRefreshing.value = true;
  499. try {
  500. await loadData(true, false);
  501. // 刷新完成后检查并更新任务状态
  502. await updateTaskInfoStatus();
  503. } catch (error) {
  504. console.error('刷新失败:', error);
  505. } finally {
  506. // 简单的状态重置
  507. refreshing.value = false;
  508. loading.value = false;
  509. isRefreshing.value = false;
  510. }
  511. setTimeout(() => {
  512. isRefreshing.value = false
  513. }, 100)
  514. }
  515. // 加载更多
  516. const loadMore = (): void => {
  517. if (!hasMore.value || loading.value) {
  518. return
  519. }
  520. page.value++
  521. loadData(false, false)
  522. }
  523. // 点击列表项
  524. const handleItemClick = (item: any | null, action: string): void => {
  525. if (item == null) return
  526. const deviceItem = item as DeviceCheckTaskDetail
  527. if(action == 'scan') {
  528. /* // 检查前一个任务是否已完成
  529. const currentIndex = dataList.value.findIndex(d => d.detailId == deviceItem.detailId);
  530. let canProcess = true;
  531. // 检查前面的所有任务是否都已完成
  532. for (let i = 0; i < currentIndex; i++) {
  533. if (dataList.value[i].taskStatus != 'completed') {
  534. canProcess = false;
  535. break;
  536. }
  537. }
  538. if (canProcess) { */
  539. // 跳转到任务处理页面
  540. uni.showModal({
  541. title: '开始检查',
  542. //content: `即将处理任务: ${deviceItem.machineryName} (${deviceItem.machinerySpec})`,
  543. confirmText: '确定开始',
  544. cancelText: '取消',
  545. success: (res) => {
  546. if(res.confirm) {
  547. // 跳转到设备检查页面进行任务处理
  548. /* const deviceName = deviceItem.machineryName != null ? deviceItem.machineryName : '';
  549. const deviceCode = deviceItem.machinerySpec != null ? deviceItem.machinerySpec : '';
  550. const deviceTypeText = deviceItem.machineryTypeName != null ? deviceItem.machineryTypeName : '';
  551. const location = deviceItem.locationName != null ? deviceItem.locationName : ''; */
  552. if(deviceItem.detailId != null){
  553. uni.navigateTo({
  554. url: `/pages/task/device-check?detailId=${deviceItem.detailId}`
  555. });
  556. }else{
  557. uni.showToast({
  558. title: '缺少参数',
  559. icon: 'none'
  560. })
  561. }
  562. }
  563. }
  564. });
  565. /* } else {
  566. uni.showToast({
  567. title: '请按顺序完成任务!前序任务完成后才能开始当前任务。',
  568. icon: 'none',
  569. duration: 2000
  570. });
  571. } */
  572. }
  573. if(action === 'detail') {
  574. uni.navigateTo({
  575. url: `/pages/task/device-check?detailId=${deviceItem.detailId}&opType=view`
  576. });
  577. }
  578. }
  579. // 点击列表项
  580. const handleView = (item: any | null): void => {
  581. /* if (item == null) return
  582. const deviceItem = item as deviceInfo
  583. uni.showToast({
  584. title: `设备详情: ${deviceItem.deviceName}`,
  585. icon: 'none'
  586. }); */
  587. }
  588. onLoad((options: any) => {
  589. const params = options as UTSJSONObject
  590. const taskId = params.get('taskId') as string | null
  591. // 获取传递的任务ID
  592. if (taskId != null) {
  593. currentTaskId.value = taskId
  594. // 并行加载字典、任务信息和设备清单
  595. Promise.all([
  596. loadTaskStatusDictList(),
  597. loadTaskInfo(),
  598. loadData(true, true)
  599. ]).catch(error => {
  600. console.error('加载数据失败:', error)
  601. }).finally(() => {
  602. // 确保在任何情况下都重置加载状态
  603. loading.value = false
  604. refreshing.value = false
  605. })
  606. } else {
  607. uni.showToast({
  608. title: '缺少任务ID参数',
  609. icon: 'none'
  610. })
  611. }
  612. })
  613. // 组件卸载前清理事件监听
  614. onBeforeUnmount(() => {
  615. refreshing.value = false
  616. loading.value = false
  617. isRefreshing.value = false
  618. })
  619. // 页面显示时强制重置加载状态
  620. onShow(() => {
  621. /* loading.value = false
  622. refreshing.value = false
  623. isRefreshing.value = false */
  624. // 检查是否有来自子页面的刷新标记
  625. const needRefresh = uni.getStorageSync('needRefresh')
  626. if (needRefresh == true) {
  627. // 清除标记
  628. uni.removeStorageSync('needRefresh')
  629. // 延迟一小段时间再执行刷新,避免状态冲突
  630. setTimeout(() => {
  631. loadData(true, false).then(() => {
  632. updateTaskInfoStatus()
  633. })
  634. }, 500)
  635. }
  636. // 延迟再重置一次确保生效
  637. /* setTimeout(() => {
  638. loading.value = false
  639. refreshing.value = false
  640. isRefreshing.value = false
  641. }, 500) */
  642. })
  643. // 页面卸载时设置返回标记
  644. onUnload(() => {
  645. // 设置标记通知index页面需要刷新
  646. uni.setStorageSync('needRefresh', true)
  647. })
  648. </script>
  649. <style lang="scss">
  650. .list-page {
  651. flex: 1;
  652. background-color: #e8f0f9;
  653. }
  654. .task-info-bar {
  655. padding: 20rpx 30rpx;
  656. background-color: #d7eafe;
  657. border-bottom: 1rpx solid #ccc;
  658. }
  659. .task-info-item {
  660. flex-direction: row;
  661. align-items: center;
  662. margin-bottom: 10rpx;
  663. }
  664. .task-info-label {
  665. font-size: 28rpx;
  666. color: #333;
  667. font-weight: bold;
  668. margin-right: 10rpx;
  669. }
  670. .task-info-value {
  671. font-size: 28rpx;
  672. color: #666;
  673. }
  674. .search-bar {
  675. padding: 20rpx 30rpx;
  676. background-color: #d7eafe;
  677. }
  678. .search-box {
  679. flex-direction: row;
  680. align-items: center;
  681. height: 72rpx;
  682. padding: 0 24rpx;
  683. background-color: #f5f5f5;
  684. border-radius: 36rpx;
  685. .search-icon {
  686. width: 32rpx;
  687. height: 32rpx;
  688. margin-right: 12rpx;
  689. }
  690. .search-input {
  691. flex: 1;
  692. font-size: 28rpx;
  693. color: #333333;
  694. }
  695. .clear-icon {
  696. margin-left: 12rpx;
  697. font-size: 28rpx;
  698. color: #999999;
  699. }
  700. }
  701. .list-item {
  702. margin: 12rpx 30rpx;
  703. background-color: #ffffff;
  704. border-radius: 16rpx;
  705. }
  706. .device-completed {
  707. background-color: #f0f9eb; /* 浅绿色背景表示已完成 */
  708. }
  709. .device-in-progress {
  710. background-color: #e6f4ff; /* 浅蓝色背景表示检查中 */
  711. }
  712. .device-pending {
  713. background-color: #ffffff; /* 白色背景表示待扫描 */
  714. }
  715. .btn-disabled {
  716. z-index: 999;
  717. border-radius: 10rpx;
  718. font-size: 24rpx;
  719. margin-left: 20rpx;
  720. background-color: #ccc;
  721. line-height: 45rpx;
  722. color: #999;
  723. .btn-text{
  724. color: #999;
  725. font-size: 24rpx;
  726. padding: 5px 15px;
  727. }
  728. }
  729. .item-container {
  730. padding: 30rpx;
  731. }
  732. .item-header {
  733. flex-direction: row;
  734. align-items: flex-start;
  735. margin-bottom: 16rpx;
  736. justify-content: space-between; /* 主轴两端对齐 */
  737. min-height: 55rpx;
  738. .item-title {
  739. font-size: 30rpx;
  740. color: #333333;
  741. font-weight: bold;
  742. flex-wrap: wrap;
  743. flex: 0 1 75%;
  744. min-width: 0;
  745. }
  746. .task-badges {
  747. display: flex;
  748. flex-direction: row;
  749. align-items: center;
  750. gap: 10rpx; /* 添加间距 */
  751. }
  752. }
  753. .info-row {
  754. flex-direction: row;
  755. justify-content: space-between;
  756. align-items: center;
  757. .info-label {
  758. font-size: 26rpx;
  759. color: #666;
  760. }
  761. .info-value {
  762. font-size: 26rpx;
  763. // color: #666;
  764. }
  765. }
  766. .btn-group {
  767. flex-direction: row;
  768. align-items: center;
  769. justify-content: flex-end;
  770. margin-top: 20rpx;
  771. }
  772. .btn-primary {
  773. z-index: 999;
  774. border-radius: 10rpx;
  775. font-size: 24rpx;
  776. // white-space: nowrap;
  777. margin-left: 20rpx;
  778. background-color: #165DFF;
  779. line-height: 45rpx;
  780. color: #ffffff;
  781. .btn-text{
  782. color: #ffffff;
  783. font-size: 24rpx;
  784. padding: 5px 15px;
  785. }
  786. }
  787. .btn-disabled {
  788. z-index: 999;
  789. border-radius: 10rpx;
  790. font-size: 24rpx;
  791. margin-left: 20rpx;
  792. background-color: #ccc;
  793. line-height: 45rpx;
  794. color: #999;
  795. .btn-text{
  796. color: #999;
  797. font-size: 24rpx;
  798. padding: 5px 15px;
  799. }
  800. }
  801. .status-tag {
  802. padding: 8rpx 20rpx;
  803. border-radius: 20rpx;
  804. font-size: 24rpx;
  805. white-space: nowrap;
  806. // margin-left: 50rpx;
  807. // justify-content: flex-end;
  808. border: 1rpx solid;
  809. text-align: center;
  810. }
  811. /* 设备类型样式 */
  812. .type-power {
  813. background-color: #ECF5FF;
  814. color: #409EFF;
  815. border-color: #d8ebff;
  816. }
  817. .type-cooling {
  818. background-color: #F4F4F5;
  819. color: #909399;
  820. border-color: #e9e9eb;
  821. }
  822. .type-water {
  823. background-color: #F0F9EB;
  824. color: #67C23A;
  825. border-color: #c2e7b0;
  826. }
  827. /* 设备状态样式 */
  828. .status-normal {
  829. background-color: #F0F9EB;
  830. color: #67C23A;
  831. border-color: #c2e7b0;
  832. }
  833. .status-warning {
  834. background-color: #FDF6EC;
  835. color: #E6A23C;
  836. border-color: #faecd8;
  837. }
  838. .status-danger {
  839. background-color: #FEF0F0;
  840. color: #F56C6C;
  841. border-color: #fde2e2;
  842. }
  843. /* 扫描状态样式 */
  844. .scan-completed {
  845. background-color: #F0F9EB;
  846. color: #67C23A;
  847. border-color: #c2e7b0;
  848. }
  849. .scan-pending {
  850. background-color: #FDF6EC;
  851. color: #E6A23C;
  852. border-color: #faecd8;
  853. }
  854. .scan-in-progress {
  855. background-color: #F4F4F5;
  856. color: #909399;
  857. border-color: #e9e9eb;
  858. }
  859. /* 任务类型样式 (保留兼容性) */
  860. .type-inspection {
  861. background-color: #ECF5FF;
  862. color: #409EFF;
  863. border-color: #d8ebff;
  864. }
  865. .type-patrol {
  866. background-color: #F4F4F5;
  867. color: #909399;
  868. border-color: #e9e9eb;
  869. }
  870. .type-maintenance {
  871. background-color: #F0F9EB;
  872. color: #67C23A;
  873. border-color: #c2e7b0;
  874. }
  875. /* 任务状态样式 (保留兼容性) */
  876. .status-pending {
  877. background-color: #FDF6EC;
  878. color: #E6A23C;
  879. border-color: #faecd8;
  880. }
  881. .status-completed {
  882. background-color: #F0F9EB;
  883. color: #67C23A;
  884. border-color: #c2e7b0;
  885. }
  886. .status-overdue {
  887. background-color: #FEF0F0;
  888. color: #F56C6C;
  889. border-color: #fde2e2;
  890. }
  891. /* 任务状态样式 */
  892. .taskStatus-0 {
  893. background-color: #FDF6EC;
  894. color: #E6A23C;
  895. border-color: #faecd8;
  896. }
  897. .taskStatus-1 {
  898. background-color: #EBF5FF;
  899. color: #409EFF;
  900. border-color: #d8ebff;
  901. }
  902. .taskStatus-2 {
  903. background-color: #F0F9EB;
  904. color: #67C23A;
  905. border-color: #c2e7b0;
  906. }
  907. /* 保持其他原有样式 */
  908. .text-gray{
  909. font-size: 26rpx;
  910. color: #666;
  911. }
  912. .scroll-view_H {
  913. width: 100%;
  914. flex-direction: row;
  915. }
  916. .scroll-view-item_H {
  917. justify-content: center;
  918. align-items: center;
  919. .status-txt{
  920. padding: 8px 12px;
  921. text-align: center;
  922. margin-right: 12rpx;
  923. border-radius: 36rpx;
  924. background-color: #fff;
  925. font-size: 28rpx;
  926. }
  927. .stauts-sel{
  928. background-color: #007AFF;
  929. color: #fff;
  930. }
  931. }
  932. </style>