Build a Dynamic Material Table with AirPower-Web, TypeScript, and Vue3
Learn how to quickly set up a material management table using the AirPower-Web library with TypeScript, Vue3, and ElementPlus, covering package installation, entity and service definitions, component integration, customization options, and handling varied backend interfaces, all illustrated with code snippets and diagrams.
Preface
❝ If you are using TypeScript, Vue3, and ElementPlus, you might want to check out this component package. ❞
Previously we mentioned using decorators to configure tables and open‑sourced the AirPower4T project, but many found sub‑repo usage inconvenient.
Therefore we split AirPower4T into independent packages:
AirPower-Transformer – core data transformation library, a wrapper around class-transformer.
AirPower-Enum – core enum library.
AirPower-i18n – core internationalization library.
AirPower-Util – core utility library.
AirPower-Web – the next library of AirPower4T, designed with decoupling.
We will focus on AirPower-Web , which provides core functionality and wraps some ElementPlus components, allowing it to replace AirPower4T.
The target table layout is shown below:
Quick Start
Initialize the project (omitted). Install the package:
Install @airpower/web
You can install via any of the following commands:
npm install @airpower/web
# or
yarn add @airpower/web
# or
cnpm install @airpower/web
# or ...Declare the entity class for the table
The material table has columns: name (string), materialType (enum), spc (string), code (string). Use AirPower-Enum for the enum:
import { WebColor, WebEnum } from '@airpower/web';
/**
* # Material type enum
*/
export class MaterialTypeEnum extends WebEnum {
/** Self‑produced */
static readonly PRODUCT = new MaterialTypeEnum(1, '自产品')
.setColor(WebColor.SUCCESS);
/** Purchased */
static readonly PURCHASE = new MaterialTypeEnum(2, '外购品')
.setColor(WebColor.WARNING);
}Then declare the entity with decorators:
@Model({
label: '物料',
})
export class MaterialEntity extends BaseEntity {
@Table({
copy: true,
force: true,
})
@Search()
@Field({
label: '物料编码',
})
code!: string;
@Table()
@Search()
@Field({
label: '物料名称',
})
name!: string;
@Table({
color: true,
width: 100,
})
@Search()
@Field({
label: '物料类型',
dictionary: MaterialTypeEnum,
})
materialType!: number;
@Table({
copy: true,
})
@Field({
label: '规格型号',
})
spc!: string;
}Implement the service for the entity
The service binds the entity and defines the base URL:
export class MaterialService extends AbstractBaseService<MaterialEntity> {
// Bind the entity class
entityClass = MaterialEntity;
// Base API path
baseUrl = 'material';
}Now you can start building the page.
Implement the page
Create list.vue:
<template>
<APanel>
<!-- Use ATable component -->
<ATable
v-loading="isLoading"
:data-list="response.list"
:entity="MaterialEntity"
:service="MaterialService"
@xxx="onXxx"
/>
<template #footerLeft>
<APage :response="response" @changed="onPageChanged" />
</template>
</APanel>
</template>
<script lang="ts" setup>
const {
isLoading,
response,
onPageChanged,
onXxx,
} = useTable(MaterialService);
</script>This completes column definition, custom column selection, and various column states.
❝ If your table needs events such as add, edit, delete, detail, sort, pagination, selection, etc., you can bind them to ATable with @xxx="onXxx" , and most of these events are available from the useTable hook. ❞
More customizations
If your backend differs in API names, data structures, or status codes, you can adjust:
Different API names
Configure baseUrl or override urlForXXX:
export class MaterialService extends AbstractBaseService<MaterialEntity> {
entityClass = MaterialEntity;
baseUrl = 'material';
// Custom page endpoint
protected urlGetPage: string = 'paaaaaaaaage';
}Or override the method directly:
export class MaterialService extends AbstractBaseService<MaterialEntity> {
entityClass = MaterialEntity;
baseUrl = 'material';
async getPage(request: QueryRequest<MaterialEntity>, apiUrl?: string): Promise<QueryResponsePage<MaterialEntity>> {
const responsePage = await this.api('getPage', '物料').post(request, QueryResponsePage<E>);
responsePage.list = responsePage.list.map(json => Transformer.parse(json, this.entityClass));
return responsePage;
}
}Different data structures
Override relevant methods to adapt to your response format.
Different status codes
Configure global HTTP success code via WebConfig:
// main.ts
WebConfig.successCode = 200000;
// other configurationsOr rewrite service methods to use your own logic.
What else is provided
The library is used in the SPMS_Web project; see the open‑source repository for more examples.
Design diagrams are also available.
That’s all for today.
Design image:
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
