Optimice la operación de Sao según la gestión de la interfaz de axios

¡Optimice la operación genial basada en la administración de la interfaz axios!

Este artículo tiene como objetivo optimizar los módulos de interfaz de proyectos backend medianos y grandes y actualizarlos incrementalmente sin afectar el funcionamiento normal del proyecto.

Funcionalidad mejorada

1. Escritura simplificada de archivos de interfaz (generación semiautomática de módulos de interfaz)
2. Programación de tareas y programación de carga (antivibración a nivel de interfaz, múltiples interfaces comparten una carga para evitar parpadeos)
3. Avisos de interfaz gratuitos (los mensajes rápidos pueden ser controlado por el front-end), también puede ser controlado por el backend)

Método de escritura de archivos de interfaz simplificado

Para las interfaces de algunos módulos mid-end y back-end, son básicamente funciones de agregar, eliminar, modificar, verificar y auditar flujos (otras interfaces especiales no se discutirán por el momento). Si la interfaz de back-end está lo suficientemente estandarizada, probablemente será la siguiente situación

 import request from "@/utils/request";
// 销售退货列表
export function getSalesReturnList(data) {
  return request({
    url: "/sales_return/list",
    method: "post",
    data,});
}
​
// 保存销售退货
export function saveSalesReturn(data) {
  return request({
    url: "/sales_return/save",
    method: "post",
    data,});
}
// 根据Id获取销售退货
export function getSalesReturn(query) {
  return request({
    url: "/sales_return/get",
    method: "get",
    params: query,});
}
// 根据Id删除销售退货
export function deleteSalesReturn(data) {
  return request({
    url: "/sales_return/delete",
    method: "post",
    data,});
}
// 提交销售退货审核
export function submitSalesReturn(data) {
  return request({
    url: "/sales_return/submit",
    method: "post",
    data,});
}
// 审核销售退货
export function auditSalesReturn(data) {
  return request({
    url: "/sales_return/audit",
    method: "post",
    data,});
}
// 撤审销售退货
export function revokeAuditSalesReturn(data) {
  return request({
    url: "/sales_return/withdraw",
    method: "post",
    data,});
}
// 审核拒绝销售退货
export function rejectSalesReturn(data) {
  return request({
    url: "/sales_return/reject",
    method: "post",
    data,});
}
// 作废销售退货
export function discardSalesReturn(data) {
  return request({
    url: "/sales_return/discard",
    method: "post",
    data,});
} 

Creo que esto es demasiado repetitivo, el nombre de la función de la interfaz es demasiado problemático y es difícil para el equipo estandarizarlo. ¿Se puede generar automáticamente y se puede ayudar con el nombre, de modo que este tipo de archivo de interfaz esté más estandarizado?

Piensa en una forma a continuación

Suponiendo lo anterior, un módulo de documento generalmente tiene nueve métodos de interfaz: agregar, eliminar, modificar, verificar, enviar, anular, revisar, retirar revisión y rechazar. Para sus URL, el empalme sales_return en el frente es fijo, la diferencia es el identificador de ruta que identifica la función en la parte posterior. Además, el método se divide en métodos de publicación y obtención.

Consideramos estas nueve interfaces como 9 bits en un número binario de 9 bits: 1 representa existencia y 0 representa inexistencia.

Podemos crear un archivo de mapa para prepararnos para la construcción (como se muestra a continuación)

export const apiEnum = {
  // 查列表2^0
  1: {
    name: "list",//接口名称
    type: "post",//接口方式},
  // 查详情2^1
  2: {
    name: "get",
    type: "get",
    loading: true,//是否需要loading调度、防抖},
  // 删列表 2^2
  4: {
    name: "delete",
    type: "post",},
  // 保存 或者 保存且提交2^3
  8: {
    name: "save",
    type: "post",
    loading: true,},
  // 提交2^4
  16: {
    name: "submit",
    type: "post",
    loading: true,},
  // 审核2^5
  32: {
    name: "audit",
    type: "post",},
  // 撤审2^6
  64: {
    name: "withdraw",
    type: "post",},
  // 拒绝2^7
  128: {
    name: "reject",
    type: "post",},
  // 作废2^7
  256: {
    name: "discard",
    type: "post",},
};
export const apiFuncModule = {
  // 全部
  COMMON: 511,
  // 增删改查
  CURD: 15,
}; 

Cuando paso 1, los nueve bits son 000000001, lo que significa que solo hay una interfaz de consulta. Cuando paso 15, los nueve dígitos 000001111representan cuatro interfaces: agregar, eliminar, modificar y verificar. Etcétera.

El siguiente paso es completar la función de procesamiento y completar la función anterior (como se muestra a continuación)

 import request from "@/utils/request";
import { apiEnum, apiFuncModule } from "@/enum/baseModule/apiEnum";
function useApi(moduleName, code = 511) {
  let apiMap = {};
  for (let key in apiEnum) {
    if ((key & code) == key) {
      let obj = apiEnum[key];
   //可以按自己习惯来对接口函数命名
      let apiName = "api_" + obj.name;
      apiMap[apiName] = (data) => {
        return request({
          url: `/${moduleName}/${obj.name}`,
          method: obj.type,
        [obj.type == "get" ? "params" : "data"]: data,
          loading: obj.loading,
      });
    };
  }}
  return apiMap;
}
export { useApi, apiFuncModule as apiType }; 

Después de completar los pasos anteriores, nuestro archivo de interfaz se puede escribir así, de modo que se hayan escrito las nueve interfaces. Y está claro de un vistazo: si necesitas modificarlo, solo necesitas ajustar los parámetros.

import { useApi } from "@/utils/system/apiGenPlugin";
//code可以不传 ,默认为511
export const API = useApi("sales_return");
//若有其他特殊接口 兼容原始写法 互不影响
export function xxxxx(data) {...
} 

Uso

 //API集中管理
import { API as SalesReturn } from "@/api/workApi/sale/return";
const {api_save,api_delete,api_get,api_list,api_audit,api_withdraw,api_discard,api_submit,api_reject} = SalesReturn
//单独使用
import { useApi } from "@/utils/system/apiGenPlugin";
const {api_save,api_delete,api_get,api_list,api_audit,api_withdraw,api_discard,api_submit,api_reject} = useApi('sales_return') 
  • Agregar SalesReturn.api_save
  • EliminarSalesReturn.api_delete
  • 改 SalesReturn.api_get
  • Consulte SalesReturn.api_list
  • Auditoría SalesReturn.api_audit
  • Retirar SalesReturn.api_withdraw
  • Descartar SalesReturn.api_discard
  • EnviarRetornoVentas.api_submit
  • Rechazar SalesReturn.api_reject

Programación de tareas, programación de carga

En el desarrollo real, es posible que realicemos algún procesamiento en las llamadas de interfaz.

1. Realice un procesamiento antivibración en eventos de envío para evitar envíos repetidos.
2. Al cargar ciertos recursos importantes, espero que haya un efecto de carga para optimizar la experiencia del usuario.
3. Deje que varias interfaces que requieren efectos de carga compartan la misma carga para evitar el parpadeo de la página.

Estas funciones son engorrosas de manejar individualmente y el estilo de escritura de cada persona es diferente, lo que dificulta aún más los costos de mantenimiento posteriores.

Sin más preámbulos, simplemente publique el código.

Clase de programación de interfaz

import { Loading } from "element-ui";
class RequestLock {
  // Loading 实例
  L_instance = null;
  // 接口map
  reqMap = new Map();
  // 最近一次调用接口时间戳
  timestamp = 0;
​
  constructor(timeout = 500) {
    // 过渡时间
    this.timeout = timeout;}
  // 创建任务
  put = (id) => {
    if (this.reqMap.has(id)) return false;
    this._put(id);
    return true;};
  _put = (id) => {
    this.timestamp = new Date().getTime();
    this.reqMap.set(id, true);
      //开启loading
    this.L_instance = Loading.service({
      fullscreen: true,
      background: "rgba(255, 255, 255, 0.1)",
      lock: true,
  });};
  // 移除任务
  del = (id) => {
    if (this.reqMap.has(id)) {
      this.reqMap.delete(id);
​
      if (this.reqMap.size == 0) {
        this._closeLoading();
    }
  }};
  // 清空所有的任务
  clearTask = () => {
    this.reqMap.clear();
    this.L_instance.close();};
    //平滑关闭loading
  _closeLoading = () => {
    let _timestamp = new Date().getTime();
    let settime = _timestamp - this.timestamp;
    if (settime > this.timeout) {
      this.L_instance?.close();
  } else {
      setTimeout(() => {
        this.L_instance?.close();
    }, this.timeout - settime);
  }};
}
export default RequestLock;
​ 

Uso en axios

Esta es una optimización incremental, que agrega funcionalidad sin afectar el código anterior.

import { RequestLock } from "@/class/lock";
let loadLock = new RequestLock(500);
//请求拦截
service.interceptors.request.use((config) => {
      ...
      //如果配置中有loading 开启调度
    if (config.loading) {
      if (!loadLock.put(config.url)) {
        return Promise.reject(new Error("repeat request!"));
    }
  }
      ...
    return config;},(error) => {
      ...
      //如果有错误请求,中止当前调度任务,并清空
    loadLock.clearTask();
      ...
    return Promise.reject(error);}
);
​
//响应拦截
service.interceptors.response.use((response) => {
    ...
    //检查
    response.config.loading && loadLock.del(response.config.url);
    ...},(error) => {
    loadLock.clearTask();
    return Promise.reject(error);}
); 

Escritura de archivos de interfaz

// 根据Id获取销售退货
export function getSalesReturn(query) {
  return request({
    url: "/sales_return/get",
    method: "get",
    params: query,
    //在这里配置loading为true,开启
    loading:true});
} 

Consejos para la liberalización de la información

A veces, cuando elimino un dato, necesito un cuadro emergente para indicar si la eliminación se realizó correctamente. Por lo general, agregamos esta función cuando la interfaz vuelve a llamar con éxito. Es necesario determinar el estado para mostrar la descripción y el color del cuadro de aviso. Por otro lado, a veces, cuando se elimina un dato, el mensaje de requisitos comerciales no es simplemente un simple "¡Eliminar correctamente!", sino que también puede requerir otros mensajes adicionales. Por ejemplo, "¡Elimine el documento xxx correctamente, procese xxxx a tiempo!". Este requisito no es difícil, pero existen costos de comunicación y costos de mantenimiento. Se requieren modificaciones si hay algunos cambios en el negocio.

Por otro lado, el backend está más cerca de la lógica empresarial del sistema y es más razonable dejar la función de aviso al backend. Por supuesto, la interfaz también debe conservar esta función para que sea compatible con determinadas necesidades.

import { Message } from "element-ui";
export function responseMsgHandle(res) {
    //这里需要后端响应数据格式的配合,MsgType表示提示状态,Msg表示提示描述
  let { MsgType, Msg } = res;
  if (["success", "warning", "error"].includes(MsgType)) {
    Message({
      message: Msg,
      type: MsgType,
      duration: 5 * 1000,
  });}
} 

usar

import { responseMsgHandle } from "@/utils";
//响应拦截
service.interceptors.response.use((response) => {
    ...
    const res = response.data;
    responseMsgHandle(res);
    ...},(error) => {
      ...
    responseMsgHandle({
        MsgType:"error",
        Msg:error.message,
  });
      ...
    return Promise.reject(error);}
); 

Resumir

Las tres soluciones de optimización simples anteriores se pueden usar en combinación o individualmente. Se puede modificar y utilizar de acuerdo con las necesidades reales de su proyecto.

Básicamente puede solucionar gran parte del trabajo repetitivo y reducir los costes de mantenimiento.

por fin

Recientemente encontré un documento de VUE que resume varios puntos de conocimiento de VUE y lo compilé en "36 consejos que debes conocer para el desarrollo de Vue". El contenido es relativamente detallado y las explicaciones de varios puntos de conocimiento también son muy buenas.



Los amigos necesitados pueden hacer clic en la tarjeta a continuación para recibirla y compartirla gratis.

Supongo que te gusta

Origin blog.csdn.net/web2022050901/article/details/129270030
Recomendado
Clasificación