Capacidades comunes

El objeto de contexto expone las capacidades nativas de NocoBase. Algunas solo están disponibles en el Plugin, otras solo en los componentes y otras en ambos lados con sintaxis diferente. Vista general:

CapacidadPlugin (this.xxx)Componente (ctx.xxx)Notas
Petición APIthis.context.apictx.apiUso idéntico
i18nthis.t() / this.context.tctx.tthis.t() inyecta el namespace del plugin
Loggerthis.context.loggerctx.loggerUso idéntico
Registro de rutasthis.router.add()-Solo en el Plugin
Navegación-ctx.router.navigate()Solo en componentes
Información de rutathis.context.locationctx.route / ctx.locationRecomendado en componentes
Gestión de vistasthis.context.viewerctx.viewerAbrir diálogos, drawers, etc.
FlowEnginethis.flowEngine-Solo en el Plugin

A continuación se describen una a una, agrupadas por namespace.

Peticiones API (ctx.api)

Use ctx.api.request() para llamar al backend. Su uso es idéntico al de Axios.

En el Plugin

import { Plugin } from '@nocobase/client-v2';

class MyPlugin extends Plugin {
  async load() {
    // Petición directa dentro de load()
    const response = await this.context.api.request({
      url: 'app:getInfo',
      method: 'get',
    });
    console.log('Información de la aplicación', response.data);
  }
}

En componentes

import { useFlowContext } from '@nocobase/flow-engine';

export default function MyPage() {
  const ctx = useFlowContext();

  const handleLoad = async () => {
    // Petición GET
    const response = await ctx.api.request({
      url: 'users:list',
      method: 'get',
    });
    console.log(response.data);

    // Petición POST
    await ctx.api.request({
      url: 'users:create',
      method: 'post',
      data: { name: 'Tao Tao' },
    });
  };

  return <button onClick={handleLoad}>Cargar datos</button>;
}

Combinado con useRequest de ahooks

En los componentes puede usar useRequest de ahooks para simplificar la gestión del estado de la petición:

import { useFlowContext } from '@nocobase/flow-engine';
import { useRequest } from 'ahooks';

export default function PostList() {
  const ctx = useFlowContext();

  const { data, loading, error, refresh } = useRequest(() =>
    ctx.api.request({
      url: 'posts:list',
      method: 'get',
    }),
  );

  if (loading) return <div>Cargando...</div>;
  if (error) return <div>Error en la petición: {error.message}</div>;

  return (
    <div>
      <button onClick={refresh}>Refrescar</button>
      <pre>{JSON.stringify(data?.data, null, 2)}</pre>
    </div>
  );
}

Interceptores de peticiones

Mediante ctx.api.axios puede añadir interceptores de petición/respuesta, normalmente en el load() del Plugin:

async load() {
  // Interceptor de petición: añadir cabecera personalizada
  this.context.api.axios.interceptors.request.use((config) => {
    config.headers['X-Custom-Header'] = 'my-value';
    return config;
  });

  // Interceptor de respuesta: tratamiento unificado de errores
  this.context.api.axios.interceptors.response.use(
    (response) => response,
    (error) => {
      console.error('Error en la petición', error);
      return Promise.reject(error);
    },
  );
}

Cabeceras personalizadas de NocoBase

NocoBase Server admite las siguientes cabeceras personalizadas. Suelen inyectarse automáticamente mediante interceptores y no es necesario establecerlas a mano:

CabeceraDescripción
X-AppAplicación actual en escenarios multi-app
X-LocaleIdioma actual (por ejemplo zh-CN, en-US)
X-HostnameNombre del host del cliente
X-TimezoneZona horaria del cliente (por ejemplo +08:00)
X-RoleRol actual
X-AuthenticatorMétodo de autenticación del usuario actual

Internacionalización (ctx.t / ctx.i18n)

Los plugins de NocoBase gestionan los archivos multilingües en el directorio src/locale/, y ctx.t() se utiliza para acceder a las traducciones desde el código.

Archivos multilingües

Cree un archivo JSON por idioma bajo src/locale/:

plugin-hello/
└── src/
    └── locale/
        ├── zh-CN.json
        └── en-US.json
// zh-CN.json
{
  "Hello": "你好",
  "Your name is {{name}}": "你的名字是 {{name}}"
}
// en-US.json
{
  "Hello": "Hello",
  "Your name is {{name}}": "Your name is {{name}}"
}
Atención

La primera vez que añada un archivo de idioma debe reiniciar la aplicación para que surta efecto.

ctx.t()

En los componentes, obtenga textos traducidos con ctx.t():

const ctx = useFlowContext();

// Uso básico
ctx.t('Hello');

// Con variables
ctx.t('Your name is {{name}}', { name: 'NocoBase' });

// Especificar namespace (el por defecto es el nombre del paquete del plugin)
ctx.t('Hello', { ns: '@my-project/plugin-hello' });

this.t()

En el Plugin es más cómodo usar this.t(): inyecta automáticamente el nombre del paquete del plugin como namespace, sin necesidad de pasar ns:

class MyPlugin extends Plugin {
  async load() {
    // Usa automáticamente el nombre del paquete actual como ns
    console.log(this.t('Hello'));

    // Equivalente a
    console.log(this.context.t('Hello', { ns: '@my-project/plugin-hello' }));
  }
}

ctx.i18n

ctx.i18n es la instancia subyacente de i18next. Por lo general basta con ctx.t(). Si necesita cambiar el idioma dinámicamente o escuchar cambios de idioma, use ctx.i18n:

// Idioma actual
const currentLang = ctx.i18n.language; // 'zh-CN'

// Escuchar cambios de idioma
ctx.i18n.on('languageChanged', (lng) => {
  console.log('Idioma cambiado a', lng);
});

tExpr()

tExpr() genera una expresión de traducción diferida y suele usarse en FlowModel.define(), ya que el define() se ejecuta al cargar el módulo, momento en el que aún no existe la instancia de i18n:

import { tExpr } from '@nocobase/flow-engine';

HelloBlockModel.define({
  label: tExpr('Hello block'), // Genera '{{t("Hello block")}}', se traduce en tiempo de ejecución
});

Para una explicación completa de la internacionalización (archivos de traducción, hook useT, tExpr, etc.), consulte Internacionalización (i18n). La lista completa de códigos de idioma soportados por NocoBase está en Lista de idiomas.

Logger (ctx.logger)

ctx.logger produce logs estructurados y está basado en pino.

En el Plugin

import { Plugin } from '@nocobase/client-v2';

class MyPlugin extends Plugin {
  async load() {
    this.context.logger.info('Plugin cargado', { plugin: 'my-plugin' });
    this.context.logger.error('Error al inicializar', { error });
  }
}

En componentes

import { useFlowContext } from '@nocobase/flow-engine';

export default function MyPage() {
  const ctx = useFlowContext();

  const handleLoad = async () => {
    ctx.logger.info('Página cargada', { page: 'UserList' });
    ctx.logger.debug('Estado actual del usuario', { user });
  };

  // ...
}

Niveles de log de mayor a menor: fatal > error > warn > info > debug > trace. Solo se emiten los logs cuyo nivel sea mayor o igual al configurado.

Rutas (ctx.router / ctx.route / ctx.location)

Las capacidades de rutas se dividen en tres bloques: registro (solo en el Plugin), navegación e información (solo en componentes).

Registro de rutas (this.router / this.pluginSettingsManager)

Dentro del load() del Plugin, registre rutas de páginas con this.router.add() y páginas de configuración con this.pluginSettingsManager:

async load() {
  // Registrar una ruta de página normal
  this.router.add('hello', {
    path: '/hello',
    componentLoader: () => import('./pages/HelloPage'),
  });

  // Registrar una página de configuración (aparecerá en el menú "Configuración del plugin")
  this.pluginSettingsManager.addMenuItem({
    key: 'my-settings',
    title: this.t('My Settings'),
    icon: 'SettingOutlined', // Iconos de Ant Design, ver https://5x.ant.design/components/icon
  });
  this.pluginSettingsManager.addPageTabItem({
    menuKey: 'my-settings',
    key: 'index',
    title: this.t('My Settings'),
    componentLoader: () => import('./pages/MySettingsPage'),
  });
}

Para más detalles, consulte Router. Para un ejemplo completo de página de configuración, consulte Crear una página de configuración del plugin.

Atención

this.router es el RouterManager y se usa para registrar rutas. this.pluginSettingsManager es el PluginSettingsManager y se usa para registrar páginas de configuración. Ninguno de los dos es lo mismo que ctx.router (React Router, que sirve para navegar entre páginas) en los componentes.

En los componentes, use ctx.router.navigate() para navegar:

const ctx = useFlowContext();
ctx.router.navigate('/hello'); // -> /v/hello

Información de la ruta (ctx.route)

En los componentes, obtenga la información de la ruta actual con ctx.route:

const ctx = useFlowContext();

// Parámetros dinámicos (por ejemplo, ruta definida como /users/:id)
const { id } = ctx.route.params;

// Nombre de la ruta
const { name } = ctx.route;

Tipo completo de ctx.route:

interface RouteOptions {
  name?: string;         // Identificador único de la ruta
  path?: string;         // Plantilla de la ruta
  pathname?: string;     // Ruta completa
  params?: Record<string, any>; // Parámetros de la ruta
}

URL actual (ctx.location)

ctx.location ofrece la información detallada de la URL actual, similar al window.location del navegador:

const ctx = useFlowContext();

console.log(ctx.location.pathname); // '/v/hello'
console.log(ctx.location.search);   // '?page=1'
console.log(ctx.location.hash);     // '#section'

Aunque ctx.route y ctx.location son accesibles en el Plugin a través de this.context, durante la carga del plugin la URL aún no es determinista y los valores carecen de sentido. Recomendamos usarlos en los componentes.

Gestión de vistas (ctx.viewer / ctx.view)

ctx.viewer ofrece una API imperativa para abrir diálogos, drawers y otras vistas. Funciona tanto en el Plugin como en los componentes.

En el Plugin

import { Plugin } from '@nocobase/client-v2';

class MyPlugin extends Plugin {
  async load() {
    // Por ejemplo, abrir un diálogo en una lógica de inicialización
    this.context.viewer.dialog({
      title: 'Bienvenido',
      content: () => <div>Plugin inicializado</div>,
    });
  }
}

En componentes

import { Button } from 'antd';
import { useFlowContext } from '@nocobase/flow-engine';

export default function MyPage() {
  const ctx = useFlowContext();

  const openDetail = () => {
    // Abrir un diálogo
    ctx.viewer.dialog({
      title: 'Editar usuario',
      content: () => <UserEditForm />,
    });
  };

  const openDrawer = () => {
    // Abrir un drawer
    ctx.viewer.drawer({
      title: 'Detalle',
      content: () => <UserDetail />,
    });
  };

  return (
    <div>
      <Button onClick={openDetail}>Editar</Button>
      <Button onClick={openDrawer}>Ver detalle</Button>
    </div>
  );
}

Método genérico

// Especificar el tipo de vista con type
ctx.viewer.open({
  type: 'dialog',  // 'dialog' | 'drawer' | 'popover' | 'embed'
  title: 'Título',
  content: () => <SomeComponent />,
});

Operar dentro de la vista (ctx.view)

Dentro del componente del diálogo o drawer puede manipular la vista actual mediante ctx.view (por ejemplo, cerrarla):

import { Button } from 'antd';
import { useFlowContext } from '@nocobase/flow-engine';

function DialogContent() {
  const ctx = useFlowContext();
  return (
    <div>
      <p>Contenido del diálogo</p>
      <Button onClick={() => ctx.view.close()}>Cerrar</Button>
    </div>
  );
}

FlowEngine (this.flowEngine)

this.flowEngine es la instancia de FlowEngine y solo está disponible en el Plugin. Suele utilizarse para registrar FlowModel:

import { Plugin } from '@nocobase/client-v2';

class MyPlugin extends Plugin {
  async load() {
    // Registrar FlowModel (forma recomendada con carga bajo demanda)
    this.flowEngine.registerModelLoaders({
      HelloBlockModel: {
        loader: () => import('./models/HelloBlockModel'),
      },
    });
  }
}

FlowModel es el núcleo del sistema de configuración visual de NocoBase. Si su componente debe aparecer en los menús "Añadir bloque / campo / acción", debe envolverlo con un FlowModel. Para más detalles, consulte FlowEngine.

Más capacidades

Las siguientes capacidades pueden resultar útiles en escenarios más avanzados:

PropiedadDescripción
ctx.modelInstancia actual de FlowModel (disponible dentro del contexto de ejecución de un Flow)
ctx.refReferencia del componente, usar junto con ctx.onRefReady
ctx.exit()Salir de la ejecución del Flow actual
ctx.defineProperty()Añadir dinámicamente una propiedad personalizada al contexto
ctx.defineMethod()Añadir dinámicamente un método personalizado al contexto
ctx.useResource()Obtener la API de operaciones sobre un recurso de datos
ctx.dataSourceManagerGestor de fuentes de datos

Para el uso detallado, consulte la Documentación completa de FlowEngine.

Enlaces relacionados