编写详情组件

本组件代码可参看oak-generail-buiness/src/components/system/detail

现在,我们需要有一个组件对本System的信息进行读取并显示。在这里注意,在很多情况下,访问对象的过程是先get list获得满足条件的列表,再对其中的某一条数据进行get detail。但System对象比较特殊,它代表着当前正在访问的业务系统,因此不需要通过先设计list组件去查询其id,而是通过其它方法获得。我们先不关心这一过程具体如何实现,假设当前System的id已经得知。

逻辑层(index.ts)

在index.ts逻辑层,我们直接通过定义要访问的这条System数据的相关属性来获取它,代码大致如下:

export default OakComponent({
    isList: false,
    Entity: 'system',
    projection: {
        id: 1,
        name: 1,
        config: 1,
        description: 1,
        super: 1,
        folder: 1,
    },
    formData({ data }) {
        return data || {};
    },
});

代码非常简洁直观,我们通过调用OakComponet来定义一个组件,组件访问的对象是System;此组件不是一个List组件,这意味着需要告知此组件要访问的数据行的id是多少(这是通过向组件传入OakId来实现的);在projection中定义要访问这行数据的属性有哪些,这里的属性明显和上面System对象的定义是保持一致的;最后在formData方法中,将取到的数据属性返回(提供给渲染层)。

通过这几行短短的代码,我们就已经实现了将一条System数据从后台取到前台的功能,接下来我们来渲染它。

渲染页面(web.pc.tsx)

在web.pc.tsx中,我们像下面这样来编写代码:

import React from 'react';
import { Tabs } from 'antd';
import { WebComponentProps } from 'oak-frontend-base';

export default function Render(props: WebComponentProps<EntityDict, 'system', false, {
    id: string;
    config: Config;
    name: string;
    style: Style;
}>) {
    const { id, config, oakFullpath, name, style } = props.data;
    const { t } = props.methods;
    
    if (id) {
        return (
            // 利用name、stype等属性进行页面渲染
        );
    }
    return null;
}

Render函数的唯一参数props中,Oak框架将以WebComponentProps定义的格式,注入了两个属性:

  • data: 在data中存放从逻辑层传递过来的数据,以及Oak框架的一些通用变量(例如上面代码中的oakFullpath,这类变量都以oak开头)。从逻辑层传递过来的数据则包括:
    • formData中返回的数据(在上面的例子里,是从所取到的system行当中展开的属性)
    • data和property中声明的数据。
  • methods: 在methods中存放从逻辑层注入的方法,以及Oak框架注入的一些通用方法(例如上面代码当中的t方法,就是框架所注入的i18n方法)。其中,组件自身逻辑层注入的方法声明在OakComponent所声明的methods属性中。

使用组件

下面需要将上面的组件嵌入到系统的某一个页面当中。如果您在初始化项目时依赖了oak-general-business库,则这个组件已经被pages/console/system/config页面所引用。

在该目录下的web.pc.tsx中,可以看到如下代码(已进行简化):

import React from 'react';
import SystemPanel from 'oak-general-business/es/components/system/panel';
export default function Render(
    props: WebComponentProps<
        EntityDict,
        'system',
        false,
        {
            systemId: string;
        }
    >
) {
    const { systemId, oakFullpath } = props.data;
    if (oakFullpath) {
        return (
            <SystemPanel
                oakId={systemId}
                oakPath={`${oakFullpath}.system`}
            />
        );
    }

    return null;
}

在这个页面上,我们将渲染oak-general-business所提供的system/panel组件(上面描述的system/detail组件是panel中的一个tab页,见下图),并传入了两个非常重要的参数:

  • oakId:对于非List页面,都需要传入该行的ID,这里我们将当前的systemId传入(至于从哪里取到这个id的,可以参见同目录下的index.ts,在此不作展开)
  • oakPath:对于所有关联Entity的组件,都需要指出它们在页面中的“路径”。在这个例子里,我们将SystemPanel组件放置在当前组件(其实是页面,其路径由oakFullpath所指代)的system子路径下。

关于页面和组件的“路径”规范及意义,我们将在todo章节详细解释。

现在,执行npm run start:web,运行项目后,进入 localhost:3000/console/system/config 页面,可以看到类似下面的效果: systemPanel