/** * URL构建工具 * 统一处理查询参数的构建,支持数组、对象、特殊字符编码等 */ /** * 构建带查询参数的URL * @param {string} basePath - 基础路径(如 'bst/task/list') * @param {Object} params - 查询参数对象 * @param {Object} options - 配置选项 * @param {boolean} options.encodeValues - 是否对值进行URL编码(默认true) * @param {boolean} options.skipEmpty - 是否跳过空值(默认true) * @param {string} options.arrayFormat - 数组格式:'repeat'(重复参数)或 'bracket'(带索引),默认'repeat' * @returns {string} 完整的URL字符串 * * @example * // 基础用法 * buildUrl('bst/task/list', { pageNum: 1, pageSize: 10 }) * // => 'bst/task/list?pageNum=1&pageSize=10' * * @example * // 数组参数(重复格式) * buildUrl('bst/task/list', { statusList: [1, 2, 3] }) * // => 'bst/task/list?statusList=1&statusList=2&statusList=3' * * @example * // 数组参数(带索引格式) * buildUrl('bst/project/list', { keys: ['key1', 'key2'] }, { arrayFormat: 'bracket' }) * // => 'bst/project/list?keys[0]=key1&keys[1]=key2' * * @example * // 包含特殊字符 * buildUrl('bst/task/list', { orderByColumn: 'create time', isAsc: 'ascending' }) * // => 'bst/task/list?orderByColumn=create%20time&isAsc=ascending' */ export function buildUrl(basePath, params = {}, options = {}) { const { encodeValues = true, skipEmpty = true, arrayFormat = 'repeat' // 'repeat' | 'bracket' } = options // 如果没有参数,直接返回基础路径 if (!params || Object.keys(params).length === 0) { return basePath } const queryParams = [] /** * 编码值 * @param {any} value - 要编码的值 * @returns {string} 编码后的字符串 */ const encodeValue = (value) => { if (encodeValues) { return encodeURIComponent(String(value)) } return String(value) } /** * 添加查询参数 * @param {string} key - 参数名 * @param {any} value - 参数值 */ const addParam = (key, value) => { // 跳过空值 if (skipEmpty && (value === null || value === undefined || value === '')) { return } const encodedKey = encodeURIComponent(key) // 处理数组 if (Array.isArray(value)) { if (value.length === 0) return value.forEach((item, index) => { // 跳过数组中的空值 if (skipEmpty && (item === null || item === undefined || item === '')) { return } if (arrayFormat === 'bracket') { // 带索引格式:keys[0]=value1 queryParams.push(`${encodedKey}[${index}]=${encodeValue(item)}`) } else { // 重复格式:key=value1&key=value2 queryParams.push(`${encodedKey}=${encodeValue(item)}`) } }) return } // 处理对象(转换为JSON字符串) if (typeof value === 'object' && value !== null) { queryParams.push(`${encodedKey}=${encodeValue(JSON.stringify(value))}`) return } // 处理布尔值 if (typeof value === 'boolean') { queryParams.push(`${encodedKey}=${value}`) return } // 处理普通值 queryParams.push(`${encodedKey}=${encodeValue(value)}`) } // 遍历所有参数 Object.entries(params).forEach(([key, value]) => { addParam(key, value) }) // 构建查询字符串 const queryString = queryParams.length > 0 ? `?${queryParams.join('&')}` : '' return `${basePath}${queryString}` } /** * 合并默认参数和用户参数 * @param {Object} defaultParams - 默认参数 * @param {Object} userParams - 用户传入的参数 * @returns {Object} 合并后的参数对象(用户参数优先) * * @example * mergeParams({ pageNum: 1, pageSize: 10 }, { pageNum: 2 }) * // => { pageNum: 2, pageSize: 10 } */ export function mergeParams(defaultParams = {}, userParams = {}) { return { ...defaultParams, ...userParams } } /** * 从URL中提取查询参数 * @param {string} url - 完整URL或查询字符串 * @returns {Object} 参数对象 * * @example * parseUrl('bst/task/list?pageNum=1&pageSize=10') * // => { pageNum: '1', pageSize: '10' } */ export function parseUrl(url) { const params = {} try { const queryString = url.includes('?') ? url.split('?')[1] : url if (!queryString) return params queryString.split('&').forEach(param => { const [key, value] = param.split('=') if (key) { params[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '' } }) } catch (error) { console.error('解析URL参数失败:', error) } return params }