area-list.uvue 27 KB

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