Framework Overview
The Oinone Kunlun framework provides a set of functionalities for Oinone Pamirs, aiding in building Oinone applications that run in browsers. As a single-page application (SPA), the Oinone Kunlun framework is based on the Vue framework and offers a set of features, commonly referred to as the Web client (accessible via URL/web).
At a high level, the Web client is an SPA: when users perform actions, it doesn't request a full page from the server each time but only fetches the required content and replaces/updates the current screen accordingly. It also manages URLs to keep them synchronized with the current state.
The Oinone Kunlun framework (in whole or part) can be used in other scenarios, but this document focuses on the Web client.
I. Technical Stack Description
The Oinone Kunlun framework is implemented based on the Vue
framework, with its underlying Oio
component library built upon the Ant Design Vue
and Element Plus
component libraries.
II. Code Structure
Similar to the common Vue
framework structure, the src
directory contains all TypeScript
(along with CSS
and Vue
components) codebase. Below is a list of subfolders recommended by Oinone:
- mask: Stores master definitions and registration-related code
- layout: Stores layout definitions and registration-related code
- types: Stores all possible public type definitions
- field: Stores all field components
- action: Stores all action components
- view: Stores all view components
- service: Stores all backend service request code (some frameworks suggest using an api directory)
- theme: Stores all theme-related code
For the field
subfolder, Oinone recommends classifying field components by view type
, with possible subfolders including:
- field/table: Stores table (TABLE) field components
- field/form: Stores form (FORM) field components
- field/detail: Stores detail (DETAIL) field components
- field/gallery: Stores gallery (GALLERY) field components
For the field/table subfolder, Oinone suggests classifying field components by field business type
, with possible subfolders such as:
- field/table/string: Stores table text type (String) field components
- field/table/integer: Stores table integer type (Integer) field components
A possible complete directory structure is:
src
├─ mask
├─ layout
├─ field
│ ├─ table
│ │ ├─ integer
│ │ ├─ float
│ │ ├─ boolean
│ │ ├─ enum
│ │ ├─ string
│ │ ├─ text
│ │ ├─ html
│ │ ├─ datetime
│ │ ├─ date
│ │ ├─ time
│ │ ├─ year
│ │ ├─ money
│ │ ├─ map
│ │ ├─ m2o
│ │ ├─ o2m
│ │ └─ m2m
│ ├─ form
│ ├─ detail
│ └─ gallery
├─ action
├─ view
├─ types
├─ service
└─ theme
Note
For code structure division, we should select a structure suitable for the business project based on actual business needs, rather than adhering to a single structure. The above structure is just one example provided by Oinone for component standardization, which is suitable for beginners and aligns with Oinone metadata classification.
For more on R&D paradigms, refer to: Widget Component Design Paradigm
II. Web Client Architecture
As mentioned, the Web client is an application implemented via the Widget framework. Here's a simplified version of its default master:
<mask>
<header />
<container>
<nav-menu />
<main-view />
</container>
</mask>
It essentially consists of a top bar (header), navigation menu (nav-menu), and main content distribution area (main-view).
III. Environment
As a Web client, Oinone Kunlun uses dotenv-webpack
for build-time
static environment variables and provides RuntimeConfig
for runtime
dynamic environment variables.
Note
For more on environment configuration, refer to: Environment
IV. Context
In Oinone Kunlun, "context" is a crucial concept: it provides components with rendering, configuration, metadata, and other information, enabling any system component to behave appropriately based on this information. In a sense, it's like an information package propagated everywhere, useful in scenarios where, for example, input fields need to behave differently in forms and details or activate/deactivate certain functions in components.
In any component, you can use these two context objects with code like:
protected doSomething() {
const { metadataRuntimeContext, rootRuntimeContext } = this;
// do something.
}
Warning
Never attempt to modify metadata-related properties; they must remain stable for retrieval in any component.
Note
For more on context, refer to: Context
V. Building Blocks
Web clients are typically built using several abstract types: Router, Render, Service, Widget, Component.
Note
In Oinone Kunlun, Widget specifically refers to components defined by TypeScript Class and inheriting from VueWidget, also abbreviated as TS components; Component refers to Vue components defined via the Vue framework. (If Oinone Kunlun provides a React-based implementation, Component refers to React components defined via the React framework.)
(Ⅰ) Router
In SPAs, the routing system essentially triggers a set of behaviors by modifying the browser URL. In Oinone Kunlun, the routing system, based on rxjs
, is core to page updates. In any component, you can use all routing system functions via useRouter
and useMatched
.
Fetch browser variables:
useMatched().matched.segmentParams
Obtain the router instance and handle page parameter changes:
protected $router!: Router;
protected doSomething() {
this.$router.push({
segments: [
{
path: 'page',
parameters: {
...
}
}
]
});
}
protected beforeMount() {
this.$router = useRouter().router;
}
Subscribe to routing changes:
protected watchRouter() {
useMatched()
.getMatched$()
.subscribe((matched: Matched) => {
// do something.
});
}
protected beforeMount() {
this.watchRouter();
}
Note
For more on routing, refer to: Router Service
(Ⅱ) Render
Oinone Kunlun provides a rendering function based on JSON data structures, handling structures like:
{
"dslNodeType": "",
...,
"widgets": [
{
"dslNodeType": "",
"widgets": [
...
]
},
...
]
}
Under this structure, each node is converted to VNode for processing and rendering via the Vue framework.
Note
For more on rendering, refer to: View
(Ⅲ) Service
Oinone Kunlun uses the GraphQL
protocol for front-end to back-end interaction
. HttpClient
is implemented based on apollo-client
, allowing requests to the backend from anywhere. For example:
export class ResourceCountryGroupService {
public static async queryListByWrapper(): Promise<ResourceCountryGroup[]> {
const gql = `{
resourceCountryGroupQuery {
queryListByWrapper(queryWrapper: {rsql: "1==1"}) {
id
code
name
}
}
}`;
const res = await http.query<ResourceCountryGroup[]>(MODULE_NAME, gql);
return res.data['resourceCountryGroupQuery']['queryListByWrapper'];
}
}
Note
For more on HTTP requests, refer to: HttpClient Service
(Ⅳ) Widget
In Oinone Kunlun, the Widget
framework is the core module. All visible components on the page are defined via the Widget
framework and rendered in the page.
Registration and lookup of Widget
components are done using the SPI
framework, which essentially stores a multi-fork tree via predefined dimensions and searches using a weighted longest path matching algorithm.
Each component type has abstract dimensions, all describing the component's usage location. Generally, the more "precise" the location description, the higher the priority of the component when rendered in that location. Components registered later will overwrite those registered earlier with identical location descriptions.
In the Widget framework, different dslNodeType
uses different SPI.Token
for registration and usage:
dslNodeType | SPI.Token | Related Documentation |
---|---|---|
view | BaseView | View |
element | BaseElementWidget | Element |
pack | BasePackWidget | Pack |
action | BaseActionWidget | Action |
field | BaseFieldWidget | Field |
(Ⅴ) Component
In Oinone Kunlun, the Widget framework provides component registration and lookup, but specific page rendering is done via Component. Oinone Kunlun implements a set of components corresponding to the Widget framework based on the Vue framework. Additionally, Component provides a set of Oio
component libraries for standard components, handling standard API
and theme
-related content.
During Oinone usage, you can directly use Oio
components for secondary development without worrying about styles, themes, etc. For example, an input box can use oio-input
:
<oio-input v-model:value="value" />
Note
For more on Oio Component, refer to: Vue UI Antd
VI. Expression
Oinone Kunlun includes a built-in small expression interpreter for evaluating small expressions (single-line expressions), crucial because most DSL configurations support attribute calculation using expressions.
For example:
<field data="phoneCode" label="国家码" />
<field data="phoneNumber" label="手机号" />
<field data="phone" compute="activeRecord.phoneCode + ' ' + activeRecord.phoneNumber" />
Note
Almost all expressions include context variables like activeRecord
, rootRecord
, and openerRecord
, but their meanings vary across components and views. You can also use some built-in Oinone functions for advanced calculations in expressions or even define custom functions for use in expressions.
For more on expressions, refer to: Expression Service
For more on built-in functions, refer to: Function API - Built-in Functions
VII. Domains
Broadly speaking, domains in Oinone Kunlun represent sets of records meeting specific conditions.
RSQL Expression is the syntax for domains, similar to SQL condition expressions. Allowed operators vary by field business type, determined by data storage structure.
In Oinone Kunlun, we divide domains into visible domains (domain) and invisible domains (filter), a division that helps present valid record sets to users in practice.
For example, in a many-to-one (M2O)
select box (Select)
component, we can use domain
to show users the set of active
records for selection:
<field data="relationOne" widget="Select" domain="state == ACTIVED" />