@infly/ui
v1.0.23
Published
Infly 公共 UI 组件库(Vue 2)
Downloads
751
Maintainers
Readme
@infly/ui
@infly/ui 是运营端通用 Vue2 组件库。当前业务页面优先使用 InflyList、InflyForm、InflyDialog 等组件承载筛选、表格、分页、详情展示和弹窗表单。
组件内部的框架无关工具来自 @infly/ts-libs。依赖 Vue 实例、请求实例或 Element UI 消息能力的全局 mixin 不属于 UI 公共入口;Vue2 应用统一从 @infly/libs/adapters/vue2/module/ 引入对应适配器。
修改 InflyList 或 InflyForm 时必须同步更新本文档:新增 prop、事件、插槽、字段配置、列类型或表单类型,都要补充至少一个可复制的使用示例。
InflyList
InflyList 组合了 el-tabs、InflyForm、el-table 和分页。适合“tab + 筛选区 + 操作按钮 + 表格 + 分页”的运营端页面。
基础示例
<template>
<InflyList
ref="listRef"
:formData="formData"
:reqUrl="reqUrl"
:filterList="filterList"
:btnList="btnList"
:columns="columns"
:dealParams="dealParams"
:customRender="customRender"
@tab-change="handleTabChange"
/>
</template>
<script>
export default {
data() {
return {
reqUrl: "/admin/reconciliation/bills/",
formData: { page: 1, pagesize: 10, total: 0 },
filterList: [
{ label: "账单年份", name: "bill_year", type: "el-select", options: [{ label: "2026", value: "2026" }], clearable: true },
{ label: "关键词", name: "keyword", type: "infly-input", placeholder: "账单ID/金额/操作人", clearable: true }
],
btnList: [
{ label: "导出", type: "primary", btnEvent: () => this.exportList() }
],
columns: [
{ label: "账单ID", prop: "id", width: "90px" },
{ label: "账单金额", prop: "total_consume_amount", type: "render", minWidth: "140px" }
]
};
},
methods: {
dealParams(params) {
return { ...params, keyword: (params.keyword || "").trim() };
},
customRender(row, prop) {
if (prop === "total_consume_amount") return `¥${row[prop] || "0.00"}`;
return row[prop] || "-";
}
}
};
</script>Props
| Prop | 类型 | 默认值 | 说明 | 示例 |
| --- | --- | --- | --- | --- |
| formData | Object | 必填 | 查询参数、分页参数和总数容器。组件会写入 page、pagesize、total。 | :formData="{ page: 1, pagesize: 10, total: 0 }" |
| defaultTabName | String | "" | 默认激活的一级 tab 名称。 | :defaultTabName="'billList'" |
| hideTab | Boolean | false | 隐藏一级 tab 头部。 | hideTab |
| tabList | Array | [{}] | 一级 tab 配置,直接透传给 el-tab-pane;每项可带 reqUrl。 | [{ label: "账单列表", name: "billList", reqUrl: "/admin/reconciliation/bills/" }] |
| filterList | Array | [] | 传给 InflyForm 的筛选/详情字段配置。 | [{ label: "关键词", name: "keyword", type: "infly-input" }] |
| columns | Array | 必填 | 表格列配置,支持普通列、操作列、特殊类型、多级表头。 | [{ label: "ID", prop: "id" }] |
| btnList | Array | [] | 顶部操作按钮,传给 InflyForm。 | [{ label: "上传", type: "blue", btnEvent: this.openDialog }] |
| outSideReqParams | Object | {} | 额外请求参数,每次请求合并到 formData 后。 | :outSideReqParams="{ bill_id: billId }" |
| reqUrl | String | "" | 列表接口地址;为空时会尝试使用当前 tab 的 reqUrl。 | reqUrl="/admin/reconciliation/logs/" |
| reqMethod | String | "get" | 请求方法,使用 this.$axios[reqMethod]。 | reqMethod="post" |
| defaultInit | Boolean | true | 创建后是否自动请求。详情页常设为 false,待详情信息加载后手动请求。 | :defaultInit="false" |
| dealParams | Function | null | 请求前处理参数,返回对象会替换最终参数。 | :dealParams="(params) => ({ ...params, status: params.status || undefined })" |
| dealRes | Function | null | 请求后处理响应,返回对象会作为最终响应。 | :dealRes="(res) => ({ lists: res.data, counts: res.total })" |
| initEventName | String | "initData" | 查询后额外 emit 的事件名。 | initEventName="refresh" |
| hideDivider | Boolean | false | 隐藏筛选区和表格之间的分隔线。 | hideDivider |
| isInnerList | Boolean | false | 内嵌列表样式。 | isInnerList |
| isTopList | Boolean | true | 页面顶部列表样式。 | :isTopList="false" |
| hideEmptyTag | Boolean | false | el-tag 列为空时不渲染 tag。 | hideEmptyTag |
| hideJumpPageButton | Boolean | false | 隐藏分页右侧“跳转”按钮。 | hideJumpPageButton |
| customRender | Function | 取 row[prop] | type: "render"、custom、el-popover 的统一渲染函数,可返回字符串或 VNode。 | customRender(row, prop) { return row[prop] || "-" } |
| tableProps | Object | {} | 透传给 el-table,也支持 dataList 覆盖内部请求数据。 | :tableProps="{ stripe: true, dataList: localRows }" |
| formProps | Object | { "label-width": "80px" } | 透传给内部 InflyForm。 | :formProps="{ layout: 'inline-seamless', 'label-width': '120px' }" |
| emptyText | String | "" | 普通单元格空值文案。 | emptyText="-" |
| tabsProps | Object | { type: "border-card" } | 透传给 el-tabs。 | :tabsProps="{ type: '' }" |
事件
| 事件 | 触发时机 | 示例 |
| --- | --- | --- |
| initData | 调用 initData() 后触发;名称可由 initEventName 改写。 | @initData="afterSearch" |
| tab-change / tabChange | 一级 tab 切换时触发,参数包含原始 tab 配置和 activityTab。 | @tab-change="handleTabChange" |
| sec-tab-change / secTabChange | 内部 InflyForm 的 secTab 切换时触发。 | @secTabChange="handleSecTabChange" |
| request-error | 请求异常或请求方法不支持时触发。 | @request-error="handleError" |
| request-timeout | 单次请求超过 60 秒时触发。 | @request-timeout="handleTimeout" |
插槽
| 插槽 | 位置 | 示例 |
| --- | --- | --- |
| pretop | el-tabs 内、tab pane 前。 | <template #pretop><div>顶部说明</div></template> |
| prepend | 每个 tab pane 的表单前。 | <template #prepend><div class="tips">说明</div></template> |
| replace | 替换表单、分隔线、表格和分页整体。 | <template #replace>自定义完整内容</template> |
| replaceTable | 只替换表格和分页。 | <template #replaceTable><CustomTable /></template> |
| customRender | 传给 InflyForm 的 type: "customRender" 字段。 | <template #customRender="{ item }"><MyInput :item="item" /></template> |
| expand | type: "expand" 展开列内容。 | <template #expand="{ row }">{{ row.detail }}</template> |
| [prop] | 表格列同名具名插槽,优先级高于列 type。 | <template #status="{ row }"><el-tag>{{ row.status_str }}</el-tag></template> |
列配置
列配置会把内部字段之外的属性透传给 el-table-column,例如 label、prop、width、minWidth、fixed、sortable、showOverflowTooltip。默认 align 为 center。
内部字段包括:children、columns、type、buttonList、className、isHide、click、options、optionKeyField、optionValueField、propValueField、mapField、render。
普通列
columns: [
{ label: "账单ID", prop: "id", width: "90px" },
{ label: "所属机构", prop: "level_name", minWidth: "150px", showOverflowTooltip: true }
]默认列:selection、index、expand
columns: [
{ type: "selection", width: 55 },
{ type: "index", label: "序号", width: 70 },
{ type: "expand", width: 50 },
{ label: "名称", prop: "name" }
]<InflyList :formData="formData" v-bind="pageConfig">
<template #expand="{ row }">
<pre>{{ row }}</pre>
</template>
</InflyList>type: "render" / custom
columns: [
{ label: "消耗金额(含税)", prop: "total_consume_amount_with_tax", type: "render" }
],
customRender(row, prop) {
return `<span class="text-red">¥${row[prop] || "0.00"}</span>`;
}type: "el-tag"
columns: [
{
label: "状态",
prop: "status",
type: "el-tag",
options: [
{ value: "pending", name: "待处理", tagType: "info" },
{ value: "completed", name: "完成", tagType: "success" },
{ value: "failed", name: "失败", tagType: "danger" }
]
}
]操作列:type: "el-button" 或 buttonList
buttonList 每一项除 name、label、className、isShow、isHide、click、btnEvent 外,其余属性会透传给 el-button,例如 size、plain、disabled、loading、icon。
columns: [
{
label: "操作",
prop: "action",
type: "el-button",
fixed: "right",
width: "120px",
buttonList: [
{
name: "查看详情",
type: "text",
size: "mini",
className: "text-blue",
disabled: false,
isShow: (row) => row.status !== "deleted",
click: (row) => this.goDetail(row)
}
]
}
]type: "el-image"
columns: [
{ label: "图片", prop: "cover_url", type: "el-image", width: 80, fit: "cover" }
]多级表头
支持 children 或 columns,叶子列继续使用普通列能力。
columns: [
{ label: "日期", prop: "date", width: 150 },
{
label: "配送信息",
children: [
{ label: "姓名", prop: "name", width: 120 },
{
label: "地址",
columns: [
{ label: "省份", prop: "province", width: 120 },
{ label: "市区", prop: "city", width: 120 },
{ label: "地址", prop: "address", minWidth: 200, showOverflowTooltip: true }
]
}
]
}
]常用页面模式
一级 tab 切换不同接口和列
pageConfig() {
return {
reqUrl: this.currentTabConfig.reqUrl,
tabList: [
{ label: "账单列表", name: "billList" },
{ label: "操作日志", name: "processLog" }
],
filterList: this.currentTabConfig.filterList,
btnList: this.currentTabConfig.btnList,
columns: this.currentTabConfig.columns
};
},
methods: {
handleTabChange({ name }) {
this.activeTab = name;
}
}本地数据表格
<InflyList
:formData="{ page: 1, pagesize: 10, total: rows.length }"
:defaultInit="false"
:columns="columns"
:tableProps="{ dataList: rows, stripe: true }"
/>替换表格区域
<InflyList :formData="formData" v-bind="pageConfig">
<template #replaceTable>
<CustomDistributionTable :rows="rows" />
</template>
</InflyList>InflyForm
InflyForm 是动态表单/详情展示组件。编辑态下根据 filterList 渲染输入控件;非编辑态下渲染文本、tag、链接或自定义内容。InflyList 内部的筛选区也是使用该组件。
基础示例
<template>
<InflyForm
ref="formRef"
:formData="formData"
:filterList="filterList"
:btnList="btnList"
layout="inline"
label-width="100px"
@initData="search"
@reset-form="resetForm"
/>
</template>
<script>
export default {
data() {
return {
formData: { keyword: "", status: "" },
filterList: [
{ label: "关键词", name: "keyword", type: "infly-input", placeholder: "请输入关键词", clearable: true },
{ label: "状态", name: "status", type: "el-select", options: [{ label: "启用", value: "enabled" }], clearable: true }
],
btnList: [
{ label: "导出", type: "primary", btnEvent: () => this.exportData() }
]
};
}
};
</script>Props
| Prop | 类型 | 默认值 | 说明 | 示例 |
| --- | --- | --- | --- | --- |
| formClass | String | "" | 追加到内部 el-form 的 class。 | formClass="reconciliation-summary-form" |
| layout | String \| Array | "" | 表单布局 class,支持 inline、inline-seamless、compact,可传数组组合。 | layout="inline-seamless" |
| formData | Object | 必填 | 表单数据对象,字段通过 name 双向绑定。 | :formData="{ keyword: '' }" |
| formRef | String | "formRef" | 内部 el-form ref 名称,供 validate() 等方法使用。 | formRef="searchFormRef" |
| btnList | Array | [] | 表单上方按钮列表。 | [{ label: "上传", type: "blue", btnEvent: this.openDialog }] |
| filterList | Array | [] | 表单字段配置。 | [{ label: "名称", name: "name", type: "infly-input" }] |
| reqParams | Object | {} | 当前请求参数,导出按钮会从中取参数。通常由 InflyList 传入。 | :reqParams="{ keyword: formData.keyword }" |
| request | Function | null | 导出按钮使用的请求实例。导出请求优先级为按钮 exportFunc、request prop、组件实例 this.$axios。 | :request="$axios" |
| hideSearchBtn | Boolean | false | 隐藏底部默认“查询”按钮。 | hideSearchBtn |
| hideResetBtn | Boolean | true | 隐藏底部默认“重置”按钮。默认隐藏。 | :hideResetBtn="false" |
| isEdit | Boolean \| null | null | 强制编辑/展示态;为 null 时按路由 mode 判断。 | :isEdit="false" |
| optBtnList | Array | [] | 底部查询/重置后的附加按钮。 | :optBtnList="[{ label: '保存', type: 'primary', btnEvent: 'submit' }]" |
| btnWrapDirection | String | "row" | 顶部按钮排列方向 class。 | btnWrapDirection="column" |
| btnWrapClass | String | "" | 底部按钮容器追加 class。 | btnWrapClass="dialog-footer" |
| baseButtonsLeft | String | "420px" | 底部按钮距离 label 后的偏移基准。 | baseButtonsLeft="260px" |
| emptyStr | String | "-" | 非编辑态空值展示。 | emptyStr="暂无" |
InflyForm 还会把未声明的属性透传给 el-form,例如 label-width、label-suffix、rules、size。
<InflyForm
:formData="formData"
:filterList="filterList"
label-width="120px"
label-suffix=":"
size="small"
/>事件
| 事件 | 触发时机 | 示例 |
| --- | --- | --- |
| initData | 底部默认“查询”按钮点击。 | @initData="search" |
| reset-form | 底部默认“重置”按钮点击,参数为初始表单快照。 | @reset-form="(data) => Object.assign(formData, data)" |
| submit | 按钮 btnEvent: "submit" 且校验通过。 | @submit="submitForm" |
| secTabChange / sec-tab-change | type: "secTab" 切换。 | @secTabChange="handleSecTabChange" |
| export-request-error | 导出按钮配置了 exportUrl 但没有可用请求实例时触发。 | @export-request-error="handleExportRequestError" |
| 自定义事件 | btnEvent 为字符串时直接 emit。 | { label: "保存", btnEvent: "save" } + @save="save" |
方法
| 方法 | 说明 | 示例 |
| --- | --- | --- |
| getFormInstance() | 返回内部 el-form 实例。 | this.$refs.formRef.getFormInstance() |
| validate(callback) | 调用内部 el-form.validate。 | await this.$refs.formRef.validate() |
| clearValidate(props) | 清除校验。 | this.$refs.formRef.clearValidate(["name"]) |
| validateField(props, callback) | 校验指定字段。 | this.$refs.formRef.validateField("name") |
| resetFormData() | 触发 reset-form,并清理 InstitutionSelect。 | this.$refs.formRef.resetFormData() |
插槽
| 插槽 | 位置 | 示例 |
| --- | --- | --- |
| prepend | 表单整体前。 | <template #prepend><div>说明</div></template> |
| append | 表单整体后。 | <template #append><div>底部说明</div></template> |
| customRender | 字段 type: "customRender" 时渲染。 | <template #customRender="{ item }"><MyField :item="item" /></template> |
filterList 字段配置
字段配置会拆分函数类型属性:除 isHide、isShow 和 el-upload 回调外,函数属性会作为事件监听传给内部控件。
| 字段 | 说明 | 示例 |
| --- | --- | --- |
| label | 表单项 label。 | { label: "关键词" } |
| name | 绑定字段名;日期范围可传数组。 | { name: "keyword" }、{ name: ["start", "end"], type: "daterange" } |
| prop | 未传 name 时作为字段名。 | { prop: "keyword", type: "infly-input" } |
| type | 控件类型或展示类型。 | { type: "el-select" } |
| options | 选择类控件选项。 | { options: [{ label: "启用", value: 1 }] } |
| required | 是否显示必填标记。 | { required: true } |
| rules | 当前字段校验规则。 | { rules: [{ required: true, message: "请输入名称" }] } |
| isHide | 隐藏条件,布尔值或函数。 | { isHide: (form) => form.type !== "coupon" } |
| isShow | 显示条件,布尔值或函数。 | { isShow: (form) => form.enabled } |
| mode | 单项强制编辑态。 | { mode: "edit" } |
| formItemClass | 当前 el-form-item 追加 class。 | { formItemClass: "summary-tax-line" } |
| nowrap | 给当前项追加不换行 class。 | { nowrap: true } |
| position | 双列定位布局,支持 left、right、full。 | { label: "备注", name: "remark", type: "render", position: "full" } |
| valuePrefix | 非编辑态展示前缀。 | { valuePrefix: "¥" } |
| optionConfig | 自定义选项取值和展示。 | { optionConfig: { labelKey: "name", valueKey: "id" } } |
| radioType | el-radio-group 内部单选组件,默认 el-radio。 | { type: "el-radio-group", radioType: "el-radio-button" } |
| 其他属性 | 透传给内部控件或 el-form-item。 | { placeholder: "请输入", clearable: true } |
支持的字段类型
输入框:infly-input / InflyInput / textarea / infly-input-number / el-autocomplete
filterList: [
{ label: "关键词", name: "keyword", type: "infly-input", placeholder: "请输入关键词", clearable: true },
{ label: "备注", name: "remark", type: "textarea", rows: 3, maxlength: 50, showWordLimit: true }
]选择器:el-select
filterList: [
{
label: "账单月份",
name: "bill_month",
type: "el-select",
options: [{ label: "05", value: "05" }],
clearable: true,
placeholder: "请选择账单月份"
}
]日期:date / month / year / datetime / daterange / datetimerange / el-time-picker
filterList: [
{ label: "账单年份", name: "bill_year", type: "year", valueFormat: "yyyy", format: "yyyy", placeholder: "请选择年份" },
{ label: "账单年月", name: "bill_month", type: "month", valueFormat: "yyyy-MM", placeholder: "请选择月份" },
{ label: "账单周期", name: ["period_start", "period_end"], type: "daterange" }
]数组形式的 name 会自动把 period_start、period_end 与内部范围值同步。
机构选择:institution-select / InstitutionSelect
filterList: [
{
label: "所属省份",
name: "province_level_id",
type: "institution-select",
title: "选择省份",
btnText: "选择",
request: this.$axios,
reqModule: "admin",
levelTypes: "1",
levelNameKey: "province_level_name_filter",
hideTips: true
}
]InstitutionSelect 请求实例优先使用 request prop,其次使用组件实例 this.$axios。默认接口为 /${reqModule}/level/,也可以通过 reqUrl 显式覆盖;组件不再读取外部工具库的环境信息推导 reqModule。
复选:infly-checkbox / InflyCheckBox
filterList: [
{
label: "处理结果",
name: "process_result",
type: "infly-checkbox",
options: [
{ label: "成功", value: "success" },
{ label: "失败", value: "failed" }
]
}
]单选:el-radio-group
filterList: [
{
label: "类型",
name: "type",
type: "el-radio-group",
radioType: "el-radio-button",
options: [
{ name: "全部", value: "" },
{ name: "已启用", value: "enabled" }
]
}
]上传:el-upload
filterList: [
{
label: "活动列表",
name: "activity_file",
type: "el-upload",
action: "",
drag: true,
accept: ".xlsx",
tips: "仅支持 .xlsx 文件",
"on-change": this.handleFileChange,
"auto-upload": false,
"file-list": this.activityFileList
}
]el-upload 的回调函数保留为属性整体透传,适配 Element UI 的 on-change、on-remove 等写法。
展示态文本:text
filterList: [
{ label: "账单ID", name: "id", type: "text" }
]当 isEdit=false 或路由 mode 非编辑态时,显示 formData[name + "_str"] 优先,其次显示 formData[name]。
分组标题:module
module 用于只显示分组标题。表单内存在 module 时,普通字段会继承 label-suffix,module 自身不展示后缀和字段值。
filterList: [
{ label: "基础信息", type: "module" },
{ label: "活动名称", name: "activity_name", type: "infly-input", required: true }
]业务开关:BusinessSwitch / business-switch
filterList: [
{
label: "启用状态",
name: "enabled",
type: "business-switch",
activeValue: true,
inactiveValue: false,
render: (value) => (value ? "已启用" : "已停用")
}
]展示态链接:router-link
router-link 只在非编辑态渲染,其他属性会透传给 Vue Router 的 router-link。
filterList: [
{
label: "详情页",
name: "detail_text",
type: "router-link",
to: { path: "/reconciliation/detail", query: { id: this.formData.id } }
}
]展示态 tag:el-tag
filterList: [
{
label: "状态",
name: "status_str",
type: "el-tag",
propValueField: "status",
options: [
{ value: "completed", tagType: "success" },
{ value: "failed", tagType: "danger" }
]
}
]自定义展示:render
filterList: [
{
label: "消耗金额(含税)",
name: "total_consume_amount_with_tax",
type: "render",
render: (value) => `<span class="text-red">¥${value || "0.00"}</span>`
}
]render 可返回字符串或 VNode。字符串会通过 v-html 渲染,调用方必须确保内容可信或已转义。
自定义插槽:customRender
<InflyForm :formData="formData" :filterList="filterList">
<template #customRender="{ item }">
<CustomUploader :config="item" />
</template>
</InflyForm>filterList: [
{ label: "附件", name: "files", type: "customRender" }
]二级 tab:secTab
适合详情页“基础信息 + 下方明细 tab”的结构。secTab 项会插入到它在 filterList 中出现的位置,激活 tab 的 filterList 会跟在 tab 后面。
filterList: [
{ label: "账单ID", name: "id", type: "text", position: "left" },
{
label: "订单明细",
name: "orders",
type: "secTab",
buttonList: [
{ name: "导出订单明细", type: "primary", click: () => this.exportDetail("orders") }
],
filterList: [
{ label: "订单号查询", name: "empower_order_id", type: "infly-input", position: "full", clearable: true }
]
},
{
label: "消耗明细",
name: "consumes",
type: "secTab",
filterList: [
{ label: "关键词搜索", name: "keyword", type: "infly-input", position: "full", clearable: true }
]
}
]布局示例
行内筛选
<InflyForm
:formData="formData"
:filterList="filterList"
layout="inline"
label-width="100px"
/>无缝行内详情
<InflyForm
:formData="billInfo"
:filterList="summaryFilterList"
:isEdit="false"
layout="inline-seamless"
label-width="150px"
label-suffix=":"
/>左右定位与整行插入
position 只影响传了 left、right、full 的项。left 固定左列,right 固定右列,full 占整行并按配置顺序插入,不会被统一挪到最后。
filterList: [
{ label: "账单ID", name: "id", type: "text", position: "left" },
{ label: "充值金额", name: "total_order_amount", type: "render", position: "right", render: this.renderMoney },
{ label: "账单年份", name: "task_bill_year", type: "text", position: "left" },
{ label: "结算金额", name: "total_settlement_amount", type: "render", position: "right", render: this.renderMoney },
{
label: "备注说明",
name: "summary_note",
type: "render",
position: "full",
nowrap: true,
render: () => this.summaryNoteHtml()
},
{ label: "订单号查询", name: "empower_order_id", type: "infly-input", position: "full", clearable: true }
]按钮配置
顶部按钮:btnList
btnList: [
{ label: "上传账单", type: "blue", btnEvent: () => { this.uploadDialogVisible = true; } },
{ label: "导出", type: "primary", isShow: () => this.canExport, btnEvent: this.exportList }
]底部按钮:默认查询、重置和 optBtnList
<InflyForm
:formData="formData"
:filterList="filterList"
:hideResetBtn="false"
:optBtnList="[{ label: '保存', type: 'primary', btnEvent: 'submit' }]"
@initData="search"
@submit="submitForm"
/>导出按钮
导出请求实例按 exportFunc -> request prop -> this.$axios 的顺序解析;组件不再内置 REST fallback。独立使用 InflyForm 时,如果页面没有全局注入 $axios,需要显式传入 request 或在按钮上配置 exportFunc。
InflyForm 直接调用 @infly/ts-libs 的 exportFile,不会注册或导出 fileExportMixin。应用若需要全局 $exportFile,使用:
import { fileExportMixin } from "@infly/libs/adapters/vue2/module/file-export.js";
Vue.mixin(fileExportMixin);<InflyForm
:formData="formData"
:filterList="filterList"
:btnList="btnList"
:request="$axios"
/>btnList: [
{
label: "导出",
type: "success",
exportUrl: "/admin/reconciliation/bills/export/",
exportFileName: "金融营销对账账单",
exportMethod: "get",
dealParams: (params, formData) => ({ ...params, keyword: formData.keyword })
}
]AI 维护规则
- 新增或修改
InflyList/InflyForm的 prop、事件、插槽、列类型、字段类型、配置字段时,同步更新本 README。 - 每个新增能力至少提供一个完整示例,优先参考
apps/postal-benefits-platform/src/shared/pages/中已经存在的写法。 - 公共组件改动必须保持旧配置语义不变;新能力优先通过显式配置启用。
- 交付说明中写清影响范围、已验证路径和未覆盖风险。
