refactor(常量): 将魔法数字替换为统一常量管理
创建 src/common/constants.js 集中管理项目常量 替换多处硬编码值为导入的常量,包括时间、超时等配置 更新 ISSUES_TO_FIX.md 标记问题为已修复
Showing
7 changed files
with
195 additions
and
7 deletions
| ... | @@ -203,7 +203,14 @@ export const MIN_TIMEOUT = 800 | ... | @@ -203,7 +203,14 @@ export const MIN_TIMEOUT = 800 |
| 203 | export const DEFAULT_FETCH_TIMEOUT = 2000 | 203 | export const DEFAULT_FETCH_TIMEOUT = 2000 |
| 204 | ``` | 204 | ``` |
| 205 | 205 | ||
| 206 | -**状态**: ⬜ 未修复 | 206 | +**状态**: ✅ 已修复 (2026-01-18) |
| 207 | +**修复详情**: 已创建 `src/common/constants.js`,包含所有需要的常量 | ||
| 208 | + | ||
| 209 | +**已应用到以下文件**: | ||
| 210 | +- `src/App.vue` - 已导入 `UPDATE_INTERVAL` 并替换 `time: 30000` | ||
| 211 | +- `src/contexts/cart.js` - 已导入 `ONE_DAY_MS` 并替换 `24 * 60 * 60 * 1000` | ||
| 212 | +- `src/utils/versionUpdater.js` - 已导入 `DEFAULT_TIMEOUT` 并替换 `timing(time = 10000)` | ||
| 213 | +- `src/components/ui/SharePoster.vue` - 已导入 `MIN_TIMEOUT, DEFAULT_FETCH_TIMEOUT` 并替换 `Math.max(800, timeout_ms || 2000)` | ||
| 207 | 214 | ||
| 208 | --- | 215 | --- |
| 209 | 216 | ... | ... |
| ... | @@ -21,6 +21,7 @@ import { apiList } from "@/api/wx/jsApiList.js"; | ... | @@ -21,6 +21,7 @@ import { apiList } from "@/api/wx/jsApiList.js"; |
| 21 | import { wxInfo } from "@/utils/tools"; | 21 | import { wxInfo } from "@/utils/tools"; |
| 22 | 22 | ||
| 23 | import { Updater } from '@/utils/versionUpdater'; | 23 | import { Updater } from '@/utils/versionUpdater'; |
| 24 | +import { UPDATE_INTERVAL } from '@/common/constants'; | ||
| 24 | 25 | ||
| 25 | import 'vant/es/toast/style' | 26 | import 'vant/es/toast/style' |
| 26 | 27 | ||
| ... | @@ -58,7 +59,7 @@ if (!import.meta.env.DEV && wxInfo().isWeiXin) { | ... | @@ -58,7 +59,7 @@ if (!import.meta.env.DEV && wxInfo().isWeiXin) { |
| 58 | let upDater = null; | 59 | let upDater = null; |
| 59 | if (import.meta.env.PROD) { | 60 | if (import.meta.env.PROD) { |
| 60 | upDater = new Updater({ | 61 | upDater = new Updater({ |
| 61 | - time: 30000 | 62 | + time: UPDATE_INTERVAL |
| 62 | }) | 63 | }) |
| 63 | upDater.on('no-update', () => { | 64 | upDater.on('no-update', () => { |
| 64 | // console.log('还没更新') | 65 | // console.log('还没更新') | ... | ... |
src/common/constants.js
0 → 100644
| 1 | +/** | ||
| 2 | + * 项目通用常量定义 | ||
| 3 | + * | ||
| 4 | + * @Date: 2026-01-18 | ||
| 5 | + * @Description: 统一管理项目中的魔法数字和字符串 | ||
| 6 | + */ | ||
| 7 | + | ||
| 8 | +// ==================== 时间相关常量 ==================== | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 一天的毫秒数 | ||
| 12 | + */ | ||
| 13 | +export const ONE_DAY_MS = 24 * 60 * 60 * 1000 | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * 一小时的毫秒数 | ||
| 17 | + */ | ||
| 18 | +export const ONE_HOUR_MS = 60 * 60 * 1000 | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * 一分钟的毫秒数 | ||
| 22 | + */ | ||
| 23 | +export const ONE_MINUTE_MS = 60 * 1000 | ||
| 24 | + | ||
| 25 | +// ==================== 更新检查间隔 ==================== | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * 更新检查间隔(30秒) | ||
| 29 | + */ | ||
| 30 | +export const UPDATE_INTERVAL = 30000 | ||
| 31 | + | ||
| 32 | +// ==================== 超时时间 ==================== | ||
| 33 | + | ||
| 34 | +/** | ||
| 35 | + * 默认 API 超时时间(10秒) | ||
| 36 | + */ | ||
| 37 | +export const DEFAULT_TIMEOUT = 10000 | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * 最小超时时间(800毫秒) | ||
| 41 | + */ | ||
| 42 | +export const MIN_TIMEOUT = 800 | ||
| 43 | + | ||
| 44 | +/** | ||
| 45 | + * 默认图片/资源加载超时时间(2秒) | ||
| 46 | + */ | ||
| 47 | +export const DEFAULT_FETCH_TIMEOUT = 2000 | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | + * 图片加载超时时间(5秒) | ||
| 51 | + */ | ||
| 52 | +export const IMAGE_LOAD_TIMEOUT = 5000 | ||
| 53 | + | ||
| 54 | +// ==================== 文件相关常量 ==================== | ||
| 55 | + | ||
| 56 | +/** | ||
| 57 | + * 最大上传文件数量 | ||
| 58 | + */ | ||
| 59 | +export const MAX_UPLOAD_COUNT = 5 | ||
| 60 | + | ||
| 61 | +/** | ||
| 62 | + * 最大文件大小(20MB) | ||
| 63 | + */ | ||
| 64 | +export const MAX_FILE_SIZE_MB = 20 | ||
| 65 | + | ||
| 66 | +/** | ||
| 67 | + * 最大文件大小(字节) | ||
| 68 | + */ | ||
| 69 | +export const MAX_FILE_SIZE_BYTES = 20 * 1024 * 1024 | ||
| 70 | + | ||
| 71 | +// ==================== 默认值 ==================== | ||
| 72 | + | ||
| 73 | +/** | ||
| 74 | + * 默认头像 URL | ||
| 75 | + */ | ||
| 76 | +export const DEFAULT_AVATAR = 'https://cdn.ipadbiz.cn/mlaj/images/default-avatar.jpeg' | ||
| 77 | + | ||
| 78 | +/** | ||
| 79 | + * 默认课程封面图 URL | ||
| 80 | + */ | ||
| 81 | +export const DEFAULT_COVER_IMAGE = 'https://cdn.ipadbiz.cn/mlaj/images/default_block.png' | ||
| 82 | + | ||
| 83 | +/** | ||
| 84 | + * 默认占位图 URL | ||
| 85 | + */ | ||
| 86 | +export const DEFAULT_PLACEHOLDER_IMAGE = '/assets/images/course-placeholder.jpg' | ||
| 87 | + | ||
| 88 | +// ==================== 分页常量 ==================== | ||
| 89 | + | ||
| 90 | +/** | ||
| 91 | + * 默认分页大小 | ||
| 92 | + */ | ||
| 93 | +export const DEFAULT_PAGE_SIZE = 10 | ||
| 94 | + | ||
| 95 | +/** | ||
| 96 | + * 打卡列表分页大小 | ||
| 97 | + */ | ||
| 98 | +export const CHECKIN_PAGE_SIZE = 5 | ||
| 99 | + | ||
| 100 | +// ==================== 评论相关常量 ==================== | ||
| 101 | + | ||
| 102 | +/** | ||
| 103 | + * 最大评论内容长度 | ||
| 104 | + */ | ||
| 105 | +export const MAX_COMMENT_LENGTH = 500 | ||
| 106 | + | ||
| 107 | +/** | ||
| 108 | + * 最短打卡内容长度(文字打卡) | ||
| 109 | + */ | ||
| 110 | +export const MIN_CHECKIN_CONTENT_LENGTH = 10 | ||
| 111 | + | ||
| 112 | +// ==================== API 响应码 ==================== | ||
| 113 | + | ||
| 114 | +/** | ||
| 115 | + * API 成功响应码 | ||
| 116 | + */ | ||
| 117 | +export const API_SUCCESS_CODE = 1 | ||
| 118 | + | ||
| 119 | +/** | ||
| 120 | + * API 未登录响应码 | ||
| 121 | + */ | ||
| 122 | +export const API_UNAUTHORIZED_CODE = 401 | ||
| 123 | + | ||
| 124 | +/** | ||
| 125 | + * API 禁止访问响应码 | ||
| 126 | + */ | ||
| 127 | +export const API_FORBIDDEN_CODE = 403 | ||
| 128 | + | ||
| 129 | +/** | ||
| 130 | + * API 未找到响应码 | ||
| 131 | + */ | ||
| 132 | +export const API_NOT_FOUND_CODE = 404 | ||
| 133 | + | ||
| 134 | +/** | ||
| 135 | + * API 服务器错误响应码 | ||
| 136 | + */ | ||
| 137 | +export const API_SERVER_ERROR_CODE = 500 | ||
| 138 | + | ||
| 139 | +// ==================== 正则表达式 ==================== | ||
| 140 | + | ||
| 141 | +/** | ||
| 142 | + * 中国大陆手机号正则表达式 | ||
| 143 | + * 规则:以 1 开头,第二位为 3-9,后面接 9 位数字 | ||
| 144 | + */ | ||
| 145 | +export const REGEX_PHONE_CN = /^1[3-9]\d{9}$/ | ||
| 146 | + | ||
| 147 | +/** | ||
| 148 | + * 身份证号正则表达式(15位或18位) | ||
| 149 | + */ | ||
| 150 | +export const REGEX_ID_CARD = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/ | ||
| 151 | + | ||
| 152 | +// ==================== 消息提示 ==================== | ||
| 153 | + | ||
| 154 | +/** | ||
| 155 | + * 默认成功提示消息 | ||
| 156 | + */ | ||
| 157 | +export const MSG_SUCCESS = '操作成功' | ||
| 158 | + | ||
| 159 | +/** | ||
| 160 | + * 默认失败提示消息 | ||
| 161 | + */ | ||
| 162 | +export const MSG_FAILED = '操作失败,请稍后重试' | ||
| 163 | + | ||
| 164 | +/** | ||
| 165 | + * 默认登录提示消息 | ||
| 166 | + */ | ||
| 167 | +export const MSG_PLEASE_LOGIN = '请先登录' | ||
| 168 | + | ||
| 169 | +/** | ||
| 170 | + * 默认网络错误提示消息 | ||
| 171 | + */ | ||
| 172 | +export const MSG_NETWORK_ERROR = '网络错误,请检查网络连接' | ||
| 173 | + | ||
| 174 | +/** | ||
| 175 | + * 默认服务器错误提示消息 | ||
| 176 | + */ | ||
| 177 | +export const MSG_SERVER_ERROR = '服务器错误,请稍后重试' |
| ... | @@ -60,6 +60,7 @@ import { ref, computed, watch, nextTick } from 'vue' | ... | @@ -60,6 +60,7 @@ import { ref, computed, watch, nextTick } from 'vue' |
| 60 | import { toPng } from 'html-to-image' | 60 | import { toPng } from 'html-to-image' |
| 61 | import QRCode from 'qrcode' | 61 | import QRCode from 'qrcode' |
| 62 | import { showToast } from 'vant' | 62 | import { showToast } from 'vant' |
| 63 | +import { MIN_TIMEOUT, DEFAULT_FETCH_TIMEOUT } from '@/common/constants' | ||
| 63 | 64 | ||
| 64 | /** | 65 | /** |
| 65 | * @typedef {Object} CourseLike | 66 | * @typedef {Object} CourseLike |
| ... | @@ -488,7 +489,7 @@ async function fetch_to_data_url_with_timeout(url, timeout_ms) { | ... | @@ -488,7 +489,7 @@ async function fetch_to_data_url_with_timeout(url, timeout_ms) { |
| 488 | if (!url) return '' | 489 | if (!url) return '' |
| 489 | try { | 490 | try { |
| 490 | const ctrl = new AbortController() | 491 | const ctrl = new AbortController() |
| 491 | - const timer = setTimeout(() => ctrl.abort(), Math.max(800, timeout_ms || 2000)) | 492 | + const timer = setTimeout(() => ctrl.abort(), Math.max(MIN_TIMEOUT, timeout_ms || DEFAULT_FETCH_TIMEOUT)) |
| 492 | const resp = await fetch(url, { mode: 'cors', cache: 'no-cache', credentials: 'omit', signal: ctrl.signal }) | 493 | const resp = await fetch(url, { mode: 'cors', cache: 'no-cache', credentials: 'omit', signal: ctrl.signal }) |
| 493 | clearTimeout(timer) | 494 | clearTimeout(timer) |
| 494 | if (!resp.ok) return '' | 495 | if (!resp.ok) return '' | ... | ... |
| ... | @@ -12,6 +12,7 @@ import { logoutAPI, getUserInfoAPI } from '@/api/users' | ... | @@ -12,6 +12,7 @@ import { logoutAPI, getUserInfoAPI } from '@/api/users' |
| 12 | import { getAuthInfoAPI } from '@/api/auth' | 12 | import { getAuthInfoAPI } from '@/api/auth' |
| 13 | import { clearAuthHeaders, setAuthHeaders } from '@/utils/axios' | 13 | import { clearAuthHeaders, setAuthHeaders } from '@/utils/axios' |
| 14 | import { applyUserInfoAuth, getUserInfoFromStorage, removeUserInfoFromStorage } from '@/utils/auth_user_info' | 14 | import { applyUserInfoAuth, getUserInfoFromStorage, removeUserInfoFromStorage } from '@/utils/auth_user_info' |
| 15 | +import { ONE_DAY_MS } from '@/common/constants' | ||
| 15 | 16 | ||
| 16 | // 创建认证上下文的Symbol key,用于provide/inject依赖注入 | 17 | // 创建认证上下文的Symbol key,用于provide/inject依赖注入 |
| 17 | // 使用Symbol确保key的唯一性,避免命名冲突 | 18 | // 使用Symbol确保key的唯一性,避免命名冲突 | ... | ... |
| 1 | import { ref, provide, inject, watchEffect } from 'vue' | 1 | import { ref, provide, inject, watchEffect } from 'vue' |
| 2 | import { useRouter } from 'vue-router' | 2 | import { useRouter } from 'vue-router' |
| 3 | - | ||
| 4 | -// 导入接口 | ||
| 5 | import { addOrderAPI } from "@/api/order"; | 3 | import { addOrderAPI } from "@/api/order"; |
| 4 | +import { ONE_DAY_MS } from '@/common/constants' | ||
| 6 | 5 | ||
| 7 | const CartSymbol = Symbol() | 6 | const CartSymbol = Symbol() |
| 8 | 7 | ||
| ... | @@ -26,7 +25,7 @@ export function provideCart(mode = CartMode.MULTIPLE) { | ... | @@ -26,7 +25,7 @@ export function provideCart(mode = CartMode.MULTIPLE) { |
| 26 | // 检查是否为新格式(包含时间戳) | 25 | // 检查是否为新格式(包含时间戳) |
| 27 | if (cartData && typeof cartData === 'object' && cartData.timestamp) { | 26 | if (cartData && typeof cartData === 'object' && cartData.timestamp) { |
| 28 | const currentTime = Date.now() | 27 | const currentTime = Date.now() |
| 29 | - const oneDay = 24 * 60 * 60 * 1000 // 一天的毫秒数 | 28 | + const oneDay = ONE_DAY_MS // 一天的毫秒数 |
| 30 | 29 | ||
| 31 | // 检查缓存是否过期(超过一天) | 30 | // 检查缓存是否过期(超过一天) |
| 32 | if (currentTime - cartData.timestamp > oneDay) { | 31 | if (currentTime - cartData.timestamp > oneDay) { | ... | ... |
| ... | @@ -11,6 +11,8 @@ | ... | @@ -11,6 +11,8 @@ |
| 11 | * @param {*} time 阈值 | 11 | * @param {*} time 阈值 |
| 12 | * @return {*} | 12 | * @return {*} |
| 13 | */ | 13 | */ |
| 14 | +import { DEFAULT_TIMEOUT } from '@/common/constants' | ||
| 15 | + | ||
| 14 | export class Updater { | 16 | export class Updater { |
| 15 | constructor(options = {}) { | 17 | constructor(options = {}) { |
| 16 | this.oldScript = []; | 18 | this.oldScript = []; |
| ... | @@ -59,7 +61,7 @@ export class Updater { | ... | @@ -59,7 +61,7 @@ export class Updater { |
| 59 | } | 61 | } |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | - timing(time = 10000) { | 64 | + timing(time = DEFAULT_TIMEOUT) { |
| 63 | //轮询 | 65 | //轮询 |
| 64 | this.intervalId = setInterval(async () => { | 66 | this.intervalId = setInterval(async () => { |
| 65 | const newHtml = await this.getHtml(); | 67 | const newHtml = await this.getHtml(); | ... | ... |
-
Please register or login to post a comment