自定义前端拦截器

某种情况下,我们需要通过自定义请求拦截器来做自己的逻辑处理,平台内置了一些拦截器

登录拦截器LoginRedirectInterceptor

重定向到登录拦截器LoginRedirectInterceptor

import { UrlHelper, IResponseErrorResult, LoginRedirectInterceptor } from '@kunlun/dependencies';

export class BizLoginRedirectInterceptor extends LoginRedirectInterceptor {
  /**
   * 重定向到登录页
   * @param response 错误响应结果
   * @return 是否重定向成功
   */
  public redirectToLogin(response: IResponseErrorResult): boolean {
    if (window.parent === window) {
      const redirect_url = location.pathname;
      // 可自定义跳转路径
      location.href = `${UrlHelper.appendBasePath('login')}?redirect_url=${redirect_url}`;
    } else {
      // iframe页面的跳转
      window.open(`${window.parent.location.origin}/#/login`, '_top');
    }
    return true;
  }
}

请求成功拦截器RequestSuccessInterceptor

请求失败拦截器 RequestErrorInterceptor

网络请求异常拦截器 NetworkErrorInterceptor

当我们需要重写某个拦截器的时候,只需要继承对应的拦截器,然后重写里面的方法即可

// 自定义登录拦截器
export class CustomLoginRedirectInterceptor extends LoginRedirectInterceptor{
    public error(response: IResponseErrorResult) {
        // 自己的逻辑处理

        return true // 必写
    }
}

// 自定义请求成功拦截器
export class CustomRequestSuccessInterceptor extends RequestSuccessInterceptor{
    public success(response: IResponseErrorResult) {
        // 自己的逻辑处理
        return true // 必写
    }
}

// 自定义请求失败拦截器
export class CustomRequestErrorInterceptor extends RequestErrorInterceptor{
    public error(response: IResponseErrorResult) {
        const { errors } = response;

    if (errors && errors.length) {
      const notPermissionCodes = [
        SystemErrorCode.NO_PERMISSION_ON_MODULE,
        SystemErrorCode.NO_PERMISSION_ON_VIEW,
        SystemErrorCode.NO_PERMISSION_ON_MODULE_ENTRY,
        SystemErrorCode.NO_PERMISSION_ON_HOMEPAGE
      ];

      /**
       * 用来处理重复的错误提示
       */
      const executedMessages: string[] = [];

      for (const errorItem of errors) {
        const errorCode = errorItem.extensions?.errorCode;
        if (!notPermissionCodes.includes(errorCode as any)) {
          const errorMessage = errorItem.extensions?.messages?.[0]?.message || errorItem.message;

          if (!executedMessages.includes(errorMessage)) {
            // 自己的逻辑处理
          }

          executedMessages.push(errorMessage);
        }
      }
    }

    return true;
  }
}

// 自定义网络请求异常拦截器
export class CustomNetworkErrorInterceptor extends NetworkErrorInterceptor{
      public error(response: IResponseErrorResult) {
            const { networkError } = response;
            if (networkError) {
            const { name, message } = networkError;
            if (name && message) {
                // 自己的逻辑处理
            }
            return false;
            }
            return true;
  }
}

当拦截器的代码写完后,需要在启动工程里面的main.ts导入它

// main.ts
import MyInterceptor from './MyInterceptor.ts'
import BizLoginRedirectInterceptor from './BizLoginRedirectInterceptor.ts'

// 使用拦截器

VueOioProvider({
    ...
    http: {
        url: '',
        interceptor: {
            loginRedirect: new BizLoginRedirectInterceptor(),
            requestError: new MyInterceptor() // 这里的key是requestError,是因为我自定义的是错误拦截器,大家根据自己自定的拦截器选择对应的key
        }
    }
})

Oinone社区 作者:oinone原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/80.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
oinone's avataroinone
Previous 2023年6月20日 pm4:07
Next 2023年11月2日 pm1:58

相关推荐

  • 前端视图的元数据与数据的传递、交互

    在阅读本篇文章之前,您需要学习以下知识点: 1: 元数据 视图的元数据 在日常开发中,我们会经常遇到自定义的字段、动作、视图需要界面设计器配置的数据,这些数据可能是当前页面的字段,也有可能动作,那么如何获取呢? 视图元数据分为两种:1: 当前视图(metadataRuntimeContext)2: 根视图(rootRuntimeContext) 那么这两种类型怎么区分呢? 举个例子:1: 如果当前字段是在表单中,那么当前视图就是表单,根视图就表单的父级视图,如果只有一个表单视图,那么当前视图就是根视图。2: 如果当前视图是表单,但是表单里面有个表格,对于表格字段而言,当前视图就是表格,根视图就是表单。 当前视图的元数据(metadataRuntimeContext) 在前端,我们通过 metadataRuntimeContext 来获取视图的元数据,例如: export class CustomFormStringFieldSingleWidget extends FormStringFieldSingleWidget { protected mounted(): void { console.log(this.metadataRuntimeContext); } /** * 界面设计器配置的动作 */ @Widget.Reactive() protected get modelActions() { return this.metadataRuntimeContext.model.modelActions } /** * 界面设计器配置的字段 */ @Widget.Reactive() protected get modelFields() { return this.metadataRuntimeContext.model.modelFields } } 属性名 类型 可选性 描述 viewAction RuntimeViewAction 是 运行时跳转动作(通过跳转动作创建的运行时上下文具备该属性) module RuntimeModule 否 运行时模块 model RuntimeModel 否 运行时模型 view RuntimeView 否 运行时视图 viewLayout DslDefinition \| undefined 否 视图布局 DSL,从运行时视图解析获得 viewDsl DslDefinition \| undefined 否 视图模板 DSL,从运行时视图解析获得 viewTemplate DslDefinition 否 视图最终执行 DSL,从运行时视图解析获得或根据布局 DSL 和模板 DSL 合并生成 getModel (model: string, isBelong?: boolean) => GetModelResult \| undefined 否 获取模型,返回获取的模型和所在的运行时上下文 getModelField (data: string, isBelong?: boolean) => GetModelFieldResult \| undefined 否 获取模型字段,返回获取的模型字段和所在的运行时上下文 getRequestModelFields (options?: GetRequestModelFieldsOptions) => RequestModelField[] 否 获取请求字段 getDefaultValue () => Promise<Record<string, unknown>> 否 获取默认值 getInitialValue () => Promise<Record<string, unknown>> 否 获取初始值 运行时模型(model) 属性名 类型 可选性 描述 id string 是 模型 id model string 否 模型编码 name string 否 技术名称 modelFields RuntimeModelField[] 否 模型字段 modelActions RuntimeAction[] 否 模型动作 type ModelType 是 模型类型 module string 是 模块编码 moduleName string 否 模块名称 moduleDefinition RuntimeModule 是…

    2024年10月8日
    3.6K00
  • 前端自定义字段与视图最佳方案

    自定义视图获取数据 在某些情况下,oinone 提供的默认视图无法满足需求,这时我们就需要自定义视图。通常,虽然视图的 UI 不足以满足要求,但数据结构是不变的。此时,重点是修改页面 UI,数据的请求与回填可以利用平台默认的能力。 如何实现? 界面设计器的使用 你可以通过界面设计器先配置页面,平台在运行时会根据设计器生成对应的 GraphQL 请求,并自动回填数据。 视图的数据结构 视图的数据类型分为可以分为 Object 跟 List Object 代表当前视图的数据结构是对象 List 代表当前视图的数据结构是数组。 如果我们将 Object 跟 List 分的更细一点就变成了这样: 1: Object: 对象,代表当前视图的数据结构是单个对象,例如:表单视图、详情视图1: List: 对象数组,代表当前视图的数据结构数组,例如:表格视图、卡片视图、画廊视图 视图类型 平台组件 数据属性 表格视图 TableWidget dataSource 画廊视图 GalleryWidget dataSource 表单视图 FormWidget formData 详情视图 DetailWidget formData 自定义视图时,需要先确认当前视图的类型,再通过界面设计器进行页面配置。前端部分只需继承相应的组件,平台底层会自动处理接口数据的获取与回填。 表单视图示例: import Form from './Form.vue'; // 自定义表单视图 @SPI.ClassFactory( BaseElementWidget.Token({ widget: 'custom-form' }) ) export class CustomForm extends FormWidget { public initialize(props: Props) { super.initialize(props); this.setComponent(Form); return this; } } Vue 组件: <template></template> <script lang="ts"> export default defineComponent({ props: { formData: { // 当前表单的数据 type: Object, default: () => ({}) } } }); </script> 自定义layout // 原始的layout模版 <view type="FORM"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> //自定义的layout模版 <view type="FORM"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="custom-form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> 其实就是把 widget="form" 改成 widget="custom-form" 表格视图示例: import Table from './Table.vue'; // 自定义表格视图 @SPI.ClassFactory( BaseElementWidget.Token({ widget: 'custom-table' }) ) export class CustomTable extends TableWidget { public initialize(props: Props) { super.initialize(props); this.setComponent(Table); return this; } } Vue 组件: <template></template> <script…

    2024年10月17日
    2.1K00
  • 如何自定义表格字段?

    目录 一、表单字段注册vue组件实现机制 二、表格字段注册vue组件实现机制 三、机制对比分析 四、表格字段完整案例 表单字段注册vue组件实现机制 核心代码 public initialize(props) { super.initialize(props); this.setComponent(VueComponent); return this; } 表格字段注册vue组件实现机制 核心代码 @Widget.Method() public renderDefaultSlot(context: RowContext) { const value = this.compute(context); return [createVNode(CustomTableString, { value })]; } 因为表格有行跟列,每一列都是一个单独的字段(对应的是TS文件),但是每列里面的单元格承载的是Vue组件,所以通过这种方式可以实现表格每个字段对应的TS文件是同一份,而单元格的组件入口是通过renderDefaultSlot函数动态渲染的vue组件,只需要通过createVNode创建对应的vue组件,然后将props传递进去就行 上下文接口 interface RowContext<T = unknown> { /** * 当前唯一键, 默认使用__draftId, 若不存在时,使用第三方组件内置唯一键(如VxeTable使用{@link VXE_TABLE_X_ID}) */ key: string; /** * 当前行数据 */ data: Record<string, unknown>; /** * 当前行索引 */ index: number; /** * 第三方组件原始上下文 */ origin: T; } 机制对比分析 表单字段 vs 表格字段渲染机制对比表 对比维度 表单字段实现方案 表格字段实现方案 绑定时机 initialize 阶段静态绑定 renderDefaultSlot 阶段动态创建 组件声明方式 this.setComponent(Component) createVNode(Component, props) 上下文传递 通过类成员变量访问 显式接收 RowContext 参数 渲染控制粒度 字段级(表单控件) 单元格级 表格字段完整案例 import { SPI, ViewType, BaseFieldWidget, Widget, TableNumberWidget, ModelFieldType, RowContext } from '@kunlun/dependencies'; import CustomTableString from './CustomTableString.vue'; import { createVNode } from 'vue'; @SPI.ClassFactory( BaseFieldWidget.Token({ ttype: ModelFieldType.String, viewType: [ViewType.Table], widget: 'CustomTableStringWidget' }) ) export class CustomTableStringWidget extends BaseTableFieldWidget { @Widget.Method() public renderDefaultSlot(context:RowContext) { const value = this.compute(context); // 当前字段的值 const rowData = context.data // 当前行的数据 const dataSource = this.dataSource // 表格数据 if (value) { // 自定义组件入口在此处 return [createVNode(CustomTableString, { value })]; } return []; } } <template> <div>当前值: {{value}}</div> </template> <script lang="ts"> import { defineComponent } from 'vue'…

    2023年11月6日
    2.7K00
  • 前端自定义组件之多页面步骤条

    本文将讲解如何通过自定义,实现多页面的步骤条组件。其中每个步骤的元素里都对应界面设计器的一个页面。以下是代码实现和原理分析。 代码实现 NextStepWidget 多页面步骤条 ts 组件 import { CallChaining, createRuntimeContextByView, customMutation, customQuery, RuntimeView, SPI, ViewCache, Widget, DefaultTabsWidget, BasePackWidget } from '@oinone/kunlun-dependencies'; import { isEmpty } from 'lodash-es'; import { MyMetadataViewWidget } from './MyMetadataViewWidget'; import NextStep from './NextStep.vue'; import { IStepConfig, StepDirection } from './type'; @SPI.ClassFactory(BasePackWidget.Token({ widget: 'NextStep' })) export class NextStepWidget extends DefaultTabsWidget { public initialize(props) { this.titles = props.template?.widgets?.map((item) => item.title) || []; props.template && (props.template.widgets = []); super.initialize(props); this.setComponent(NextStep); return this; } @Widget.Reactive() public get invisible() { return false; } // 配置的每一步名称 @Widget.Reactive() public titles = []; // region 上一步下一步配置 // 步骤配置,切换的顺序就是数组的顺序,模型没有限制 @Widget.Reactive() public get stepJsonConfig() { let data = JSON.parse( this.getDsl().stepJsonConfig || '[{"model":"resource.ResourceCountry","viewName":"国家form"},{"model":"resource.ResourceProvince","viewName":"省form"},{"model":"resource.ResourceCity","viewName":"市form"}]' ); return data as IStepConfig[]; } // 切换上一步下一步 @Widget.Method() public async onStepChange(stepDirection: StepDirection) { // 没有激活的,说明是初始化,取第一步 if (!this.activeStepKey) { const step = this.stepJsonConfig[0]; if (step) { this.activeStepKey = `${step.model}_${step.viewName}`; await this.initStepView(step); } return; } // 获取当前步骤的索引 if (this.currentActiveKeyIndex > -1) { await this.onSave(); // 获取下一步索引 const nextStepIndex = stepDirection === StepDirection.NEXT ? this.currentActiveKeyIndex + 1 : this.currentActiveKeyIndex – 1; // 在索引范围内,则渲染视图 if (nextStepIndex >= 0 && nextStepIndex < this.stepJsonConfig.length) { const nextStep = this.stepJsonConfig[nextStepIndex];…

    2025年7月21日
    96600
  • 表格字段API

    BaseTableFieldWidget 表格字段的基类. 示例 class MyTableFieldClass extends BaseTableFieldWidget{ } 内置常见的属性 dataSource 当前表格数据 rootData 根视图数据 activeRecords 当前选中行 userPrefer 用户偏好 width 单元格宽度 minWidth 单元格最小宽度 align 内容对齐方式 headerAlign 头部内容对齐方式 metadataRuntimeContext 当前视图运行时的上下文,可以获取当前模型、字段、动作、视图等所有的数据 urlParameters 获取当前的url field 当前字段 详细信息 用来获取当前字段的元数据 model 当前模型 详细信息 用来获取当前模型的元数据 view 当前视图 详细信息 界面设计器配置的视图dsl disabled 是否禁用 详细信息 来源于界面设计器的配置 invisible 当前字段是否不可见 详细信息 来源于界面设计器的配置,true -> 不可见, false -> 可见 required 是否必填 详细信息 来源于界面设计器的配置,如果当前字段是在详情页,那么是false readonly 是否只读 详细信息 来源于界面设计器的配置,如果当前字段是在详情页、搜索,那么是false label 当前字段的标题 详细信息 用来获取当前字段的标题 内置常见的方法 renderDefaultSlot 渲染单元格内容 示例 @Widget.Method() public renderDefaultSlot(context): VNode[] | string { // 当前单元格的数据 const currentValue = this.compute(context) as string[]; return [createVNode('div', { class: 'table-string-tag' }, currentValue)]; } renderHeaderSlot 自定义渲染头部 示例 @Widget.Method() public renderHeaderSlot(context: RowContext): VNode[] | string { const children = [createVNode('span', { class: 'oio-column-header-title' }, this.label)]; return children; } getTableInstance 获取当前表格实例(vxe-table) getDsl 获取界面设计器的配置

    2023年11月16日
    1.3K00

Leave a Reply

Please Login to Comment