166 lines
4.6 KiB
JavaScript
166 lines
4.6 KiB
JavaScript
/**
|
||
* 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
|
||
}
|
||
|