300 lines
8.1 KiB
JavaScript
300 lines
8.1 KiB
JavaScript
/**
|
||
* 数据处理工具类
|
||
* 用于统一处理前后端数据结构差异
|
||
*
|
||
* 创建日期:2026-01-09
|
||
* 用途:避免重复的数据解析代码,提高开发效率
|
||
*/
|
||
|
||
/**
|
||
* 统一解析列表数据
|
||
* 兼容多种响应格式:
|
||
* - 直接数组:[...]
|
||
* - 带records:{ records: [...] }
|
||
* - 嵌套data:{ data: { records: [...] } }
|
||
*
|
||
* @param {*} res - 接口响应数据
|
||
* @returns {Array} 解析后的数组
|
||
*/
|
||
export function getRecords(res) {
|
||
// 1. 直接是数组
|
||
if (Array.isArray(res)) {
|
||
return res
|
||
}
|
||
|
||
// 2. res.records
|
||
if (res && res.records) {
|
||
return Array.isArray(res.records) ? res.records : []
|
||
}
|
||
|
||
// 3. res.data.records
|
||
if (res && res.data && res.data.records) {
|
||
return Array.isArray(res.data.records) ? res.data.records : []
|
||
}
|
||
|
||
// 4. res.data 是数组
|
||
if (res && res.data && Array.isArray(res.data)) {
|
||
return res.data
|
||
}
|
||
|
||
// 5. 都不是,返回空数组
|
||
console.warn('无法解析records,返回空数组', res)
|
||
return []
|
||
}
|
||
|
||
/**
|
||
* 获取字段值(兼容多种命名方式)
|
||
* 支持驼峰、下划线、首字母大写等多种命名
|
||
*
|
||
* @param {Object} obj - 对象
|
||
* @param {...string} keys - 可能的字段名(按优先级)
|
||
* @returns {*} 字段值,如果都不存在返回 null
|
||
*
|
||
* @example
|
||
* const orderNo = getField(order, 'orderNo', 'order_no', 'OrderNo')
|
||
*/
|
||
export function getField(obj, ...keys) {
|
||
if (!obj) return null
|
||
|
||
for (let key of keys) {
|
||
if (obj[key] !== undefined && obj[key] !== null) {
|
||
return obj[key]
|
||
}
|
||
}
|
||
|
||
return null
|
||
}
|
||
|
||
/**
|
||
* 获取字段值(带默认值)
|
||
*
|
||
* @param {Object} obj - 对象
|
||
* @param {*} defaultValue - 默认值
|
||
* @param {...string} keys - 可能的字段名
|
||
* @returns {*} 字段值或默认值
|
||
*
|
||
* @example
|
||
* const name = getFieldOr(user, '未知', 'name', 'userName', 'user_name')
|
||
*/
|
||
export function getFieldOr(obj, defaultValue, ...keys) {
|
||
const value = getField(obj, ...keys)
|
||
return value !== null ? value : defaultValue
|
||
}
|
||
|
||
/**
|
||
* 格式化日期时间
|
||
*
|
||
* @param {string|Date} datetime - 日期时间
|
||
* @param {string} format - 格式(默认:'YYYY-MM-DD HH:mm:ss')
|
||
* @returns {string} 格式化后的字符串
|
||
*/
|
||
export function formatDateTime(datetime, format = 'YYYY-MM-DD HH:mm:ss') {
|
||
if (!datetime) return ''
|
||
|
||
const d = new Date(datetime)
|
||
if (isNaN(d.getTime())) return ''
|
||
|
||
const year = d.getFullYear()
|
||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||
const day = String(d.getDate()).padStart(2, '0')
|
||
const hours = String(d.getHours()).padStart(2, '0')
|
||
const minutes = String(d.getMinutes()).padStart(2, '0')
|
||
const seconds = String(d.getSeconds()).padStart(2, '0')
|
||
|
||
return format
|
||
.replace('YYYY', year)
|
||
.replace('MM', month)
|
||
.replace('DD', day)
|
||
.replace('HH', hours)
|
||
.replace('mm', minutes)
|
||
.replace('ss', seconds)
|
||
}
|
||
|
||
/**
|
||
* 格式化金额
|
||
*
|
||
* @param {number|string} amount - 金额
|
||
* @param {number} decimals - 小数位数(默认:2)
|
||
* @returns {string} 格式化后的金额
|
||
*
|
||
* @example
|
||
* formatAmount(1234.5) // '1,234.50'
|
||
*/
|
||
export function formatAmount(amount, decimals = 2) {
|
||
if (amount === null || amount === undefined) return '0.00'
|
||
|
||
const num = parseFloat(amount)
|
||
if (isNaN(num)) return '0.00'
|
||
|
||
return num.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||
}
|
||
|
||
/**
|
||
* 安全的数字转换
|
||
*
|
||
* @param {*} value - 值
|
||
* @param {number} defaultValue - 默认值(默认:0)
|
||
* @returns {number} 数字
|
||
*/
|
||
export function toNumber(value, defaultValue = 0) {
|
||
if (value === null || value === undefined) return defaultValue
|
||
|
||
const num = parseFloat(value)
|
||
return isNaN(num) ? defaultValue : num
|
||
}
|
||
|
||
/**
|
||
* 安全的整数转换
|
||
*
|
||
* @param {*} value - 值
|
||
* @param {number} defaultValue - 默认值(默认:0)
|
||
* @returns {number} 整数
|
||
*/
|
||
export function toInt(value, defaultValue = 0) {
|
||
if (value === null || value === undefined) return defaultValue
|
||
|
||
const num = parseInt(value)
|
||
return isNaN(num) ? defaultValue : num
|
||
}
|
||
|
||
/**
|
||
* 解析订单数据(标准化)
|
||
*
|
||
* @param {Object} order - 原始订单数据
|
||
* @returns {Object} 标准化的订单数据
|
||
*/
|
||
export function parseOrder(order) {
|
||
if (!order) return null
|
||
|
||
return {
|
||
id: order.id,
|
||
orderNo: getFieldOr(order, `ORD${order.id}`, 'orderNo', 'order_no'),
|
||
serviceName: getFieldOr(order, '陪伴服务', 'serviceName', 'service_name', 'packageName', 'package_name'),
|
||
serviceDate: getField(order, 'serviceDate', 'service_date'),
|
||
serviceTime: getField(order, 'serviceTime', 'service_time', 'timeSlot', 'time_slot'),
|
||
studentName: getFieldOr(order, '学生', 'studentName', 'student_name', 'userName', 'user_name'),
|
||
grade: getFieldOr(order, '', 'grade'),
|
||
price: toNumber(getField(order, 'payAmount', 'pay_amount', 'price', 'amount')),
|
||
status: toInt(getField(order, 'status')),
|
||
createTime: getField(order, 'createTime', 'create_time'),
|
||
updateTime: getField(order, 'updateTime', 'update_time')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析排班数据(标准化)
|
||
*
|
||
* @param {Object} schedule - 原始排班数据
|
||
* @returns {Object} 标准化的排班数据
|
||
*/
|
||
export function parseSchedule(schedule) {
|
||
if (!schedule) return null
|
||
|
||
// 解析时间段
|
||
const timeSlot = getField(schedule, 'timeSlot', 'time_slot', 'timeRange', 'time_range') || ''
|
||
const parts = timeSlot.split('-')
|
||
const startTime = parts[0] ? parts[0].trim() : getField(schedule, 'startTime', 'start_time') || ''
|
||
const endTime = parts[1] ? parts[1].trim() : getField(schedule, 'endTime', 'end_time') || ''
|
||
|
||
// 解析状态
|
||
const status = toInt(getField(schedule, 'status'))
|
||
const statusMap = {
|
||
0: { text: '不可用', class: 'unavailable' },
|
||
1: { text: '可预约', class: 'available' },
|
||
2: { text: '已预约', class: 'booked' }
|
||
}
|
||
const statusInfo = statusMap[status] || { text: '未知', class: '' }
|
||
|
||
return {
|
||
id: schedule.id,
|
||
scheduleDate: getField(schedule, 'scheduleDate', 'schedule_date'),
|
||
startTime: startTime,
|
||
endTime: endTime,
|
||
status: statusInfo.class,
|
||
statusText: statusInfo.text,
|
||
statusValue: status
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析收益数据(标准化)
|
||
*
|
||
* @param {Object} salary - 原始收益数据
|
||
* @returns {Object} 标准化的收益数据
|
||
*/
|
||
export function parseSalary(salary) {
|
||
if (!salary) return null
|
||
|
||
// 解析状态
|
||
const status = toInt(getField(salary, 'status'))
|
||
const statusMap = {
|
||
0: '待结算',
|
||
1: '已结算',
|
||
2: '已发放'
|
||
}
|
||
|
||
return {
|
||
id: salary.id,
|
||
amount: toNumber(getField(salary, 'amount')),
|
||
actualAmount: toNumber(getField(salary, 'actualAmount', 'actual_amount')),
|
||
serviceDuration: toInt(getField(salary, 'serviceDuration', 'service_duration', 'duration')),
|
||
status: status,
|
||
statusText: statusMap[status] || '未知',
|
||
workOrderId: getField(salary, 'workOrderId', 'work_order_id'),
|
||
orderId: getField(salary, 'orderId', 'order_id'),
|
||
createTime: getField(salary, 'createTime', 'create_time'),
|
||
settlementTime: getField(salary, 'settlementTime', 'settlement_time')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量解析数据
|
||
*
|
||
* @param {Array} list - 原始数据列表
|
||
* @param {Function} parser - 解析函数
|
||
* @returns {Array} 解析后的列表
|
||
*/
|
||
export function parseList(list, parser) {
|
||
if (!Array.isArray(list)) return []
|
||
return list.map(item => parser(item)).filter(item => item !== null)
|
||
}
|
||
|
||
/**
|
||
* 调试日志(带时间戳和样式)
|
||
*
|
||
* @param {string} title - 标题
|
||
* @param {*} data - 数据
|
||
*/
|
||
export function debugLog(title, data) {
|
||
const timestamp = new Date().toLocaleTimeString()
|
||
console.log(`%c[${timestamp}] ${title}`, 'color: #4CAF50; font-weight: bold;', data)
|
||
}
|
||
|
||
/**
|
||
* 错误日志(带时间戳和样式)
|
||
*
|
||
* @param {string} title - 标题
|
||
* @param {*} error - 错误
|
||
*/
|
||
export function errorLog(title, error) {
|
||
const timestamp = new Date().toLocaleTimeString()
|
||
console.error(`%c[${timestamp}] ${title}`, 'color: #F44336; font-weight: bold;', error)
|
||
}
|
||
|
||
// 默认导出所有方法
|
||
export default {
|
||
getRecords,
|
||
getField,
|
||
getFieldOr,
|
||
formatDateTime,
|
||
formatAmount,
|
||
toNumber,
|
||
toInt,
|
||
parseOrder,
|
||
parseSchedule,
|
||
parseSalary,
|
||
parseList,
|
||
debugLog,
|
||
errorLog
|
||
}
|