hookehuyr

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

将多处重复的打卡任务列表字段映射逻辑提取为工具函数 normalizeCheckinTaskItems
统一处理字段映射逻辑,避免散落在各页面导致维护困难
......@@ -24,6 +24,7 @@ import { ref, computed, onMounted, provide } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import CheckInList from '@/components/ui/CheckInList.vue'
import { getTaskListAPI } from "@/api/checkin";
import { normalizeCheckinTaskItems } from '@/utils/tools'
// 签到列表
const checkInTypes = ref([]);
......@@ -81,14 +82,7 @@ const refresh_checkin_list = async () => {
const task = await getTaskListAPI()
if (task?.code) {
// 重建本地签到任务列表(当未传入 props.items_today 时用于展示)
checkInTypes.value = (task.data || []).map(item => ({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id
}))
checkInTypes.value = normalizeCheckinTaskItems(task.data)
// 向父组件透出最新数据,便于父组件自行刷新其持有的数据源
emit('check-in-data', task.data)
}
......
/*
* @Date: 2022-04-18 15:59:42
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-04-07 15:18:25
* @LastEditTime: 2026-01-21 10:51:15
* @FilePath: /mlaj/src/utils/tools.js
* @Description: 文件描述
*/
......@@ -83,30 +83,6 @@ const strExist = (array, str) => {
return exist.length > 0
}
/**
* 自定义替换参数
* @param {*} url
* @param {*} arg
* @param {*} arg_val
* @returns
*/
const changeURLArg = (url, arg, arg_val) => {
var pattern = arg + '=([^&]*)';
var replaceText = arg + '=' + arg_val;
if (url.match(pattern)) {
var tmp = '/(' + arg + '=)([^&]*)/gi';
tmp = url.replace(eval(tmp), replaceText);
return tmp;
} else {
if (url.match('[\?]')) {
return url + '&' + replaceText;
} else {
return url + '?' + replaceText;
}
}
return url + '\n' + arg + '\n' + arg_val;
}
// 获取参数key/value值对
const getUrlParams = (url) => {
// 没有参数处理
......@@ -150,14 +126,40 @@ const formatDuration = (seconds) => {
return result;
};
/**
* @description 归一化“打卡任务列表”字段,避免各页面散落 map 导致漏改。
* @param {Array<any>} list 原始任务列表(通常为接口返回 task_list/timeout_task_list)
* @returns {Array<{id: number|string, name: string, task_type: string, is_gray: boolean, is_finish: boolean, checkin_subtask_id: number|string|undefined}>}
*/
const normalizeCheckinTaskItems = (list) => {
const raw_list = Array.isArray(list) ? list : [];
return raw_list.map((item) => {
const safe_item = item || {};
const id = safe_item.id;
const name = safe_item.title || safe_item.name || '';
const task_type = safe_item.task_type || safe_item.taskType || '';
const is_gray = !!safe_item.is_gray;
const is_finish = !!safe_item.is_finish;
const checkin_subtask_id = safe_item.checkin_subtask_id || safe_item.subtask_id;
return {
id,
name,
task_type,
is_gray,
is_finish,
checkin_subtask_id
};
});
};
export {
formatDate,
wxInfo,
hasEllipsis,
parseQueryString,
strExist,
changeURLArg,
getUrlParams,
stringifyQuery,
formatDuration,
normalizeCheckinTaskItems,
};
......
......@@ -350,6 +350,7 @@ import { useImageLoader } from '@/composables/useImageLoader'
// 导入接口
import { getTaskListAPI } from "@/api/checkin";
import { normalizeCheckinTaskItems } from '@/utils/tools'
// 图片加载错误处理
const { handleImageError } = useImageLoader()
......@@ -375,14 +376,7 @@ onMounted(() => {
if (!newVal) return
const task = await getTaskListAPI()
if (task && task.code) {
checkInTypes.value = (task.data || []).map(item => ({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id
}))
checkInTypes.value = normalizeCheckinTaskItems(task.data)
}
}, { immediate: true })
})
......@@ -405,14 +399,7 @@ const handleHomeCheckInSuccess = async () => {
// 统一刷新:重新获取签到任务列表并更新置灰状态
const task = await getTaskListAPI()
if (task?.code) {
checkInTypes.value = (task.data || []).map(item => ({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id
}))
checkInTypes.value = normalizeCheckinTaskItems(task.data)
}
}
......
......@@ -330,11 +330,10 @@ import { useRoute, useRouter } from 'vue-router'
import { useCart } from '@/contexts/cart'
import { useAuth } from '@/contexts/auth'
import { useTitle } from '@vueuse/core';
import { wxInfo } from '@/utils/tools';
import { wxInfo, formatDate, normalizeCheckinTaskItems } from '@/utils/tools'
import { startWxAuth } from '@/router/guards'
import { getAuthInfoAPI, getUserIsLoginAPI } from '@/api/auth'
import { showToast, showDialog, showImagePreview } from 'vant';
import { formatDate } from '@/utils/tools'
import { sharePage } from '@/composables/useShare.js'
import { useImageLoader } from '@/composables/useImageLoader'
......@@ -748,32 +747,10 @@ onMounted(async () => {
await fetchCommentList()
// 处理task_list数据格式
if (data.task_list) {
data.task_list.forEach(item => {
task_list.value.push({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id
});
});
}
task_list.value = normalizeCheckinTaskItems(data.task_list)
// 处理timeout_task_list数据格式
if (data.timeout_task_list) {
data.timeout_task_list.forEach(item => {
timeout_task_list.value.push({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id
});
});
}
timeout_task_list.value = normalizeCheckinTaskItems(data.timeout_task_list)
// 统一弹窗组件后不再维护 default_list
......
......@@ -116,6 +116,7 @@ import { useTitle } from '@vueuse/core';
import { useRouter } from "vue-router";
import dayjs from 'dayjs';
import { showToast } from 'vant';
import { normalizeCheckinTaskItems } from '@/utils/tools'
import AppLayout from '@/components/layout/AppLayout.vue';
import CheckInDialog from '@/components/ui/CheckInDialog.vue';
......@@ -270,32 +271,10 @@ onMounted(async () => {
timeout_task_list.value = [];
// 处理task_list数据格式
if (data.task_list) {
data.task_list.forEach(item => {
task_list.value.push({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id,
});
});
}
task_list.value = normalizeCheckinTaskItems(data.task_list)
// 处理timeout_task_list数据格式
if (data.timeout_task_list) {
data.timeout_task_list.forEach(item => {
timeout_task_list.value.push({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id,
});
});
}
timeout_task_list.value = normalizeCheckinTaskItems(data.timeout_task_list)
course_lessons.value = data.schedule || [];
}
......
......@@ -247,6 +247,7 @@ import CheckInDialog from '@/components/ui/CheckInDialog.vue';
// import OfficeViewer from '@/components/ui/OfficeViewer.vue';
import dayjs from 'dayjs';
import { showToast } from 'vant';
import { normalizeCheckinTaskItems } from '@/utils/tools'
import StudyCommentsSection from '@/components/studyDetail/StudyCommentsSection.vue';
import StudyCatalogPopup from '@/components/studyDetail/StudyCatalogPopup.vue';
import StudyMaterialsPopup from '@/components/studyDetail/StudyMaterialsPopup.vue';
......@@ -704,32 +705,10 @@ onMounted(async () => {
timeout_task_list.value = [];
// 处理task_list数据格式
if (detail.data.task_list) {
detail.data.task_list.forEach(item => {
task_list.value.push({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id,
});
});
}
task_list.value = normalizeCheckinTaskItems(detail.data?.task_list)
// 处理timeout_task_list数据格式
if (detail.timeout_task_list) {
detail.timeout_task_list.forEach(item => {
timeout_task_list.value.push({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray,
is_finish: item.is_finish,
checkin_subtask_id: item.checkin_subtask_id,
});
});
}
timeout_task_list.value = normalizeCheckinTaskItems(detail.data?.timeout_task_list || detail.timeout_task_list)
// 统一弹窗组件后不再维护 default_list 与切换状态
}
......