Oinone平台可视化调试工具

为方便开发者定位问题,我们提供了可视化的调试工具。
该文档将介绍可视化调试工具的基本使用方法。

概述

调试工具分为两部分内容

  • 页面调试
  • 接口调试

PS:可视化调试工具仅能用于测试当前环境,无法跨环境测试。

页面调试概述

对当前页面的前端运行时上下文做了简单的解析,主要用于解决元数据权限视图等常见问题。

接口调试概述

对任何Oinone平台发起的标准请求,都可以使用该调试工具进行检查。主要用于解决异常堆栈权限SQL执行等相关问题的排查。

表述解释

为了方便表述,以下内容包含的后端模型字段/方法或GQL请求相关信息,其表述规则为:

{ClassSimpleName/GQLNamespace}#{field/method}

例如后端模型字段/方法:(该示例并不在平台代码中,仅作为展示)

public class ModuleDefinition {
    private String module;

    public void queryOne() {
        ...
    }
}

ClassSimpleNameJava类的类名,在上述例子中,ClassSimpleNameModuleDefinition
该Java类下的module字段可以表述为ModuleDefinition#module
该Java类下的queryOne方法可以表述为ModuleDefinition#queryOne

例如:

{
  viewActionQuery {
    load(
      ...
    ) {
      ...
    }
  }
}

GQLNamespace为GQL的首个字段在移除QueryMutation后缀后的结果,在上述例子中,GQLNamespaceviewAction
该GQL请求调用了load方法,可以将该请求简单表述为viewAction#load

PS:通常情况下,Java类名采用大驼峰表述,而GQL采用小驼峰表述。因此可以根据首字母为大写或小写区分其表述的具体内容。

以下所有内容表述均建立在此基础之上。

调试工具使用说明

进入调试工具页面

在需要调试的页面,通过修改浏览器URL的方式进入调试工具页面。如下图所示:

需要调试的页面

如需要调试的页面的URL如下所示:

http://127.0.0.1:9093/page;module=resource;viewType=TABLE;model=resource.ResourceCountryGroup;action=resource%23%E5%9B%BD%E5%AE%B6%E5%88%86%E7%BB%84;scene=resource%23%E5%9B%BD%E5%AE%B6%E5%88%86%E7%BB%84;target=OPEN_WINDOW;menu=%7B%22selectedKeys%22:%5B%22%E5%9B%BD%E5%AE%B6%E5%88%86%E7%BB%84%22%5D,%22openKeys%22:%5B%22%E5%9C%B0%E5%9D%80%E5%BA%93%22,%22%E5%9C%B0%E5%8C%BA%22%5D%7D

将page改为debug后即可进入该页面的调试页面,如下所示:

http://127.0.0.1:9093/debug;module=resource;viewType=TABLE;model=resource.ResourceCountryGroup;action=resource%23%E5%9B%BD%E5%AE%B6%E5%88%86%E7%BB%84;scene=resource%23%E5%9B%BD%E5%AE%B6%E5%88%86%E7%BB%84;target=OPEN_WINDOW;menu=%7B%22selectedKeys%22:%5B%22%E5%9B%BD%E5%AE%B6%E5%88%86%E7%BB%84%22%5D,%22openKeys%22:%5B%22%E5%9C%B0%E5%9D%80%E5%BA%93%22,%22%E5%9C%B0%E5%8C%BA%22%5D%7D

PS:通常我们会将新的URL改好后粘贴到新的浏览器标签页,以保留原页面可以继续查看相关信息。

调试工具页面

进入调试工具页面后,我们可以看到如下图所示的页面:

调试工具页面

调试页面信息概述

  • 下载全部调试数据:包括页面调试接口调试的全部数据。
    • 页面调试数据包含页面参数viewAction#load等页面数据。
    • 接口调试数据仅包含最近一次接口调试相关数据,未发起过请求将没有相关数据。

页面调试信息概述

  • 页面参数:当前URL中所有参数。
    • module:模块名称。ModuleDefinition#name
    • viewType:视图类型。ViewAction#resView#viewType
    • model:当前跳转动作模型编码。ViewAction#model
    • action:当前跳转动作名称。ViewAction#name
  • 页面信息:ViewAction#load接口返回的基础信息。
    • id:当前跳转动作ID。
    • model:同URL参数model
    • name:同URL参数action
    • title:用于浏览器标题以及面包屑显示名称备选项。
    • displayName:用于浏览器标题以及面包屑显示名称备选项。
    • contextType:数据交互上下文类型。
    • target:后端配置路由类型。不同于URL参数中的target。
    • domain:用户可视过滤条件,会根据规则回填至搜索区域
    • filter:用户不可视过滤条件,通过后端DataFilterHook追加至查询条件中。
    • module:跳转动作加载模块编码。
    • moduleName:跳转动作加载模块名称。
    • resModule:目标视图模块编码。
    • resModuleName:目标视图模块名称,用于模块跳转。
    • resViewId:目标视图ID。即当前页面视图ID。
    • resViewModel:目标视图模型编码。即当前页面视图模型编码。
    • resViewName:目标视图名称。即当前页面视图名称。
    • resViewType:目标视图类型。即当前页面视图类型。
    • maskName:后端配置母版名称。
    • layoutName:后端配置布局名称。
  • DSL:当前页面返回的未经处理的全部元数据信息。
  • Layout:当前页面使用的布局数据,当layoutName属性不存在时,该数据来自于前端注册的Layout。
  • Mask:当前页面使用的母版数据。
  • 页面字段:当前页面的全部字段元数据信息。(不包含引用视图)
  • 页面动作:当前页面的全部动作元数据信息。(不包含引用视图)
  • 运行时视图:当前页面的视图元数据信息。
  • 运行时DSL:经过解析的DSL元数据信息。
  • 运行时Layout:经过解析的布局信息。
  • 运行时渲染模板:主视图区域渲染的完整模板,即合并Layout和DSL后的最终结果。
  • 完整上下文:运行时上下文中的全部内容。

接口调试信息概述

  • 接口调试:用于发起一个fetch格式的浏览器请求。
    • 日志级别:根据不同的日志级别返回或多或少的调试信息。(暂未支持)
    • 发起请求:在下方输入框中粘贴fetch格式请求后可以发起真实的接口调用。(生产环境使用时可能产生数据,请确保接口幂等性以及在允许产生测试数据的环境中使用)
    • 重置:还原接口调试页面所有内容。
  • 接口响应结果:完整的接口返回结果。
  • 请求信息:当前请求的基本信息以及性能信息。
    • URL:调试请求的URL。
    • 请求方式:调试请求的Http请求方式。GET/POST
    • 完整请求耗时:从调试请求发起到前端响应并解析完成的时间。
    • 连接耗时:Http请求连接建立的时间。
    • 请求耗时:从调试请求发起到浏览器响应的时间。
    • 响应耗时:从浏览器响应到解析完成的时间。
    • 异常编码:调试请求响应结果中的首个异常信息的错误编码。
    • 异常信息:调试请求响应结果中的首个异常信息的错误信息。
    • 请求头:调试请求的Http请求头信息。
  • GQL#{index}:一个请求中可能包含多个GQL同时发起并调用多个对应的后端函数,index表示其对应的序号。
    • GQL:GQL内容
    • Variables:GQL参数
    • 异常抛出栈:请求出现异常的首个栈,即异常发生地。(无异常不返回)
    • 业务堆栈:不包含Oinone堆栈的调用堆栈信息。
    • 业务与Oinone堆栈:包含Oinone堆栈的调用堆栈信息。
    • 全部堆栈:未经处理的全部堆栈信息。
    • SQL调试:在当前请求链路中用到的所有执行SQL。
    • 函数调用链追踪:在当前请求链路中执行的全部Oinone函数基本信息及耗时。
    • GQL上下文:当前GQL上下文摘要。
    • 会话上下文:当前请求链路到结束的全部PamirsSession上下文信息。
    • 函数信息:当前GQL调用函数信息。
    • 模型信息:当前GQL调用函数对应模型的摘要信息。
    • 环境配置信息:服务端环境配置信息。
    • {GQLNamespace}#{GQLName}:当前执行函数的响应结果。

发起一次接口调试

以下示例均在Chrome浏览器中进行演示,不同浏览器可能存在差异。

使用浏览器查看接口及查看接口异常

如下图所示,通过检查F12打开浏览器控制台,并查看所有接口请求:

无异常接口
无异常接口

有异常接口

有异常接口

PS:一般情况下,所有Oinone请求的Http状态都为200,错误信息在errors数组中进行返回。

在浏览器控制台复制fetch格式请求

复制fetch格式请求

粘贴至接口调试输入框

粘贴至接口调试输入框

点击发起请求即可看到该接口的响应信息

点击发起请求

至此,我们已经完全介绍了现有调试工具的使用及页面展示内容的基本解释。未来我们还会根据需要调试的内容对该调试工具进行补充和完善,尽可能帮助开发者可以高效定位开发过程中遇到的常见问题。

下面,我们将提供几种查看调试信息的简单场景及步骤,帮助开发者可以快速上手并使用调试工具。

调试场景及检查步骤

通常情况下,Oinone平台遇到的问题都可以通过以下调试场景列举的检查步骤轻松定位问题。

当遇到无法通过调试工具定位问题时,可通过下载全部调试数据下载调试数据按钮,将下载的文件发送给Oinone售后服务工程师,并清楚描述遇到的问题,Oinone售后服务工程师会针对该问题提出解决方案或修复方案。

以下调试场景不区分使用页面调试接口调试,需要开发者根据遇到的问题自行判断该使用什么调试工具解决遇到的问题。

SQL示例解释

SQL示例中的表名可能与开发者调试的环境中的表名存在差异,需要开发者根据SQL示例找到对应的数据库及数据表并执行SQL。SQL示例中的参数需要根据开发者所遇到的问题进行调整。

SQL示例中并不包含租户隔离相关字段,请开发者根据运行环境自行补充查询条件。

{URL#model}表示使用URL参数中的model属性值进行替换,其他情况开发者可自行调整。

当页面中的字段/动作未正确显示时

检查当前用户是否具有该字段/动作的权限(超级管理员可跳过此步骤)

使用页面进行检查

步骤1:进入用户模块,查看该用户配置的角色列表,检查是否包含预期角色。
步骤2:进入权限模块,查看该用户所有角色的权限配置,检查是否包含字段的可见权限或动作的访问权限。

使用SQL进行检查

步骤1:根据当前登录用户获取用户ID(请开发者通过当前登录用户信息在user_pamirs_user表中自行查看)
步骤2:查看该用户配置的角色列表,检查是否包含预期角色。

-- 检查当前用户配置的角色列表
select id,name from auth_auth_role where id in (select role_id from auth_user_role_rel where user_id = {userId} and is_deleted = 0) and is_deleted = 0;

步骤3:根据角色列表分别查看字段和动作权限配置相关信息

检查当前跳转动作对应的视图是否为所需视图

步骤1:在页面调试DSL中搜索字段/动作相关信息,看看有没有正确返回。

如正确返回,可根据以下步骤进行检查:

  • 检查元数据是否补充完整。
  • 检查invisible属性是否按预期执行。

如未正确返回,可根据以下SQL示例在数据库中检查相关内容。

-- 检查ViewAction对应的视图是否为预期视图
select id,res_model,res_view_name from base_view_action where model = '{URL#model}' and name = '{URL#action}' and is_deleted = 0;

-- 检查视图的template是否存在字段/动作
select b.id,b.type,b.template from (select res_model,res_view_name from base_view_action where model = ''{URL#model}' and name = ''{URL#action}' and is_deleted = 0) a left join base_view b on a.res_model = b.model and a.res_view_name = b.name;

本文来自投稿,不代表Oinone社区立场,如若转载,请注明出处:https://doc.oinone.top/frontend/6669.html

(0)
张博昊的头像张博昊数式管理员
上一篇 2024年4月8日 pm10:15
下一篇 2024年4月18日 pm8:09

相关推荐

  • oinone的GraphQL使用指南

    如果之前没了解过GraphQL,可以先查看GraphQL的文档 为什么oinone要选用GraphQL? 我们先看一下oinone独特的元数据设计 介绍信息来源于Oinone 7天从入门到精通,如提示无权限,则需要申请 再看一下GraphQl的介绍 我们可以看出,GraphQL提供的特性可以满足我们对元数据的描述需求,因此我们选用GraphQL。 相关工具推荐 可视化gql请求工具: 官方下载地址 oinone工具包-win版 oinone工具包-mac版 模拟登录请求 点击“Refresh Schema”按钮手动同步后端的gql文档数据 点击“show Documentation”按钮查看gql文档,可以在搜索框内输入关键字查询相关文档

    2023年11月1日
    1.1K00
  • 如何提高自定义组件的开发效率

    引言 本文将通过前端的开发者模式带领大家提高自定义组件的开发效率 支持2024年9月6日之后用npm i安装的4.7.x之后的所有版本 介绍前端开发者模式 开发者模式的特性 浏览器控制台可以看到更多利于开发的日志输出 页面顶部状态栏消息模块的轮询接口,将只在页面刷新后请求一次,这样会减少开发阶段不必要的请求,以及解决后端断点调试的时候被消息轮询干扰的问题 页面视图的数据将不在走缓存,而是每次实时从base_view表里查询template字段获取,方便需要实时看通过xml修改的页面效果 如何进入开发者模式 通过在浏览器地址栏后追加;mode=dev刷新页面进入开发者模式,页面加载后可以在浏览器开发者工具的应用标签下的本地存储空间(即localStorage)中看到本标识的存储,如果想退出开发者模式可以手动清除该值 开发者模式的应用场景 1.通过控制台跳转到视图动作(ViewAction)的调试页面 页面刷新后,可以在浏览器开发者工具的控制台看到如下图的日志输出,直接点击该链接可以跳转到当前页面的调试链接弹窗视图动作、抽屉视图动作等以弹出层为展示效果的页面,之前的版本是无法进入调试链接查看的,现在可以在弹窗等视图动作点击后在控制台看到该链接点击进入调试页面 2.查看页面母版(mask)、布局(layout)的匹配情况 母版(mask)匹配结果布局(layout)匹配结果 3.查看视图组件(View)、字段组件(Field)、动作组件(Action)的匹配情况 通过浏览器开发者工具的控制台,我们可以看到每个视图、字段、字段匹配到的组件的class类名,这样我们就知道当前用的是那个组件,在自定义的时候可以在源码查看该组件类的实现代码,然后再选择是否继承该父类。另外我们在给组件定义SPI条件的时候,可以参考匹配入参和匹配结果内的属性。 匹配入参是当前元数据SPI的最全量注册条件 匹配结果是当前匹配到的组件的注册条件,一般情况下我们只需要在匹配结果的条件加上当前模型编码(model)、视图名称(viewName)、字段名称(name)、动作名称(actionName)等条件就可以完成自定义组件的覆盖。 在浏览器开发者工具的控制台,通过模型编码、视图名称、字段名称、动作名称等关键字快速搜索定位到需要查找的组件 控制台搜索快捷键:win系统通过ctrl+f,mac系统通过cmd+f 总结 在确保自定义部分代码最终正确被import导入到启动工程main.ts内的情况下,可以通过开发者模式在浏览器控制台打印的日志来排查组件未正确覆盖的问题。

    2024年9月6日
    1.7K00
  • 弹窗生命周期实践

    在oinone平台中,弹窗、抽屉是用户界面设计中最为常见的,而对于开发者而言,能够监听弹窗的生命周期事件通常是十分重要的,因为它提供了一个机会去执行一些逻辑。在这篇文章中,我们将深入探讨如何监听弹窗、抽屉生命周期事件,并讨论一些可能的应用场景。 首先,我们来实现一个监听弹窗销毁的事件。 让我们看一下提供的代码片段: // 1: 自定义打开弹窗的动作 @SPI.ClassFactory( BaseActionWidget.Token({ actionType: [ActionType.View], target: [ViewActionTarget.Dialog], model: 'model', name: 'name' }) ) export class MyDialogViewActionWidget extends DialogViewActionWidget { protected subscribePopupDispose = (manager: IPopupManager, instance: IPopupInstance, action) => { // 自定义销毁弹窗后的逻辑 }; protected mounted() { PopupManager.INSTANCE.onDispose(this.subscribePopupDispose.bind(this)); } protected unmounted() { PopupManager.INSTANCE.clearOnDispose(this.subscribePopupDispose.bind(this)); } } 在上面的代码中,我们自定义了打开弹窗的动作,并且监听了弹窗销毁事件。 让我们逐步解析这段代码: 1: subscribePopupDispose 是一个函数,作为弹窗销毁事件的处理程序。它接收三个参数:manager、instance 和 action。 manager: 弹窗事件管理器 instance: 弹窗实例 action: 操作弹窗的动作,如果是点击弹窗右上角的关闭按钮,那action为null 2: 组件挂载的时候,进行监听. 4: 最后组件销毁的时候需要清除对应的监听 那么,如果监听到弹窗销毁,我们可以执行什么样的逻辑呢? 1: 更新相关组件状态: 弹窗销毁后,可能需要更新其他组件的状态。通过 popupWidget 可以获取到弹窗相关的信息,进而执行一些状态更新操作。 2: 处理弹窗销毁时的数据或动作: 在 subscribePopupDispose 函数中,action 参数含一些关于弹窗销毁时的动作信息,如果是点击弹窗右上角的销毁按钮,那action为null。我们可以根据这些信息执行相应的逻辑,例如更新界面状态、保存用户输入等 3: 触发其他操作: 弹窗销毁后,可能需要触发一些后续操作,比如显示另一个弹窗、发起网络请求等。 完整的生命周期 方法名 功能描述 onPush(fn) 监听 弹出窗口被推入时的事件处理器 clearOnPush(fn) 清除onPush事件的监听 onCreated(fn) 监听 弹出窗口创建时的事件处理器 clearOnCreated(fn) 清除onCreated事件的监听 onOpen(fn) 监听 弹出窗口打开时的事件处理器 clearOnOpen(fn) 清除onOpen事件的监听 onClose(fn) 监听 弹出窗口关闭时的事件处理器 clearOnClose(fn) 清除onClose事件的监听 onDispose(fn) 监听 弹出窗口被销毁时的事件处理器 clearOnDispose(fn) 清除onDispose事件的监听 onDisposeAll(fn) 监听 所有弹出窗口被销毁时的事件处理器 clearOnDisposeAll(fn) 清除onDisposeAll事件的监听 结语 开发者可以更灵活地响应用户操作,提升用户体验。在实际项目中,根据应用需求和设计,可以根据以上优化逻辑定制具体的处理流程。希望这篇文章为你提供了更深入的理解。

    2023年11月17日
    92400
  • 自定义的复杂字段配置透出字段

    学习这篇文章之前,需要先学会使用在界面设计器自定义一个前端组件,如果您还不会,可以先看这篇文章 默认情况下,当开前端发人员自定义了一个复杂字段,比如M2O、O2M、M2M的字段,那么Graphql查询的时候,只会查询id跟name这两个字段,如果还想查询字段的字段,那么可以通过配置化的方式来处理 1: 在界面设计器的组件区域中新增对应的字段 2: 设计元件,在模型区域中搜索选项字段列表,拖到设计区域,然后保存 3: 去对应的设计页面,刷新下页面,选中对应的字段,可以看到右侧有选项字段列表4: 输入期望Graphql查询字段,保存发布

    2023年11月9日
    1.3K00
  • Class Component(ts)(v4)

    Class Component 一种使用typescript的class声明组件的方式。 IWidget类型声明 IWidget是平台内所有组件的统一接口定义,也是一个组件定义的最小集。 /** * 组件构造器 */ export type WidgetConstructor<Props extends WidgetProps, Widget extends IWidget<Props>> = Constructor<Widget>; /** * 组件属性 */ export interface WidgetProps { [key: string]: unknown; } /** * 组件 */ export interface IWidget<Props extends WidgetProps = WidgetProps> extends DisposableSupported { /** * 获取当前组件响应式对象 * @return this */ getOperator(); /** * 组件初始化 * @param props 属性 */ initialize(props: Props); /** * 创建子组件 * @param constructor 子组件构造器 * @param slotName 插槽名称 * @param props 属性 * @param specifiedIndex 插入/替换指定索引的子组件 */ createWidget<ChildProps extends WidgetProps = WidgetProps>( constructor: WidgetConstructor<ChildProps, IWidget<ChildProps>>, slotName?: string, props?: ChildProps, specifiedIndex?: number ); } Widget Widget是平台实现的类似于Class Component组件抽象基类,定义了包括渲染、生命周期、provider/inject、watch等相关功能。 export abstract class Widget<Props extends WidgetProps = WidgetProps, R = unknown> implements IWidget<Props> { /** * 添加事件监听 * * @param {string} path 监听的路径 * @param {deep?:boolean;immediate?:boolean} options? * * @example * * @Widget.Watch('formData.name', {deep: true, immediate: true}) * private watchName(name: string) { * … todo * } * */ protected static Watch(path: string, options?: { deep?: boolean; immediate?: boolean }); /** * 可以用来处理不同widget之间的通讯,当被订阅的时候,会将默认值发送出去 * * @param {Symbol} name 唯一标示 * @param {unknown} value? 默认值 * * @example *…

    2023年11月1日
    1.2K00

Leave a Reply

登录后才能评论