# 数据处理

# Dataflow

接下来我们重点了解一下 Vue Admin Next 中的数据处理流程。在中后台系统中,与服务器端的数据交互是项目中的重中之重。为了避免将大量业务逻辑耦合在视图层中,Vue Admin Next 设计了一套基于 DAO(Data Access Object,数据访问对象)、Model(模型)、Service(服务)的数据处理流程,同时还可以通过 Log(日志)模块打印关键信息至控制台或上报至日志服务器。Vue Admin Next 将这个流程命名为 Dataflow

# Log

Log 类提供打印日志的基础功能。底层引用了 consola 类库,可自定义不同的 Reporter,默认采用全局 console 模块进行打印。

详细代码参见 src/base/log/index.js

# 日志格式

项目中约定采用以下格式打印日志:

this.$logger.log('[methodName]', '[label1]', value1, '[label2]', value2)

第一个参数为方法名,使用括号 [] 标注。其后应该是成对的名称(label)+ 值(value)的组合,名称同样使用括号 [] 标注。

# DAO

DAO 用于从服务器端获取原始数据,定义了接口访问的 URL、请求方式、参数格式等。

TIP

一般情况下 DAO 都需要结合 Model 及 Service 进行使用。但是如果数据非常简单明确并且无需处理,则可以直接调用 DAO。

# DAO 基类

DAO 默认封装了 axioscheckCode 方法,可根据不同的接口提供方在业务类中进行修改或覆盖。

详细代码参见 src/base/dao/index.js

# DAO 业务类

import Dao from '@/base/dao'

class UserDao extends Dao {
  async login(options = {}) {
    // 记录日志
    this.$logger.log('[login]', '[options]', options)

    return this.axios({
      url: '/api/login',
      method: 'post',
      ...options,
    })
  }
}

export default UserDao

# Model

Model 用于定义数据模型,提供基于字段的格式化方法等操作。本项目封装了 CollectionEntity 两种常用的数据处理模型。

详细代码参见

  • src/base/model/collection.js
  • src/base/model/entity.js

简单 Entity 定义示例:

import { merge } from 'lodash'
import { Entity } from '@/base/model'

const defaultOptions = {
  formatters: {
    name(value) {
      return `${value}${Math.random().toFixed(2)}`
    },
  },
}

class User extends Entity {
  constructor(data = {}, options = {}) {
    options = merge({}, defaultOptions, options)
    super(data, options)
  }
}

export default User

简单 Collection 定义示例:
























 


import { merge } from 'lodash'
import { Entity, Collection } from '@/base/model'

const defaultOptions = {
  formatters: {
    title(value) {
      return `V - ${value || 'Unknown'}`
    },
  },
}

class ExampleEntity extends Entity {
  constructor(data, options = {}) {
    options = merge({}, defaultOptions, options)
    super(data, options)
  }
}

class ExampleList extends Collection {
  constructor(list = [], entity = ExampleEntity, options = {}) {
    super(list, entity, options)
  }
}

export default ExampleList

# Service

Service 用于整合整体流程并处理业务逻辑。一般情况下,DAO 的调用和 Model 的创建都是在 Service 中进行的;此外,它可能会包含以下几种操作:

  • 对模型进行附加处理,如添加字段、拆分字段、整合字段、异步处理等
  • 将一个复杂模型拆分为几个子模型
  • 将几个子模型合并为一个复杂模型
  • 封装同时调用多个接口的逻辑(如一次保存操作包含多方接口调用)

# Service 基类

详细代码参见 src/base/service/index.js

# Service 业务类










 

















 












import Service from '@/base/service'

class SomeService extends Service {
  someEntity = null

  // set 操作,初始化为 Model 并执行附加格式化等
  async setSomeEntity(entity) {
    const { SomeEntity } = this.dataflow.models

    this.someEntity = new SomeEntity(entity)

    this.formatSomeEntity()

    return this.someEntity
  }

  getSomeEntity() {
    return this.someEntity.get()
  }

  formatSomeEntity() {
    // 附加的数据处理方法
  }

  async fetchSomeEntity(options) {
    const { someDao } = this.dataflow.dao

    const response = await someDao.getSomeEntity(options)

    this.setSomeEntity(response.data)

    // 记录日志
    this.$logger.log('[fetchSomeEntity]', '[data]', this.getSomeEntity())

    return this.getSomeEntity()
  }
}

export default SomeService

# 使用方式

虽然 Dataflow 从源码组织形式上分为了 daomodelsservices 三个目录,但是为了更加高效便捷地使用,Vue Admin Next 通过插件将其整合到了 src/dataflow.js 中。这样,就可以直接在需要的地方进行如下调用:

// DAO
dataflow.dao.CommonDao
// Model
dataflow.models.UserModel
// Service
dataflow.services.AuthService

TIP

注意文件名应该与类名相同,并采用大驼峰式命名法。

在实践过程中,DAO 和 Service 大部分情况下并不需要持久化的数据,因此可以采用单例模式。dataflow 也自动创建了它们的实例。例如:

// 调用 DAO 实例方法
dataflow.dao.commonDao.login()
// 调用 Service 实例方法
dataflow.services.authService.hasAuth()

TIP

无法使用单例的场景下,可以自己创建实例。

# 在组件中使用

参考了 Vuex、VueRouter 的实现方式,Dataflow 也向每个组件实例中注入了 $dao$services 方法。

例如:














 





<template>
  <div class="login-box">
    <!-- login form -->
  </div>
</template>

<script>
export default {
  name: 'login-page',

  methods: {
    login() {
      // 简单接口,无需 Service 直接调用 DAO
      await this.$dao.commonDao.login()
    }
  }
};
</script>

# 在 Vuex 中使用

Vue 框架从设计上来说,更加关注视图层的渲染和更新。Vuex 的引入,让大型应用的状态管理更加集中,无需在组件之间层层传递。虽然它提供了可以执行异步操作的 Action,但是如果把所有数据处理、业务逻辑都放在 Action 里面,整个 Vuex 的组织会非常臃肿和复杂。

因此 Vue Admin Next 推荐的方式是:当 Vuex 需要调用接口、处理数据时,统一使用 Dataflow 提供的方法。

具体如何实现?在创建 Vuex Store 实例时,通过 Vuex 的插件机制在 Store 上添加了 dataflow 属性,这样,就可以在 Action 中通过以下方式进行调用了:








 



{
  async removeGlobalAppData({ commit }) {
    const { dataflow } = this;

    commit(types.SET_GLOBAL_APP_DATA, {});

    // 调用 dataflow 提供的方法
    await dataflow.dao.commonDao.logout();
  }
}

此外,还有一些关于 Vuex 的其他使用建议,可以查看 通用开发模式 - 状态管理;