# 数据格式化

# JSON数据格式化

const todayILearn = {
  _id: 1,
  content: '今天学习 JSON.stringify(),我很开心!',
  created_at: 'Mon Nov 25 2019 14:03:55 GMT+0800 (中国标准时间)',
  updated_at: 'Mon Nov 25 2019 16:03:55 GMT+0800 (中国标准时间)'
}

将上面这个对象处理成下面这个对象

const todayILearn = {
  id: 1,
  content: '今天学习 JSON.stringify(),我很开心!',
  createdAt: 'Mon Nov 25 2019 14:03:55 GMT+0800 (中国标准时间)',
  updatedAt: 'Mon Nov 25 2019 16:03:55 GMT+0800 (中国标准时间)'
}

也就是在不改变属性的值的前提下,将对象属性修改一下。 把_id 改成 id,把 updated_at 改成 updatedAt,把 created_at 改成 createdAt

# 方案:序列化+ replace 美学典范

const mapObj = {
  _id: "id",
  created_at: "createdAt",
  updated_at: "updatedAt"
};
JSON.parse(
  JSON.stringify(todayILearn).replace(
    /_id|created_at|updated_at/gi,
    matched => mapObj[matched]
  )
)

// { 
// id: 1,
//  content: '今天学习 JSON.stringify(),我很开心!',
//  createdAt: 'Mon Nov 25 2019 14:03:55 GMT+0800 (中国标准时间)',
//  updatedAt: 'Mon Nov 25 2019 16:03:55 GMT+0800 (中国标准时间)' 
// }

# 接口数据格式化

# 约定

要明确所有的接口格式都要如下返回:

{
	status: 200,
	code: 10000,
  message: '',
  data: {
  	...
  },
}

# 处理数据

credit.js

import dayjs from 'dayjs'
import { apiRequest as Axios, courseRequest } from '@@/utils/axios'
import { injectRowKey } from '@@/utils/rowKey'
import { getCreateTime } from '@@/utils/format'
import { decodeUniqueId } from '@@/utils/crypto'

const decodeName = code => {
  switch (code) {
    case 'finance_quotient_course_study_add_200':
      return '学习课程'
    case 'finance_quotient_course_notes_add_200':
      return '写笔记'
    case 'finance_quotient_course_praxis_add_200':
      return '做测试题'
    case 'finance_quotient_transfer_1_ratio':
      return '历史积分导入'
    case 'finance_quotient_course_note_share_add_400':
      return '分享笔记'
    case 'finance_quotient_exchange_subtract_1_ratio':
      return '积分兑换'
  }
}

const creditFormat = item => {
  return {
    name: decodeName(item.creditRuleCode),
    createdAt: item.createdAt || new Date().valueOf(),
    createdTime: getCreateTime(item.createdAt * 1000),
    action: item.action,
    amount: item.amount,
    tradeNumber: item.tradeNumber,
    isValid: item.isValid === 1, // 0-无效,1-有效
  }
}

class CreditService {
	async list(pageNum = 1, pageSize = 10) {
    const {
      data: { items = [], total },
    } = await Axios.get('/user-center/credit/transactions', {
      params: {
        pageNum,
        pageSize,
        creditTypeCode: 'fq_credit',
      },
    })
    const list = items.map(creditFormat)

    return { items: injectRowKey(list), total: total || items.length }
  }
}
export default new CreditService()

# 调用

import creditService from '@@/services/credit'


action = {
  handleFetch: async () => {
    const { items, total } = await creditService.list(current.pageNum, pageSize)
    this.setState({
      ...
    })
  },
}

# 依赖

rowKey.js

import UUID from 'uuid'

// 设置数据唯一标识
export const setRowKey = data => {
  return Object.assign({ rowKey: UUID() }, data)
}

// 数组遍历设置唯一标识
export const injectRowKey = dataSource => {
  return Array.isArray(dataSource) ? dataSource.map(setRowKey) : []
}

format.js

import dayjs from 'dayjs'

const currentYear = new Date().getFullYear()
const startDay = new Date(new Date().toLocaleDateString()).valueOf()
const endDay = startDay + 24 * 60 * 60 * 1000

const timeFormatList = [
  {
    check: time => time >= startDay && time < endDay,
    render: time => '今天 ' + dayjs(time).format('HH:mm'),
  },
  {
    check: time => dayjs(time).year() === currentYear,
    render: time => dayjs(time).format('MM-DD HH:mm'),
  },
  {
    check: () => true,
    render: time => dayjs(time).format('YYYY-MM-DD HH:mm'),
  },
]

export const getCreateTime = createdAt => {
  const format = timeFormatList.find(item => {
    if (item.check(createdAt)) {
      return item
    }
  })
  return format.render(createdAt)
}

export const timeFormat = time => {
  const thisYear = dayjs(time).year()
  if (thisYear === currentYear) {
    return dayjs(time).format('M月DD日')
  } else {
    return dayjs(time).format('YYYY年M月DD日')
  }
}

const checkList = [
  {
    check: value => value >= 1000 * 10000,
    format: value => '999万+',
  },
  {
    check: value => value >= 10000,
    format: value => {
      const result = Math.round(+value / 10000)
      if (result === 1000) {
        return '999万+'
      }
      return `${result}`
    },
  },
  {
    check: value => value >= 0,
    format: value => value,
  },
]

// 数字格式化
export const numberFormat = number => {
  const checker = checkList.find(item => item.check(number))
  return checker.format(number)
}

// 商品价格格式化
export const priceFormat = (price = 0, precison = 2) => {
  price = Number(price) || 0
  return +price.toFixed(precison)
}

// 收益率格式化
export const profitRateFormat = (profitRate = 0) => {
  return (profitRate * 100).toFixed(2) + '%'
}

// 有符号收益率格式化
export const signedProfitRateFormat = (profitRate = 0) => {
  if (profitRate > 0) {
    return `+${(profitRate * 100).toFixed(2)}%`
  } else {
    return `${(profitRate * 100).toFixed(2)}%`
  }
}

// 百分比格式化
export const percentageFormat = (number = 0) => {
  return Math.round(number * 100) + '%'
}

crypto.js

// 课程资源自定义编号拼接
export const encodeUniqueId = (productId, chapterId, resourceId) => {
  return [productId, chapterId, resourceId].join('-')
}

// 课程资源自定义编号解析
export const decodeUniqueId = uniqueId => {
  const [productId, chapterId, resourceId] = uniqueId.split('-')
  return [productId, chapterId, resourceId].map(item => parseInt(item, 10))
}

// 课程资源自定义编号解析
export const parseUniqueId = uniqueId => {
  const [productId, chapterId, resourceId] = uniqueId.split('-').map(item => parseInt(item, 10))
  return { productId, chapterId, resourceId }
}

// 原生交互数据编码
export const encodeHybrid = data => {
  const payload = Object.assign({}, data)
  return btoa(encodeURIComponent(JSON.stringify(payload)))
}

// 原生交互数据解码
export const decodeHybrid = str => {
  try {
    return JSON.parse(decodeURIComponent(atob(str)))
  } catch (error) {
    console.warn(error)
    return {}
  }
}

# 参考

  1. 你不知道的 JSON.stringify() 的威力 (opens new window)