refactor(utils): 提取打卡任务列表归一化函数并复用
将多处重复的打卡任务列表字段映射逻辑提取为工具函数 normalizeCheckinTaskItems 统一处理字段映射逻辑,避免散落在各页面导致维护困难
Showing
6 changed files
with
42 additions
and
124 deletions
| ... | @@ -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 | } | ... | ... |
-
Please register or login to post a comment