Chọn component theo việc
Decide from the job on the screen, not from the data. One line per job: component · props that make it right · the mistake to avoid.
Pages & navigation
- App frame, menu per role →
ProLayout(layout="mix",route.routesfiltered by role,menuItemRender→ router,avatarProps+actionsRender) · not a hand-madeLayout.Sider. - Page title + actions + tabs →
PageContainer(title,subTitle,extra=[buttons],tabList/onTabChange,contentfor a summary line) · not<h1>+<Space>. - Long form/detail with a sticky save bar →
FooterToolbar(extra= total/status, children = buttons).
Work queues (“what do I need to do”)
- Records to process by status →
ProTablewithtoolbar.menutabs + Badge counts (type: "tab"),request+params={{ tab }}, row actions asvalueType: "option",rowSelection+tableAlertOptionRenderfor bulk approve · notTable+ your own fetch. - Items moving through stages (production, pipeline, tickets) → board:
ProCard split="vertical"(orRow/Col) with one column per status, each aProList/Cardstack, status change by a button/Dropdownon the card (no drag library in the allowlist) · not a table when the user thinks in columns. - My inbox / approvals →
ProList(metas:title,description,subTitleTag,actions,extra) withtoolbar.menutabs · good for 1–3 actions per item. - Today’s tasks for one role →
ProCardgrid of smallProLists (“Cần giao hôm nay”, “Hàng sắp về”…) on one page.
Lists of records
- Searchable list →
ProTable(search={{ labelWidth: "auto" }}built from columns,valueEnumfor status/select,valueType: "money" | "percent" | "dateTime" | "dateRange",hideInSearch/hideInTable,fieldProps),pagination.showTotal,options={{ density: true, setting: false }}· server returns{ data, total }. - Few filters, compact →
toolbar.filterwithLightFilter· many → ProTablesearchorQueryFilteron a non-table page. - Ordered rules / priorities the user re-orders →
DragSortTable(dragSortKey,onDragSortEnd). - Gallery / product cards →
ProListgrid={{ gutter: 16, column: 3 }}orCard+Image·CheckCard.Groupwhen the user picks one/many of them. - Tree data (categories, BOM levels, org) →
Table/ProTablewithchildrenrows, orTree/TreeSelectfor picking.
Entering data
- Create/edit a record from a list →
DrawerForm(≥ 6 fields or line items) /ModalForm(≤ 5 fields),trigger= the button,onFinishreturnstrueto close,initialValuesfor edit · not a separate page. - Document with line items (order, purchase, invoice, BOM) →
EditableProTableinside the form (recordCreatorProps,editable.type="multiple", money columns read-only and computed) orProFormListfor short repeated groups; show the server-computed total inFooterToolbar/ProDescriptionsafter save · never let the client send prices or totals. - Field depends on another (customer → address, product → unit price shown) →
ProFormDependency/Form.useWatch; options from the API withProFormSelect request+showSearch(debounceTime). - Money / quantity / percent →
ProFormMoney(locale="vi-VN"),ProFormDigit(min,fieldProps.precision),ProFormSlider/ProFormDigit+%. - Dates →
ProFormDatePicker/ProFormDateRangePickerwithtransformto the API format (neverformatalone — gatecode.proform-date-format-submit). - Multi-step setup / onboarding →
StepsForm(StepsForm.StepFormper step,onFinishon the last). - Same fields reused in table + form + detail → one
columnsarray +BetaSchemaForm(layoutType="DrawerForm"|"ModalForm"|"Form"). - Confirm a risky action →
Popconfirm(one click) · with a reason →ModalFormwith a requiredProFormTextArea· irreversible bulk →Modal.confirmstating counts and money. - Files / photos →
Upload(listType="picture-card"for photos,beforeUploadto check type/size,customRequest→ your API or apresignPutURL), show withImage(preview).
Reading a record
- Record header →
PageContainertitle+ statusTag+extraactions allowed in this status for this role (hide, don’t disable, what the role can never do). - Fields →
ProDescriptions(column={{ xs: 1, md: 2, xl: 3 }}, samevalueTypes as the table,dataSourcefrom the detail call). - Where it is in its lifecycle →
Steps(currentfrom status,status="error"when cancelled) · history →Timeline(who · what · when, newest first). - Related lists (lines, payments, movements) →
ProTablewithsearch={false},toolBarRender={false},pagination={false},summaryrow for totals. - Printable document (delivery note, invoice) → plain
Descriptions+Table(bordered,size="small") on a page with a “In” button callingwindow.print().
Numbers & dashboards
- KPI row →
StatisticCard.Group(statistic.value,valueType,descriptionwithtrendup/down vs last period,chartmini) · one KPI per card, max 4–6. - Trend over time →
Line/Area· compare categories →Column/Bar· share of a whole (≤ 6 parts) →PiewithinnerRadius· target vs actual →Progress/Gauge/Liquid· two measures, two scales →DualAxes· stage drop-off →Funnel(all from@ant-design/charts; setheight,autoFit, axis label formatter for money). - Ranked list (top customers, late orders) →
ProList/Tablesize small withProgressorStatisticper row. - Calendar of due dates / bookings →
CalendarwithcellRender(antd v6 — notdateCellRender) orProTablegrouped by date.
Feedback & states
- Loading →
Skeleton/tableloading; empty →Emptywith one sentence + the next action button; error / no permission / done →Result(status="403" | "404" | "success" | "warning"). - Short success/error after an action →
App.useApp().message; long-running or cross-page →notification; server 4xx text shown as-is. - Status everywhere →
Badge status/Tag colorfrom onevalueEnummap; overdue/short →Typography.Text type="danger". - Guided first run →
Tour· watermark on exported/printed pages →Watermark.
AI features (only if the product asks for them) → @ant-design/x: chat = Bubble.List + Sender, suggestions = Prompts, conversations = Conversations; backend via app/std/openai.
Last updated on