admate
TypeScript icon, indicating that this package has built-in type declarations

0.10.0 • Public • Published

Admate version

中后台 CRUD 前端框架,极致简洁的基础上不向灵活性妥协,
致力于攻克「页面重复度高,提取公共代码却难以兼顾定制化需求」的痛点。

minzipped size conventional commits code style PRs Welcome

i want it all
assessment


特性

  • 🖖 Vue 2.6/2.7/3 一体通用 - 零成本升级
  • 🔓 解耦合 UI 框架 - 只要技术栈是 Vue + Axios 便可使用,提供主流 UI 框架示例代码如 Vuetify,Element,AntDesignVue,Quasar 和 PrimeVue
  • 🤝 后台模板友好 - 可集成进任意管理后台模板如 vue-pure-adminvue-vben-adminvue-element-admin
  • 🌐 规整统一的页面代码风格 - 避免了每个页面的代码风格五花八门、难以维护
  • 🥥 模块级别的请求配置 - 虽然 Axios 支持全局配置,由于同模块内请求配置相似,接口前缀通常是一致的,所以往往还需要模块级别的配置
  • 🪝 量身打造的生命周期 - 代理模式 + 控制反转,定制属于你的生命周期行为
  • 🍪 贴心而不武断的逻辑封装
    • 列表筛选:支持监听筛选参数 (防抖控制接口调用频率) 的方式,也支持点击读取按钮触发的方式
    • 表单展现风格:支持对话框的风格,也支持独立页面的风格
    • 单条记录状态:支持调用 “编辑接口” 改变状态,也支持调用独立的 “更新状态接口” 指定新状态,也支持分别调用 “启用接口” 和 “停用接口” 改变状态
    • 加载状态:提供列表读取状态、表单读取状态、表单提交状态的响应式变量
  • 🧹 缜密周全的收尾工作,无后顾之忧
    • 关闭表单时,自动将表单绑定的数据恢复至初始状态 (不是直接清空)
    • 删除当前分页最后一条记录时,自动切换至上一页 (如果当前不在第一页)
  • 🔌 开箱即用的适配层示例
    • 列表筛选参数重置 & 参数校验
    • 支持 URL 传参指定筛选项默认值
    • 支持动态生成筛选项默认值,使用场景举例:日期/时间类的参数,如果其默认值为当前最新时刻,重置筛选项时会重置到已过期的时刻

对比

案例 技术栈 业务代码量(字符数)
常规增删查改页面 Vue 2 + Element 13,330
常规增删查改页面 Vue 2 + Element + Admate 约 5,000
对接支付宝进件 Vue 2 + Element 89,293
(表单部分)
对接微信进件 Vue 2 + Element + Admate 38,718
(表单部分)
电商后台的商品管理 Vue 2 + Element 425,885
电商后台的商品管理 Vue 2 + Element + Admate 235,979

架构

架构图


安装

npm i admate

外置依赖

  • vue
  • @vue/composition-api:仅 Vue 2.6 或更早版本需要

搭配 Vuetify

 

Vuetify 3 (Vue 3) 示例

Vuetify 2 (Vue 2.7) 示例

Vuetify 2 (Vue 2.6) 示例

搭配 ElementPlus

 

ElementPlus (Vue 3) 示例

搭配 Element

 

Element (Vue 2.7) 示例

Element (Vue 2.6) 示例

搭配 Quasar

 

Quasar 2 (Vue 3) 示例

Quasar 1 不支持 Vite,暂无示例

搭配 AntDesignVue

 

AntDesignVue 2 (Vue 3) 示例

AntDesignVue 1 (Vue 2.7) 示例

AntDesignVue 1 (Vue 2.6) 示例

搭配 PrimeVue

 

PrimeVue 3 (Vue 3) 示例

PrimeVue 2 不支持 Vite,暂无示例


请求配置

axios

useAdmate({
  // Axios 或 Axios 实例
  // 用于调用接口
  axios,
})

axiosConfig

useAdmate({
  // Axios 配置
  axiosConfig: {
    // 读取列表
    getList: {
      method: 'GET',
    },
    // 新增一条记录(submitForm 在新增时调用)
    c: {
      method: 'POST',
    },
    // 读取一条记录(openForm 在查看、编辑时调用)
    r: {
      method: 'GET',
    },
    // 编辑一条记录(submitForm 在编辑时调用)
    u: {
      method: 'PUT',
    },
    // 删除一条记录
    d: {
      method: 'DELETE',
    },
    // 启用一条记录
    enable: {
      method: 'PUT',
    },
    // 禁用一条记录
    disable: {
      method: 'PUT',
    },
    // 变更一条记录的状态
    updateStatus: {
      method: 'PUT',
    },
  },
})

urlPrefix

useAdmate({
  // axiosConfig 中各个接口的 URL 前缀
  urlPrefix: '',
})
// 示例: URL 前缀不统一

useAdmate({
  urlPrefix: 'somepage',
  axiosConfig: {
    r: {
      // 如果某个接口的前缀不是 'somepage',可以在 URL 前面加斜线,即可忽略该前缀
      url: '/anotherpage/selectOne',
    },
  }
})

RESTful

如果接口地址需要进行动态拼接

// 配置
const { openForm, d, enable, disable, updateStatus } = useAdmate({
  axiosConfig: {
    // 读取列表
    getList: payload => ({
      method: 'GET',
      url: `module/${payload.xxx}`
    }),
    // 读取一条记录(openForm 在查看、编辑时调用)
    r: payload => ({
      method: 'GET',
      url: `module/${payload.id}`
    }),
    // 编辑一条记录(submitForm 在编辑时调用)
    u: payload => ({
      method: 'PUT',
      url: `module/${payload.id}`
    }),
    // 删除一条记录
    d: payload => ({
      method: 'DELETE',
      url: `module/${payload.id}`
    }),
    // 启用一条记录
    enable: payload => ({
      method: 'PUT',
      url: `module/${payload.id}`
    }),
    // 禁用一条记录
    disable: payload => ({
      method: 'PUT',
      url: `module/${payload.id}`
    }),
    // 变更一条记录的状态
    updateStatus: payload => ({
      method: 'PUT',
      url: `module/${payload.id}`
    }),
  }
})

// 使用
openForm({ id: 1 }, 'config')
d({ id: 1 }, 'config')
enable({ id: 1 }, 'config')
disable({ id: 1 }, 'config')
updateStatus({ id: 1 }, 'config')

FormData

Axios 的 data 默认以 application/json 作为 MIME type,如果你需要使用 multipart/form-data

  • 全局配置

给你的 Axios 配置 transformRequestheaders['Content-Type']

  • 局部配置

getListopenFormdupdateStatusenabledisablesubmitForm 的参数 1 均支持 FormData 类型

<!-- 示例: 局部配置 -->

<script setup>
import useAdmateAdapter from '@/utils/useAdmateAdapter'

// 过滤 list.value.filter 并转换为 FormData 格式
FormData.from = (json) => {
  const formData = new FormData()
  for (const k in json) {
    if (![Number.NaN, null, undefined].includes(json[k])) {
      formData.append(k, json[k])
    }
  }
  return formData
}

useAdmateAdapter({
  getListProxy(getList, trigger) {
    getList(FormData.from(list.value.filter))
  },
})

const FormData = window.FormData
</script>

<template>
  <el-table>
    <el-table-column label="操作">
      <template #default="{ row: { id } }">
        <el-button @click="r(FormData.from({ id }))">
          查看
        </el-button>
        <el-button @click="u(FormData.from({ id }))">
          编辑
        </el-button>
        <el-button @click="d(FormData.from({ id }))">
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>

  <el-dialog>
    <template #footer>
      <el-button @click="() => submitForm(FormData.from(form.data))">
        确 定
      </el-button>
    </template>
  </el-dialog>
</template>

列表

筛选参数

list.filter

useAdmate({
  list: {
    // 页码的参数名称或路径,必填
    // 支持属性名,如 `'pageNo'`
    // 支持属性路径,如 `'page.pageNo'`
    pageNumberAt: undefined,

    // 可以在这里提供筛选参数的默认值
    filter: {
      'pageNumberAt 生成的页码参数名称': 1
    },
  },
})

触发读取

  • 点击专用的读取按钮触发
    • ✗ 操作相对繁琐。
    • ✗ 列表数据与筛选条件可能是无关的。可能产生 “当前的列表数据是否基于筛选项?” 的顾虑,导致徒增点击读取按钮的次数。
    • ✓ 想同时设置多个筛选条件时,只调用一次接口,不浪费服务器资源。
useAdmate({
  list: {
    watchFilter: false,
  }
})

  • 改变筛选条件后即时触发
    • ✓ 操作相对简便。
    • ✓ 列表数据与筛选条件即时绑定。
    • 想同时设置多个筛选条件时,接口会被多次调用,浪费服务器资源 (Admate 已优化)。
useAdmate({
  list: {
    watchFilter: true, // 默认值

    // 防抖间隔,单位毫秒
    // 如果筛选参数不含 input 类型,可以设置为 0,即不防抖
    // 翻页不会触发防抖
    // watchFilter 开启时有效
    debounceInterval: 300, // 默认值
  }
})

列表数据

list.data

useAdmate({
  list: {
    // 列表数据
    data: [],

    // 指定接口返回值中列表数据的位置
    // 支持属性名,如 `'data'`
    // 支持属性路径,如 `'data[0].records'`
    // 支持 symbol 类型的属性名
    // 支持 Function,如 `response => response.data`
    dataAt: undefined,

    // 指定接口返回值中记录总数的位置
    // 支持属性名,如 `'total'`
    // 支持属性路径,如 `'data[0].total'`
    // 支持 symbol 类型的属性名
    // 支持 Function,如 `response => response.total`
    totalAt: undefined,
  }
})

读取列表

getList

获取列表,在首次进入页面、列表筛选参数改变、单条记录增删查改后会被调用

const {
  /**
   * PS: 以下为原始 getList 的函数签名,如果你配置了 getListProxy,则以 getListProxy 为准
   *
   * @param {any} [payload = list.filter]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   * @returns {Promise<any>} 接口返回值
   */
  getList
} = useAdmate()

getList() // 手动读取

getListProxy

你可以使用 getListProxy 来代理 getList,以便在 getList 前后做一些操作,或改变 getList 的行为

useAdmate({
  /**
   * @param {Function} getList 被代理的原始 getList
   * @param {string} trigger 调用动机 可能的值: 'init' 'pageNumberChange' 'filterChange' 'c' 'r' 'u' 'd' 'updateStatus' 'enable' 'disable'
   */
  getListProxy(getList, trigger) {},
})
// 示例: 获取列表之前,校验参数

useAdmate({
  getListProxy(getList, trigger) {
    if (trigger === 'filterChange') {
      listFilterRef.value.validate().then(() => {
        getList()
      })
    } else {
      getList()
    }
  },
})
// 示例: 单条记录操作成功后,弹出提示

useAdmate({
  getListProxy(getList, trigger) {
    getList()
    if (['c', 'u', 'd', 'updateStatus', 'enable', 'disable'].includes(trigger)) {
      currentInstance.value.$message.success('操作成功')
    }
  },
})
// 示例: 读取列表后,修改列表数据

const { list } = useAdmate({
  getListProxy(getList, trigger) {
    getList().then((response) => {
      // response 为 axiosConfig.getList 的接口返回值
      list.data = response.data?.filter(v => !v.disabled)
    })
  },
})

读取状态

list.loading

axiosConfig.getList 被调用时值为 true,否则为 false

<!-- 示例 -->

<script setup>
import useAdmate from 'admate'

const { list } = useAdmate()

function handleTable() {
  list.value.loading = true
  Vue.prototype.$POST('').finally(() => {
    list.value.loading = false
  })
}
</script>

<template>
  <el-table v-loading="list.loading" />
</template>

表单

表单风格

表单默认是对话框的风格,但也支持独立页面的风格

对比

  • 对话框:体验好,割裂感低,表单的开闭不影响父页面状态
  • 独立页面:体验较差,从表单返回父页面时,父页面的状态会丢失,比如列表筛选状态

表单显隐

form.show: boolean


表单数据

form.data

useAdmate({
  form: {
    // 可以在这里提供表单数据的默认值
    data: {},

    // 在查看、编辑表单时,可能需要调用接口(axiosConfig.r)回显表单的数据
    // dataAt 用于指定接口返回值中表单数据的位置
    // 支持属性名,如 `'detail'`
    // 支持属性路径,如 `'data[0].detail'`
    // 支持 symbol 类型的属性名
    // 支持 Function,如 `response => response.detail`
    dataAt: undefined,

    // 接口(axiosConfig.r)返回值与 form.data 合并的方式
    mergeData: 'deep',
  },
})

mergeData:

  • 'deep':深合并 (默认)
  • 'shallow':浅合并
  • (newFormData: any) => any:自定义合并方式
  • false:不合并,直接替换

为什么默认是深合并?

在 Vue 2 中,template 不支持 ?. 语法,要在 template 中判空,代码写起来会非常冗余,通常的做法是在 data 中声明空对象

比如给 form.data 提供默认值:

<script setup>
import useAdmate from 'admate'

const { form } = useAdmate({
  form: {
    data: {
      a: {
        b: {}
      }
    }
  }
})
</script>

<template>
  {{ form.data.a.b.c }}
</template>

如果 axiosConfig.r 的返回值为: { a: {} }

如果与默认值浅合并后将得到: { a: {} } —— 默认值中的对象 b 丢失了,引发空指针异常。

如果与默认值深合并后将得到: { a: { b: {} } } —— 代码正常工作。

// 示例: 自定义合并方式

import { mergeWith } from 'lodash'

function defaultFormData() {
  return {
    a: {
      b: {}
    }
  }
}

const { form } = useAdmate({
  form: {
    data: defaultFormData(),
    // 接口返回值中嵌套的对象可能为 null,会覆盖默认值中的空对象
    mergeData(
      // 接口返回值在通过 form.dataAt 计算过后的值
      newFormData
    ) {
      // Vue 3 中不需要赋值,mergeWith 的改动是响应式的
      form.data = mergeWith(
        defaultFormData(),
        newFormData,
        (oldObj, newObj) => [undefined, null].includes(newObj) ? oldObj : undefined
      )
    },
  },
})

表单形态

form.status: StatusType


新增

打开表单,提交时会调用 axiosConfig.c

const { form, openForm } = useAdmate()

// 将表单形态设置为“新增”,然后打开表单
form.status = 'c'
openForm()

复制新增

表单的初始数据不是空白,而是复制一条已有的记录

  1. 打开表单时,和查看/编辑一样,需要调接口回显
  2. 提交表单时调用的是新增的接口
  3. 表单名称显示为 “复制新增”

复制新增属于一种交叉状态,这种情况没有必要专门增加一种表单形态,可以借助一个辅助变量如 isCopy,用 isCopy && form.status ==='c' 来判断是不是复制新增,然后给 openForm 传参即可回显。


查看

打开表单,并调用 axiosConfig.r 回显表单内容

const { form, openForm } = useAdmate()

// 将表单形态设置为“查看”,然后打开表单
form.status = 'r'
/**
 * PS: 以下为原始 openForm 的函数签名,如果你配置了 openFormProxy ,则以 openFormProxy 为准
 *
 * @param {any} [payload] 如果 payload 不为空,则会调用 axiosConfig.r
 * @param {'data'|'params'|'config'|'cache'} [payloadAs] 指定 payload 的用途
 *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
 *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
 *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
 *   'cache': 将 payload 直接用作表单数据(不调用读取单条记录的接口)
 * @returns {Promise<any>} axiosConfig.r 的返回值
 */
openForm()

编辑

打开表单,并调用 axiosConfig.r 回显表单内容,提交时会调用 axiosConfig.u

const { form, openForm } = useAdmate()

// 将表单形态设置为“编辑”,然后打开表单
form.status = 'u'
/**
 * PS: 以下为原始 openForm 的函数签名,如果你配置了 openFormProxy,则以 openFormProxy 为准
 *
 * @param {any} [payload] 如果 payload 不为空,则会调用 axiosConfig.r
 * @param {'data'|'params'|'config'|'cache'} [payloadAs] 指定 payload 的用途
 *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
 *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
 *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
 *   'cache': 将 payload 直接用作表单数据(不调用读取单条记录的接口)
 * @returns {Promise<any>} axiosConfig.r 的返回值
 */
openForm()

删除

const {
  /**
   * @param {any} [payload]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
   *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
   *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
   * @returns {Promise<any>} axiosConfig.d 的返回值
   */
  d
} = useAdmate()

状态变更

状态变更有三种方式:

  1. 后端提供一个统一的接口,传参指定新的状态

使用 updateStatus

<script setup>
import useAdmate from 'admate'

const {
  /**
   * @param {any} [payload]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
   *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
   *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
   * @returns {Promise<any>} axiosConfig.updateStatus 的返回值
   */
  updateStatus,
} = useAdmate()
</script>

<template>
  <el-table>
    <el-table-column
      label="操作"
      align="center"
    >
      <template #default="{ row: { id, status } }">
        <el-switch @change="updateStatus({ id, status: status ^ 1 })" />
      </template>
    </el-table-column>
  </el-table>
</template>
  1. 后端提供启用和停用两个接口

使用 enabledisable

<script setup>
import useAdmate from 'admate'

const {
  /**
   * @param {any} [payload]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
   *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
   *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
   * @returns {Promise<any>} axiosConfig.enable 的返回值
   */
  enable,
  /**
   * @param {any} [payload]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
   *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
   *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
   * @returns {Promise<any>} axiosConfig.disable 的返回值
   */
  disable
} = useAdmate()
</script>

<template>
  <el-table>
    <el-table-column
      label="操作"
      align="center"
    >
      <template #default="{ row: { id, status } }">
        <el-switch @change="[enable, disable][status]({ id })" />
      </template>
    </el-table-column>
  </el-table>
</template>
  1. 后端未提供独立的接口,使用编辑接口改变状态

updateStatus 当作 u 来使用

<script setup>
import useAdmate from 'admate'

const {
  /**
   * @param {any} [payload]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   *   'data': 将 payload 用作请求配置的 `data` 参数(请求方式为 POST / PATCH / PUT / DELETE 时默认)
   *   'params': 将 payload 用作请求配置的 `params` 参数(请求方式为 GET / HEAD 时默认)
   *   'config': 将 payload 仅用于构建请求配置(详见 RESTful 章节)
   * @returns {Promise<any>} axiosConfig.updateStatus 的返回值
   */
  updateStatus,
} = useAdmate({
  axiosConfig: {
    updateStatus: {
      // 按编辑接口进行配置
    },
  },
})
</script>

<template>
  <el-table>
    <el-table-column
      label="操作"
      align="center"
    >
      <template #default="{ row }">
        <el-switch @change="updateStatus({ ...row, status: row.status ^ 1 })" />
      </template>
    </el-table-column>
  </el-table>
</template>

打开表单

openForm

打开表单,函数签名要分情况:

openFormProxy

你可以使用 openFormProxy 来代理 openForm,以便在 openForm 前后做一些操作,或改变 openForm 的行为

useAdmate({
  /**
   * @param {Function} openForm 被代理的原始 openForm
   * @returns {Promise<object> | object | void} object 为打开表单后 form 的终态
   */
  openFormProxy(openForm) {},
})
// 示例: 回显表单后,修改表单数据

const { form } = useAdmate({
  openFormProxy(openForm) {
    // 新增时 openForm 没有返回值
    return new Promise((resolve, reject) => {
      openForm()?.then((response) => {
        // response 为 axiosConfig.r 的接口返回值
        // 修改表单数据
        form.data.status = 1
        resolve()
      }).catch((e) => {
        reject(e)
      })
    })
  },
})
// 示例: 回显表单后,清除校验

useAdmate({
  openFormProxy(openForm) {
    return new Promise((resolve, reject) => {
      openForm()?.finally(() => {
        formRef.value.clearValidate()
      }).then(() => {
        resolve()
      }).catch((e) => {
        reject(e)
      })
    })
  },
})
// 示例: 回显表单后,自定义表单的开闭和读取状态
useAdmate({
  openFormProxy(openForm) {
    return new Promise((resolve, reject) => {
      // 可以在 finally 中 resolve
      openForm().then(() => {
        // 回显成功后,默认停止加载
        resolve({
          loading: false,
        })
      }).catch(() => {
        // 回显失败后,默认关闭表单并停止加载
        resolve({
          show: false,
          loading: false,
        })
      })
    })
  }
})

// 也可以返回一个对象(如果没有异步操作)
useAdmate({
  openFormProxy(openForm) {
    return {
      loading: false
    }
  }
})

读取状态

form.loading

axiosConfig.r 被调用时值为 true,否则为 false

不能将该值当作表单回显结束的标志,因为复用列表数据时不会调用 axiosConfig.r

<!-- 示例 -->

<script setup>
import useAdmate from 'admate'

const { form } = useAdmate()
</script>

<template>
  <el-dialog>
    <el-form v-loading="form.loading" />
  </el-dialog>
</template>

提交表单

submitForm

提交表单,新增时调用 axiosConfig.c,编辑时调用 axiosConfig.u

const {
  /**
   * PS: 以下为原始 submitForm 的函数签名,如果你配置了 submitFormProxy ,则以 submitFormProxy 为准
   *
   * @param {any} [payload = form.data]
   * @param {'data'|'params'|'config'} [payloadAs] 指定 payload 的用途
   * @returns {Promise<any>} 接口返回值
   */
  submitForm
} = useAdmate()

submitFormProxy

你可以使用 submitFormProxy 来代理 submitForm,以便在 submitForm 前后做一些操作,或改变 submitForm 的行为

useAdmate({
  /**
   * @param {Function} submitForm 被代理的原始 submitForm
   * @returns {Promise<object> | object | void} object 为提交表单后 form 的终态
   */
  submitFormProxy(submitForm) {}
})
// 示例: 指定提交参数

submitForm({
  ...form.data,
  status: 1,
})

// submitForm 被代理时
useAdmate({
  submitFormProxy(submitForm) {
    return new Promise((resolve, reject) => {
      submitForm({
        ...form.data,
        status: 1,
      }).then(() => {
        resolve()
      }).catch((e) => {
        reject(e)
      })
    })
  }
})
// 示例: 提交前校验表单

useAdmate({
  submitFormProxy(submitForm) {
    return new Promise((resolve, reject) => {
      formRef.value.validate().then(() => {
        submitForm().then(() => {
          resolve()
        }).catch((e) => {
          reject(e)
        })
      })
    })
  }
})
// 示例: 提交表单后,自定义表单的开闭和提交状态

// 返回一个 promise
useAdmate({
  submitFormProxy(submitForm) {
    return new Promise((resolve, reject) => {
      formRef.value.validate().then(() => {
        submitForm().then(() => {
          // 提交成功后,默认关闭表单,并停止加载
          resolve({
            show: false,
            submitting: false,
          })
        }).catch(() => {
          // 提交失败后,默认仅停止加载
          resolve({
            show: true,
            submitting: false,
          })
        })
      })
    })
  }
})

// 也可以返回一个对象(如果没有异步操作)
useAdmate({
  submitFormProxy(submitForm) {
    return {
      show: false,
      submitting: false,
    }
  }
})

提交状态

form.submitting

axiosConfig.caxiosConfig.u 被调用时值为 true,否则为 false

<!-- 示例 -->

<script setup>
import useAdmate from 'admate'

const { form } = useAdmate()
</script>

<template>
  <el-dialog>
    <template #footer>
      <el-button :loading="form.submitting">
        确 定
      </el-button>
    </template>
  </el-dialog>
</template>

生命周期

读取列表

// 示例: 适配层提供 afterGetList

useAdmateAdapter({}, {
  afterGetList(res, trigger) {
    // res 为接口返回值,trigger 为调用动机
    // 可访问 this(组件实例)
  }
})

打开 / 读取表单

  • 读取表单前
watch(() => form.value.show, (n) => {
  if (n) {
    // 打开表单
  }
})
  • 读取表单后
// 示例: 适配层提供 afterOpenForm

useAdmateAdapter({}, {
  afterOpenForm(res) {
    // res 为接口返回值(新增时为空)
    // 可访问 this(组件实例)
  }
})
  • 读取表单后 (不含新增)
// 示例: 适配层提供 afterRetrieve

useAdmateAdapter({}, {
  afterRetrieve(res) {
    // res 为接口返回值
    // 可访问 this(组件实例)
  }
})

提交表单

  • 提交表单前
// 示例: 适配层提供 beforeSubmit

useAdmateAdapter({}, {
  beforeSubmit(form) {
    // 可访问 this(组件实例)
  }
})
  • 提交表单后
// 示例: 适配层提供 afterSubmit

useAdmateAdapter({}, {
  afterSubmit(res) {
    // res 为接口返回值
    // 可访问 this(组件实例)
  }
})

关闭表单

watch(() => form.value.show, (n) => {
  if (!n) {
    // 关闭表单
  }
})

类型

type StatusType = '' | 'c' | 'r' | 'u' | string

场景

表单是子组件

将表单抽离为子组件

示例


表单是独立页面

操作单条记录时,跳转到专用的表单页面,操作完毕后返回

示例


只有表单没有列表

表单默认打开,且无法关闭,通常用于列表中只有一条数据,故列表被省略的场景

示例


嵌套使用

当前页面的对话框也使用 Admate

示例


更新日志

各版本详细改动请参考 release notes


Package Sidebar

Install

npm i admate

Weekly Downloads

6

Version

0.10.0

License

MIT

Unpacked Size

2.71 MB

Total Files

11

Last publish

Collaborators

  • cloydlau