4.2.4 框架之网络请求-HttpClient

oinone提供统一的网络请求底座,基于graphql二次封装

一、初始化

import { HttpClient } from '@kunlun/dependencies';
const http = HttpClient.getInstance();
http.setMiddleware() // 必须设置,请求回调。具体查看文章https://shushi.yuque.com/yqitvf/oinone/vwo80g
http.setBaseURL() // 必须设置,后端请求的路径

图4-2-4-1 初始化代码示例

二、HttpClient详细介绍

获取实例

import { HttpClient } from '@kunlun/dependencies';
const http = HttpClient.getInstance();

图4-2-4-2 获取实例

接口地址

import { HttpClient } from '@kunlun/dependencies';
const http = HttpClient.getInstance();
http.setBaseURL('接口地址');
http.getBaseURL(); // 获取接口地址

图4-2-4-3 接口地址

请求头

import { HttpClient } from '@kunlun/dependencies';
const http = HttpClient.getInstance();
http.setHeader({key: value});

图4-2-4-4 请求头

variables

import { HttpClient } from '@kunlun/dependencies';
const http = HttpClient.getInstance();
http.setExtendVariables((moduleName: string) => {
 return customFuntion();

});

图4-2-4-5 variables

回调

import { HttpClient } from '@kunlun/dependencies';
const http = HttpClient.getInstance();
http.setMiddleware([middleware]);

图4-2-4-6 回调

业务使用-query

private http = HttpClient.getInstance();
private getTestQuery = async () => {
 const query = `gql str`;
 const result = await this.http.query('module name', query);
 console.log(result)
 return result.data[`xx`]['xx']; // 返回的接口,打印出result对象层次返回
};

图4-2-4-7 业务使用-query

业务使用-mutate

private http = HttpClient.getInstance();

private getTestMutate = async () => {
  const mutation = `gql str`;

  const result = await this.http.mutate('module name', mutation);
    console.log(result)
  return result.data[`xx`]['xx']; // 返回的接口,打印出result对象层次返回
};

图4-2-4-8 业务使用-mutate

三、如何使用HttpClient

初始化

在项目目录src/main.ts下初始化httpClient

初始化必须要做的事:

  • 设置服务接口链接

  • 设置接口请求回调

业务实战

前文说到自定义新增宠物表单,让我们在这个基础上加入我们的httpClient;

第一步新增service.ts

image.png

图4-2-4-8 新增service.ts

service.ts

import { HttpClient } from '@kunlun/dependencies';

const addPetMutate = async (modelName, data) => {
    const http = HttpClient.getInstance();
    const mutateGql = `mutation{
    petMutation{
      addPet(data:${data})
       {
        id
      }
    }
  }`;

    const result = await http.mutate('pet', mutateGql);
    return (result as any).data['petMutation']['addPet'];
};

export { addPetMutate };

图4-2-4-9 service.ts

第二步业务中使用

import { constructOne, queryOne, SPI, ViewWidget, Widget, IModel, getModelByUrl, getModel, getIdByUrl, FormWidgetV3, CustomWidget, CallChaining } from '@kunlun/dependencies';
import PetFormView from './PetFormView.vue';
// 引入
import { addPetMutate } from './service';

@SPI.ClassFactory(CustomWidget.Token({ widget: 'PetForm' }))
export class PetFormViewWidget extends FormWidgetV3 {
  public initialize(props) {
    super.initialize(props);
    this.setComponent(PetFormView);
    return this;
  }

  /**
   * 数据提交
   * @protected
   */
  @Widget.Reactive()
  @Widget.Inject()
  protected callChaining: CallChaining | undefined;

  private modelInstance!: IModel;

  /**
   * 重要!!!!
   * 当字段改变时修改formData
   * */
  @Widget.Method()
  public onFieldChange(fieldName: string, value) {
    this.setDataByKey(fieldName, value);
  }

  /**
   * 表单编辑时查询数据
   * */
  public async fetchData(content: Record<string, unknown>[] = [], options: Record<string, unknown> = {}, variables: Record<string, unknown> = {}) {
    this.setBusy(true);
    const context: typeof options = { sourceModel: this.modelInstance.model, ...options };
    const fields = this.modelInstance?.modelFields;
    try {
      const id = getIdByUrl();
      const data = (await queryOne(this.modelInstance.model, (content[0] || { id }) as Record<string, string>, fields, variables, context)) as Record<string, unknown>;

      this.loadData(data);
      this.setBusy(false);
      return data;
    } catch (e) {
      console.error(e);
    } finally {
      this.setBusy(false);
    }
  }

  /**
   * 新增数据时获取表单默认值
   * */
  @Widget.Method()
  public async constructData(content: Record<string, unknown>[] = [], options: Record<string, unknown> = {}, variables: Record<string, unknown> = {}) {
    this.setBusy(true);
    const context: typeof options = { sourceModel: this.modelInstance.model, ...options };
    const fields = this.modelInstance.modelFields;
    const reqData = content[0] || {};
    const data = await constructOne(this.modelInstance!.model, reqData, fields, variables, context);
    return data as Record<string, unknown>;
  }

  @Widget.Method()
  private async reloadData() {
    const data = await this.constructData();
    // 覆盖formData
    this.setData(data);
  }

  @Widget.Method()
  public onChange(name, value) {
    this.formData[name] = value;
  }

  protected async mounted() {
    super.mounted();
    const modelModel = getModelByUrl();
    this.modelInstance = await getModel(modelModel);
    this.fetchData();
    // 数据提交钩子函数!!!
    this.callChaining?.callBefore(() => {
      return this.formData;
    });
  }

  @Widget.Method()
  private async addPet() {
    // 调用
    const data = await addPetMutate('petModule', this.getData());
  }
}

图4-2-4-10 业务中使用

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

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

(0)
史, 昂的头像史, 昂数式管理员
上一篇 2024年5月23日 am8:33
下一篇 2024年5月23日 am8:35

相关推荐

  • 6.1 文件与导入导出(改)

    导入导出在一定程度上是企业级软件和效率工具(office工具)的桥梁 文件的上传下载以及业务数据的导入导出是企业级软件一个比较常规的需求,甚至是巨量的需求。业务有管理需要一般都伴随有导入导出需求,导入导出在一定程度上是企业级软件和效率工具(office工具)的桥梁。oinone的文件模块就提供了通用的导入导出实现方案,以简单、一致、可扩展为目标,简单是快速入门,一致是用户操作感知一致、可扩展是满足用户最大化的自定义需求。 下图为文件导入导出的实现示意图,大家可以做一个整体了解 图6-1-1 文件导入导出实现示意图 一、基础能力 准备工作 pamirs-demo-api的pom文件中引入pamirs-file2-api包依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-file2-api</artifactId> </dependency> 图6-1-2 引入pamirs-file2-api包依赖 DemoModule增加对FileModule的依赖 @Module(dependencies = {FileModule.MODULE_MODULE}) 图6-1-3 DemoModule增加对FileModule的依赖 pamirs-demo-boot的pom文件中引入pamirs-file2-core包依赖 <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-file2-core</artifactId> </dependency> 图6-1-4 启动工程引入pamirs-file2-core包依赖 pamirs-demo-boot的application-dev.yml文件中增加配置pamirs.boot.modules增加file,即在启动模块中增加file模块 pamirs: boot: modules: – file 图6-1-5 pamirs-demo-boot的application-dev.yml文件中增加配置 pamirs-demo-boot的application-dev.yml文件中增加oss的配置。更多有关文件相关配置详见4.1.1【模块之yml文件结构详解】一文 cdn: oss: name: 阿里云 type: OSS bucket: demo uploadUrl: #换成自己的oss上传服务地址 downUrl: #换成自己的oss下载服务地址 accessKeyId: #阿里云oss的accessKeyId accessKeySecret: #阿里云oss的accessKeySecret mairDir: upload/demo #换成自己的目录 validTime: 360000 timeout: 60000 active: true referer: www.shushi.pro 图6-1-6 application-dev.yml文件中增加oss的配置 其他文件系统支持 a. 文件系统类型 类型 服务 OSS 阿里云 UPYUN 又拍云 MINIO Minio HUAWEI_OBS 华为云 LOCAL 本地文件存储 表6-1-1 支持的文件系统类型 b. OSS配置示例 ⅰ. 华为云OBS cdn: oss: name: 华为云 type: HUAWEI_OBS bucket: pamirs #(根据实际情况修改) uploadUrl: obs.cn-east-2.myhuaweicloud.com downloadUrl: obs.cn-east-2.myhuaweicloud.com accessKeyId: 你的accessKeyId accessKeySecret: 你的accessKeySecret # 根据实际情况修改 mainDir: upload/ validTime: 3600000 timeout: 600000 active: true allowedOrigin: http://192.168.95.31:8888,https://xxxx.xxxxx.com referer: 图6-1-7 OBS的配置说明 ⅱ. MINIO cdn: oss: name: minio type: MINIO bucket: pamirs #(根据实际情况修改) uploadUrl: http://192.168.243.6:32190 #(根据实际情况修改) downloadUrl: http://192.168.243.6:9000 #(根据实际情况修改) accessKeyId: 你的accessKeyId accessKeySecret: 你的accessKeySecret # 根据实际情况修改 mainDir: upload/ validTime: 3600000 timeout: 600000 active: true referer: localFolderUrl: 图6-1-8 MINIO的配置说明 ⅲ. 又拍云 cdn: oss: name: 又拍云 type: UPYUN bucket: pamirs #(根据实际情况修改) uploadUrl: v0.api.upyun.com downloadUrl: v0.api.upyun.com accessKeyId: 你的accessKeyId accessKeySecret: 你的accessKeySecret # 根据实际情况修改 mainDir: upload/ validTime: 3600000 timeout: 600000…

    2024年5月23日
    1.2K00
  • 3.5.7.8 自定义菜单栏

    在业务中,可能会遇到需要对菜单栏的交互或UI做全新设计的需求,这个时候可以自定义菜单栏组件支持。 首先继承平台的CustomMenuWidget 组件,将自己vue文件设置到component处 import { NavMenu, SPI, ViewWidget } from '@kunlun/dependencies'; import Component from './CustomMenu.vue'; @SPI.ClassFactory( ViewWidget.Token({ // 这里的widget跟平台的组件一样,这样才能覆盖平台的组件 widget: 'nav-menu' }) ) export class CustomMenuWidget extends NavMenu { public initialize(props) { super.initialize(props); this.setComponent(Component); return this; } } vue文件中继承平台的props,编写自定义页面代码 export const NavMenuProps = { /** * 当前模块 */ module: { type: Object as PropType<IModule | null> }, /** * 树结构的菜单 */ menus: { type: Array as PropType<IResolvedMenu[]>, default: () => [] }, /** * 菜单类型,现在支持垂直、水平、和内嵌模式三种 */ mode: { type: String as PropType<'vertical' | 'horizontal' | 'inline'>, default: 'inline' }, /** * 菜单栏是否折叠收起 */ collapsed: { type: Boolean, default: false }, /** * 当前展开的 SubMenu 菜单项 key 数组 */ openKeys: { type: Array as PropType<string[]>, default: () => [] }, /** * 当前选中的菜单项 key 数组 */ selectKeys: { type: Array as PropType<string[]>, default: () => [] }, /** * 菜单搜索下拉选中菜单项 */ selectMenuBySearch: { type: Function as PropType<(menuName: String) => void> }, /** * 选中菜单项 */ selectMenu: { type: Function as PropType<(menuName: String) => Promise<void>> }, /** * SubMenu 展开/关闭的回调 */ openChange: { type: Function as PropType<(openKeys: string[]) => void> }, /**…

    2024年5月23日
    1.1K00
  • 节点动作

    节点动作为触发和结束结点中间的动作,点击节点名称可以进行修改。

    Oinone 7天入门到精通 2024年6月20日
    1.1K00
  • 3.5.2.1 整体介绍

    虽然我们有小眼睛可以让用户自定义展示字段和排序喜好,以及通过权限控制行、列展示,但在我们日常业务开发中还是会对页面进行调整,以满足业务方的对交互友好和便捷性的要求。本节会在如何自定义之前我们先介绍页面结构与逻辑,再带小伙伴一起完成自定义view的Template和Layout,以及整个母版的Template和Layout 页面的构成讲解 页面交互拓扑图 页面交互拓扑图 图3-5-2-1 页面交互拓扑图 注:页面逻辑交互拓扑图说明 模块作为主切换入口 模块决定菜单列表 菜单切换触发点击action 前端根据Mask、View进行渲染, a. Mask是母版是确定了主题、非主内容分发区域所使用组件和主内容分发区域联动方式的页面模板。全局、应用、视图动作、视图都可以通过mask属性指定母版 bMask和View都是有layout定义和template定义合并而成,系统会提供默认母版,以及为每种视图提供默认layout c. layout与template通过插槽进行匹配 Action根据不同类型做出不同访问后端服务、url跳转、页面路由、发起客户端动作等 Aciton路由可以指定Mask、视图组件的layout、template a. 当layout没有指定的时候则用系统默认的 b. 当template没有指定的时候,且视图组件相同类型有多条记录时,根据优先级选取 Mask和视图组件的layout优先级(视图组件>视图动作 > 应用 > 全局) 默认母版以及各类视图组件 母版布局 默认母版基础布局base-layout <mask layout="default"> <header slot="header"/> <container slot="main" name="main"> <sidebar slot="sidebar"/> <container slot="content"/> </container> <footer slot="footer"/> </mask> 图3-5-2-2 默认母版基础布局base-layout 母版template <mask layout="default"> <mask name="defaultMask"> <template slot="header"> <container name="appBar"> <element widget="logo"/> <element widget="appFinder"/> </container> <container name="operationBar"> <element widget="notification"/> <element widget="dividerVertical"/> <element widget="languages"/> </container> <element widget="userProfile"/> </template> <template slot="sidebar"> <element widget="navMenu"/> </template> <template slot="content"> <element widget="breadcrumb"/> <element widget="mainView"/> </template> </mask> 图3-5-2-3 母版template 注: 上例中因为名称为main的插槽不需要设置更多的属性,所以在template中缺省了main插槽的template标签。 最终可执行视图 <mask name="defaultMask"> <header> <container name="appBar"> <element widget="logo"/> <element widget="appFinder"/> </container> <container name="operationBar"> <element widget="notification"/> <element widget="dividerVertical"/> <element widget="languages"/> </container> <element widget="userProfile"/> </header> <container name="main"> <sidebar name="sidebar"> <element widget="navMenu"/> </sidebar> <container name="content"> <element widget="breadcrumb"/> <element widget="mainView"/> </container> </container> <footer/> </mask> 图3-5-2-4 最终可执行视图 表格视图布局 默认表格视图基础布局base-layout <view type="table"> <view type="search"> <element widget="search" slot="search"> <xslot name="fields" slotSupport="field" /> </element> </view> <pack widget="fieldset"> <element widget="actionBar" slot="actions" slotSupport="action" /> <element widget="table" slot="table"> <xslot name="fields" slotSupport="field" /> <element widget="actionsColumn" slot="actionsColumn"> <xslot name="rowActions" slotSupport="action" /> </element> </element> </pack> </view> 图3-5-2-5 默认表格视图基础布局base-layout 注:table标签的子标签为column组件,如果field填充到元数据插槽fields没有column组件将自动包裹column组件。 表格视图template <view type="table" model="xxx" name="tableViewExample">…

    2024年5月23日
    1.2K00
  • 3.4.2 函数的开放级别与类型

    一、函数开放级别 我们在日常开发中通常会因为安全性,为方法定义不同的开放层级,或者通过应用分层把需要对web开放的接口统一定义在一个独立的应用中。oinone也提供类似的策略,所有逻辑都通过Function来归口统一管理,所以在Function是可以定义其开放级别有API、REMOTE、LOCAL三种类型,配置可多选。 四种自定义新增方式与开放级别的对应关系 函数 本地调用(LOCAL) 远程调用(REMOTE) 开放(API) 伴随模型新增函数 支持 支持【默认】 支持 独立新增函数绑定到模型 支持 支持【默认】 支持 独立新增函数只作公共逻辑单元 支持 支持【默认】 伴随ServerAction新增函数 必选 表3-4-2-1 四种自定义新增方式与开放级别的对应关系 远程调用(REMOTE) 如果函数的开放级别为本地调用,则不会发布远程服务和注册远程服务消费者 非数据管理器函数 提供者:如果函数定义在当前部署包的启动应用中,则主动发布远程服务提供者。 消费者:如果函数定义在部署依赖包中但未在当前部署包的启动应用中,则系统会默认注册远程消费者。发布注册的远程服务使用命名空间和函数编码进行路由。 所以非数据管理器函数的消费者并不需要感知该服务是否是本地提供还是远程提供。而服务提供者也不需要手动注册远程服务。 数据管理器类函数 提供者:如果数据管理器函数所在模型定义在当前部署包的启动应用中,则系统会主动发布数据管理器的远程服务作为数据管理器的远程服务提供者; 消费者:如果模型定义在部署依赖包中但未在当前部署包的启动应用中,则系统会主动注册数据管理器的远程服务消费者。 所以数据管理器类函数的消费者与服务提供者并不需要感知函数的远程调用。 二、函数类型 函数的类型语义分为:增、删、改、查,在编程模式下目前用于Function为API级别,生成GraphQL的Schema时放在query还是mutation。查放在query,其余放mutation。 三、函数分类 TBD 在无代码编辑器中,函数分类主要用函数选择的分类管理。

    Oinone 7天入门到精通 2024年5月23日
    1.3K00

Leave a Reply

登录后才能评论