hookehuyr

refactor(utils): 提取打卡任务列表归一化函数并复用

将多处重复的打卡任务列表字段映射逻辑提取为工具函数 normalizeCheckinTaskItems
统一处理字段映射逻辑,避免散落在各页面导致维护困难
...@@ -24,6 +24,7 @@ import { ref, computed, onMounted, provide } from 'vue' ...@@ -24,6 +24,7 @@ import { ref, computed, onMounted, provide } from 'vue'
24 import { useRoute, useRouter } from 'vue-router' 24 import { useRoute, useRouter } from 'vue-router'
25 import CheckInList from '@/components/ui/CheckInList.vue' 25 import CheckInList from '@/components/ui/CheckInList.vue'
26 import { getTaskListAPI } from "@/api/checkin"; 26 import { getTaskListAPI } from "@/api/checkin";
27 +import { normalizeCheckinTaskItems } from '@/utils/tools'
27 28
28 // 签到列表 29 // 签到列表
29 const checkInTypes = ref([]); 30 const checkInTypes = ref([]);
...@@ -81,14 +82,7 @@ const refresh_checkin_list = async () => { ...@@ -81,14 +82,7 @@ const refresh_checkin_list = async () => {
81 const task = await getTaskListAPI() 82 const task = await getTaskListAPI()
82 if (task?.code) { 83 if (task?.code) {
83 // 重建本地签到任务列表(当未传入 props.items_today 时用于展示) 84 // 重建本地签到任务列表(当未传入 props.items_today 时用于展示)
84 - checkInTypes.value = (task.data || []).map(item => ({ 85 + checkInTypes.value = normalizeCheckinTaskItems(task.data)
85 - id: item.id,
86 - name: item.title,
87 - task_type: item.task_type,
88 - is_gray: item.is_gray,
89 - is_finish: item.is_finish,
90 - checkin_subtask_id: item.checkin_subtask_id
91 - }))
92 // 向父组件透出最新数据,便于父组件自行刷新其持有的数据源 86 // 向父组件透出最新数据,便于父组件自行刷新其持有的数据源
93 emit('check-in-data', task.data) 87 emit('check-in-data', task.data)
94 } 88 }
......
1 /* 1 /*
2 * @Date: 2022-04-18 15:59:42 2 * @Date: 2022-04-18 15:59:42
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-04-07 15:18:25 4 + * @LastEditTime: 2026-01-21 10:51:15
5 * @FilePath: /mlaj/src/utils/tools.js 5 * @FilePath: /mlaj/src/utils/tools.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -83,30 +83,6 @@ const strExist = (array, str) => { ...@@ -83,30 +83,6 @@ const strExist = (array, str) => {
83 return exist.length > 0 83 return exist.length > 0
84 } 84 }
85 85
86 -/**
87 - * 自定义替换参数
88 - * @param {*} url
89 - * @param {*} arg
90 - * @param {*} arg_val
91 - * @returns
92 - */
93 -const changeURLArg = (url, arg, arg_val) => {
94 - var pattern = arg + '=([^&]*)';
95 - var replaceText = arg + '=' + arg_val;
96 - if (url.match(pattern)) {
97 - var tmp = '/(' + arg + '=)([^&]*)/gi';
98 - tmp = url.replace(eval(tmp), replaceText);
99 - return tmp;
100 - } else {
101 - if (url.match('[\?]')) {
102 - return url + '&' + replaceText;
103 - } else {
104 - return url + '?' + replaceText;
105 - }
106 - }
107 - return url + '\n' + arg + '\n' + arg_val;
108 -}
109 -
110 // 获取参数key/value值对 86 // 获取参数key/value值对
111 const getUrlParams = (url) => { 87 const getUrlParams = (url) => {
112 // 没有参数处理 88 // 没有参数处理
...@@ -150,14 +126,40 @@ const formatDuration = (seconds) => { ...@@ -150,14 +126,40 @@ const formatDuration = (seconds) => {
150 return result; 126 return result;
151 }; 127 };
152 128
129 +/**
130 + * @description 归一化“打卡任务列表”字段,避免各页面散落 map 导致漏改。
131 + * @param {Array<any>} list 原始任务列表(通常为接口返回 task_list/timeout_task_list)
132 + * @returns {Array<{id: number|string, name: string, task_type: string, is_gray: boolean, is_finish: boolean, checkin_subtask_id: number|string|undefined}>}
133 + */
134 +const normalizeCheckinTaskItems = (list) => {
135 + const raw_list = Array.isArray(list) ? list : [];
136 + return raw_list.map((item) => {
137 + const safe_item = item || {};
138 + const id = safe_item.id;
139 + const name = safe_item.title || safe_item.name || '';
140 + const task_type = safe_item.task_type || safe_item.taskType || '';
141 + const is_gray = !!safe_item.is_gray;
142 + const is_finish = !!safe_item.is_finish;
143 + const checkin_subtask_id = safe_item.checkin_subtask_id || safe_item.subtask_id;
144 + return {
145 + id,
146 + name,
147 + task_type,
148 + is_gray,
149 + is_finish,
150 + checkin_subtask_id
151 + };
152 + });
153 +};
154 +
153 export { 155 export {
154 formatDate, 156 formatDate,
155 wxInfo, 157 wxInfo,
156 hasEllipsis, 158 hasEllipsis,
157 parseQueryString, 159 parseQueryString,
158 strExist, 160 strExist,
159 - changeURLArg,
160 getUrlParams, 161 getUrlParams,
161 stringifyQuery, 162 stringifyQuery,
162 formatDuration, 163 formatDuration,
164 + normalizeCheckinTaskItems,
163 }; 165 };
......
...@@ -350,6 +350,7 @@ import { useImageLoader } from '@/composables/useImageLoader' ...@@ -350,6 +350,7 @@ import { useImageLoader } from '@/composables/useImageLoader'
350 350
351 // 导入接口 351 // 导入接口
352 import { getTaskListAPI } from "@/api/checkin"; 352 import { getTaskListAPI } from "@/api/checkin";
353 +import { normalizeCheckinTaskItems } from '@/utils/tools'
353 354
354 // 图片加载错误处理 355 // 图片加载错误处理
355 const { handleImageError } = useImageLoader() 356 const { handleImageError } = useImageLoader()
...@@ -375,14 +376,7 @@ onMounted(() => { ...@@ -375,14 +376,7 @@ onMounted(() => {
375 if (!newVal) return 376 if (!newVal) return
376 const task = await getTaskListAPI() 377 const task = await getTaskListAPI()
377 if (task && task.code) { 378 if (task && task.code) {
378 - checkInTypes.value = (task.data || []).map(item => ({ 379 + checkInTypes.value = normalizeCheckinTaskItems(task.data)
379 - id: item.id,
380 - name: item.title,
381 - task_type: item.task_type,
382 - is_gray: item.is_gray,
383 - is_finish: item.is_finish,
384 - checkin_subtask_id: item.checkin_subtask_id
385 - }))
386 } 380 }
387 }, { immediate: true }) 381 }, { immediate: true })
388 }) 382 })
...@@ -405,14 +399,7 @@ const handleHomeCheckInSuccess = async () => { ...@@ -405,14 +399,7 @@ const handleHomeCheckInSuccess = async () => {
405 // 统一刷新:重新获取签到任务列表并更新置灰状态 399 // 统一刷新:重新获取签到任务列表并更新置灰状态
406 const task = await getTaskListAPI() 400 const task = await getTaskListAPI()
407 if (task?.code) { 401 if (task?.code) {
408 - checkInTypes.value = (task.data || []).map(item => ({ 402 + checkInTypes.value = normalizeCheckinTaskItems(task.data)
409 - id: item.id,
410 - name: item.title,
411 - task_type: item.task_type,
412 - is_gray: item.is_gray,
413 - is_finish: item.is_finish,
414 - checkin_subtask_id: item.checkin_subtask_id
415 - }))
416 } 403 }
417 } 404 }
418 405
......
...@@ -330,11 +330,10 @@ import { useRoute, useRouter } from 'vue-router' ...@@ -330,11 +330,10 @@ import { useRoute, useRouter } from 'vue-router'
330 import { useCart } from '@/contexts/cart' 330 import { useCart } from '@/contexts/cart'
331 import { useAuth } from '@/contexts/auth' 331 import { useAuth } from '@/contexts/auth'
332 import { useTitle } from '@vueuse/core'; 332 import { useTitle } from '@vueuse/core';
333 -import { wxInfo } from '@/utils/tools'; 333 +import { wxInfo, formatDate, normalizeCheckinTaskItems } from '@/utils/tools'
334 import { startWxAuth } from '@/router/guards' 334 import { startWxAuth } from '@/router/guards'
335 import { getAuthInfoAPI, getUserIsLoginAPI } from '@/api/auth' 335 import { getAuthInfoAPI, getUserIsLoginAPI } from '@/api/auth'
336 import { showToast, showDialog, showImagePreview } from 'vant'; 336 import { showToast, showDialog, showImagePreview } from 'vant';
337 -import { formatDate } from '@/utils/tools'
338 import { sharePage } from '@/composables/useShare.js' 337 import { sharePage } from '@/composables/useShare.js'
339 import { useImageLoader } from '@/composables/useImageLoader' 338 import { useImageLoader } from '@/composables/useImageLoader'
340 339
...@@ -748,32 +747,10 @@ onMounted(async () => { ...@@ -748,32 +747,10 @@ onMounted(async () => {
748 await fetchCommentList() 747 await fetchCommentList()
749 748
750 // 处理task_list数据格式 749 // 处理task_list数据格式
751 - if (data.task_list) { 750 + task_list.value = normalizeCheckinTaskItems(data.task_list)
752 - data.task_list.forEach(item => {
753 - task_list.value.push({
754 - id: item.id,
755 - name: item.title,
756 - task_type: item.task_type,
757 - is_gray: item.is_gray,
758 - is_finish: item.is_finish,
759 - checkin_subtask_id: item.checkin_subtask_id
760 - });
761 - });
762 - }
763 751
764 // 处理timeout_task_list数据格式 752 // 处理timeout_task_list数据格式
765 - if (data.timeout_task_list) { 753 + timeout_task_list.value = normalizeCheckinTaskItems(data.timeout_task_list)
766 - data.timeout_task_list.forEach(item => {
767 - timeout_task_list.value.push({
768 - id: item.id,
769 - name: item.title,
770 - task_type: item.task_type,
771 - is_gray: item.is_gray,
772 - is_finish: item.is_finish,
773 - checkin_subtask_id: item.checkin_subtask_id
774 - });
775 - });
776 - }
777 754
778 // 统一弹窗组件后不再维护 default_list 755 // 统一弹窗组件后不再维护 default_list
779 756
......
...@@ -116,6 +116,7 @@ import { useTitle } from '@vueuse/core'; ...@@ -116,6 +116,7 @@ import { useTitle } from '@vueuse/core';
116 import { useRouter } from "vue-router"; 116 import { useRouter } from "vue-router";
117 import dayjs from 'dayjs'; 117 import dayjs from 'dayjs';
118 import { showToast } from 'vant'; 118 import { showToast } from 'vant';
119 +import { normalizeCheckinTaskItems } from '@/utils/tools'
119 import AppLayout from '@/components/layout/AppLayout.vue'; 120 import AppLayout from '@/components/layout/AppLayout.vue';
120 import CheckInDialog from '@/components/ui/CheckInDialog.vue'; 121 import CheckInDialog from '@/components/ui/CheckInDialog.vue';
121 122
...@@ -270,32 +271,10 @@ onMounted(async () => { ...@@ -270,32 +271,10 @@ onMounted(async () => {
270 timeout_task_list.value = []; 271 timeout_task_list.value = [];
271 272
272 // 处理task_list数据格式 273 // 处理task_list数据格式
273 - if (data.task_list) { 274 + task_list.value = normalizeCheckinTaskItems(data.task_list)
274 - data.task_list.forEach(item => {
275 - task_list.value.push({
276 - id: item.id,
277 - name: item.title,
278 - task_type: item.task_type,
279 - is_gray: item.is_gray,
280 - is_finish: item.is_finish,
281 - checkin_subtask_id: item.checkin_subtask_id,
282 - });
283 - });
284 - }
285 275
286 // 处理timeout_task_list数据格式 276 // 处理timeout_task_list数据格式
287 - if (data.timeout_task_list) { 277 + timeout_task_list.value = normalizeCheckinTaskItems(data.timeout_task_list)
288 - data.timeout_task_list.forEach(item => {
289 - timeout_task_list.value.push({
290 - id: item.id,
291 - name: item.title,
292 - task_type: item.task_type,
293 - is_gray: item.is_gray,
294 - is_finish: item.is_finish,
295 - checkin_subtask_id: item.checkin_subtask_id,
296 - });
297 - });
298 - }
299 278
300 course_lessons.value = data.schedule || []; 279 course_lessons.value = data.schedule || [];
301 } 280 }
......
...@@ -247,6 +247,7 @@ import CheckInDialog from '@/components/ui/CheckInDialog.vue'; ...@@ -247,6 +247,7 @@ import CheckInDialog from '@/components/ui/CheckInDialog.vue';
247 // import OfficeViewer from '@/components/ui/OfficeViewer.vue'; 247 // import OfficeViewer from '@/components/ui/OfficeViewer.vue';
248 import dayjs from 'dayjs'; 248 import dayjs from 'dayjs';
249 import { showToast } from 'vant'; 249 import { showToast } from 'vant';
250 +import { normalizeCheckinTaskItems } from '@/utils/tools'
250 import StudyCommentsSection from '@/components/studyDetail/StudyCommentsSection.vue'; 251 import StudyCommentsSection from '@/components/studyDetail/StudyCommentsSection.vue';
251 import StudyCatalogPopup from '@/components/studyDetail/StudyCatalogPopup.vue'; 252 import StudyCatalogPopup from '@/components/studyDetail/StudyCatalogPopup.vue';
252 import StudyMaterialsPopup from '@/components/studyDetail/StudyMaterialsPopup.vue'; 253 import StudyMaterialsPopup from '@/components/studyDetail/StudyMaterialsPopup.vue';
...@@ -704,32 +705,10 @@ onMounted(async () => { ...@@ -704,32 +705,10 @@ onMounted(async () => {
704 timeout_task_list.value = []; 705 timeout_task_list.value = [];
705 706
706 // 处理task_list数据格式 707 // 处理task_list数据格式
707 - if (detail.data.task_list) { 708 + task_list.value = normalizeCheckinTaskItems(detail.data?.task_list)
708 - detail.data.task_list.forEach(item => {
709 - task_list.value.push({
710 - id: item.id,
711 - name: item.title,
712 - task_type: item.task_type,
713 - is_gray: item.is_gray,
714 - is_finish: item.is_finish,
715 - checkin_subtask_id: item.checkin_subtask_id,
716 - });
717 - });
718 - }
719 709
720 // 处理timeout_task_list数据格式 710 // 处理timeout_task_list数据格式
721 - if (detail.timeout_task_list) { 711 + timeout_task_list.value = normalizeCheckinTaskItems(detail.data?.timeout_task_list || detail.timeout_task_list)
722 - detail.timeout_task_list.forEach(item => {
723 - timeout_task_list.value.push({
724 - id: item.id,
725 - name: item.title,
726 - task_type: item.task_type,
727 - is_gray: item.is_gray,
728 - is_finish: item.is_finish,
729 - checkin_subtask_id: item.checkin_subtask_id,
730 - });
731 - });
732 - }
733 712
734 // 统一弹窗组件后不再维护 default_list 与切换状态 713 // 统一弹窗组件后不再维护 default_list 与切换状态
735 } 714 }
......