area-list.uvue 27 KB

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