Files
smart-cropx-ui/src/utils/urlParams.ts
peng 68d9d97142 refactor: 优化认证系统和组件类型安全性
- 新增 safeLocalStorage 工具函数增强本地存储安全性
- 简化认证流程,重构用户数据结构和 token 管理
- 修复多个模块的 TypeScript 类型错误和导入问题
- 优化状态管理,重构各模块 store 结构
- 清理冗余代码,移除未使用的组件和函数
- 改进错误处理和边界情况处理
- 更新配置文件以支持最新的类型检查

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 14:52:52 +08:00

271 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* filekorolheader: URL参数处理工具函数 - 通用URL参数解析和优先级管理
* 功能从浏览器URL读取参数、参数优先级处理、类型安全的参数转换
* 路径:/utils/urlParams
* 规范遵循crop-x/docs/开发项目规范.mdTypeScript类型安全泛型支持
*/
// URL参数解析配置接口
export interface UrlParamsConfig<T extends Record<string, any>> {
// 搜索字段配置定义哪些字段需要从URL中读取
searchFields: {
[K in keyof T]?: {
type: 'string' | 'number' | 'boolean';
// URL参数名映射如果不配置则使用字段名
urlKey?: string;
// 默认值
default?: T[K];
// 是否必需字段
required?: boolean;
};
};
// 分页字段配置
paginationFields?: {
page?: {
urlKey?: string;
default?: number;
};
size?: {
urlKey?: string;
default?: number;
};
};
}
// URL参数解析结果接口
export interface UrlParamsResult<T extends Record<string, any>> {
// 搜索参数
searchParams: Partial<T>;
// 分页参数
paginationParams: {
page: number;
size: number;
};
// 是否包含任何URL参数
hasUrlParams: boolean;
// 原始URL参数字符串
rawUrlParams: string;
}
/**
* 通用URL参数解析函数
*
* @param config URL参数配置
* @returns 解析后的URL参数结果
*
* @example
* interface MyParams {
* search: string;
* status: string;
* category: string;
* }
*
* const config: UrlParamsConfig<MyParams> = {
* searchFields: {
* search: { type: 'string', urlKey: 'search', default: '' },
* status: { type: 'string', urlKey: 'audit_status', default: 'all' },
* category: { type: 'string', default: 'all' }
* },
* paginationFields: {
* page: { urlKey: 'page', default: 1 },
* size: { urlKey: 'size', default: 10 }
* }
* };
*
* const result = parseUrlParams(config);
* console.log(result.searchParams); // { search: 'keyword', status: 'pending', category: 'all' }
* console.log(result.paginationParams); // { page: 2, size: 20 }
*/
export function parseUrlParams<T extends Record<string, any>>(
config: UrlParamsConfig<T>
): UrlParamsResult<T> {
// 检查是否在浏览器环境
if (typeof window === 'undefined') {
return {
searchParams: {} as Partial<T>,
paginationParams: {
page: config.paginationFields?.page?.default ?? 1,
size: config.paginationFields?.size?.default ?? 10
},
hasUrlParams: false,
rawUrlParams: ''
};
}
try {
const urlParams = new URLSearchParams(window.location.search);
const rawUrlParams = urlParams.toString();
const searchParams: Partial<T> = {};
let hasUrlParams = rawUrlParams !== '';
// 解析搜索字段
Object.entries(config.searchFields).forEach(([fieldKey, fieldConfig]) => {
if (!fieldConfig) return;
const urlKey = fieldConfig.urlKey || fieldKey;
const rawValue = urlParams.get(urlKey);
if (rawValue !== null) {
let parsedValue: any = rawValue;
// 类型转换
switch (fieldConfig.type) {
case 'number':
parsedValue = parseInt(rawValue, 10);
if (isNaN(parsedValue)) {
parsedValue = fieldConfig.default;
}
break;
case 'boolean':
parsedValue = rawValue === 'true' || rawValue === '1';
break;
case 'string':
default:
parsedValue = rawValue;
break;
}
(searchParams as any)[fieldKey] = parsedValue;
} else if (fieldConfig.default !== undefined) {
(searchParams as any)[fieldKey] = fieldConfig.default;
} else if (fieldConfig.required) {
console.warn(`Required URL parameter '${urlKey}' is missing`);
}
});
// 解析分页字段
const pageValue = urlParams.get(config.paginationFields?.page?.urlKey || 'page');
const sizeValue = urlParams.get(config.paginationFields?.size?.urlKey || 'size');
const page = pageValue ? Math.max(1, parseInt(pageValue, 10) || 1) : (config.paginationFields?.page?.default ?? 1);
const size = sizeValue ? Math.max(1, parseInt(sizeValue, 10) || 10) : (config.paginationFields?.size?.default ?? 10);
const paginationParams = { page, size };
return {
searchParams,
paginationParams,
hasUrlParams,
rawUrlParams
};
} catch (error) {
console.error('Failed to parse URL parameters:', error);
return {
searchParams: {} as Partial<T>,
paginationParams: {
page: config.paginationFields?.page?.default ?? 1,
size: config.paginationFields?.size?.default ?? 10
},
hasUrlParams: false,
rawUrlParams: ''
};
}
}
/**
* 参数优先级合并函数
* 优先级URL参数 > 函数传入参数 > 默认状态
*
* @param urlParams 从URL解析的参数
* @param functionParams 函数传入的参数
* @param defaultState 默认状态
* @returns 合并后的参数
*/
export function mergeParamsWithPriority<T extends Record<string, any>>(
urlParams: Partial<T>,
functionParams: Partial<T> = {},
defaultState: T
): T {
const result = { ...defaultState };
// 先合并函数参数(第二优先级)
Object.keys(result).forEach(key => {
if (functionParams[key as keyof T] !== undefined) {
(result as any)[key] = functionParams[key as keyof T];
}
});
// 再合并URL参数第一优先级
Object.keys(urlParams).forEach(key => {
if (urlParams[key as keyof T] !== undefined && urlParams[key as keyof T] !== '') {
(result as any)[key] = urlParams[key as keyof T];
}
});
return result;
}
/**
* 分页参数优先级合并函数
*
* @param urlPagination 从URL解析的分页参数
* @param functionPagination 函数传入的分页参数
* @param defaultPagination 默认分页状态
* @param resetPage 是否重置到第一页
* @returns 合并后的分页参数
*/
export function mergePaginationWithPriority(
urlPagination: { page: number; size: number },
functionPagination: { page?: number; size?: number } = {},
defaultPagination: { page: number; size: number },
resetPage: boolean = false
): { page: number; size: number } {
const page = resetPage
? 1
: (urlPagination.page || functionPagination.page || defaultPagination.page);
const size = urlPagination.size || functionPagination.size || defaultPagination.size;
return { page: Math.max(1, page), size: Math.max(1, size) };
}
/**
* 审核历史页面专用的URL参数配置
*/
export const AUDIT_HISTORY_URL_CONFIG: UrlParamsConfig<{
search: string;
action: string;
audit_status: string;
date_range: string;
}> = {
searchFields: {
search: { type: 'string', default: '' },
action: { type: 'string', urlKey: 'action', default: 'all' },
audit_status: { type: 'string', urlKey: 'audit_status', default: 'all' },
date_range: { type: 'string', urlKey: 'date_range', default: 'all' }
},
paginationFields: {
page: { urlKey: 'page', default: 1 },
size: { urlKey: 'size', default: 10 }
}
};
/**
* 企业审核页面专用的URL参数配置
*/
export const ENTERPRISE_AUDIT_URL_CONFIG: UrlParamsConfig<{
search: string;
audit_status: string;
}> = {
searchFields: {
search: { type: 'string', default: '' },
audit_status: { type: 'string', urlKey: 'audit_status', default: 'all' }
},
paginationFields: {
page: { urlKey: 'page', default: 1 },
size: { urlKey: 'size', default: 10 }
}
};
/**
* 默认URL参数配置通用
*/
export const DEFAULT_URL_CONFIG: UrlParamsConfig<Record<string, any>> = {
searchFields: {},
paginationFields: {
page: { urlKey: 'page', default: 1 },
size: { urlKey: 'size', default: 10 }
}
};