iter(g147): 补三条组合配方
This commit is contained in:
@@ -1532,6 +1532,14 @@
|
|||||||
"acceptance": "progress 新增 type=line|circle,环形走 createElementNS 的 SVG 双圆 + dashoffset,中间显示百分比、aria-label 拼名称与数值,variant 换弧色;linear 行为不变;文档与演示同步;npm run check 全绿",
|
"acceptance": "progress 新增 type=line|circle,环形走 createElementNS 的 SVG 双圆 + dashoffset,中间显示百分比、aria-label 拼名称与数值,variant 换弧色;linear 行为不变;文档与演示同步;npm run check 全绿",
|
||||||
"notes": "自补:既有组件可用性细节(坑:h() 用 createElement 造不出可渲染 SVG,必须 createElementNS)",
|
"notes": "自补:既有组件可用性细节(坑:h() 用 createElement 造不出可渲染 SVG,必须 createElementNS)",
|
||||||
"status": "done"
|
"status": "done"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "g147",
|
||||||
|
"title": "补三条组合配方(筛选栏/评论/详情页)",
|
||||||
|
"motivation": "本轮新增的 treeSelect、datePicker range、mentions、avatarGroup、typography、grid 只有参数表,Agent 拿到组件却不知道该怎么拼;recipes.md 还停在 6 条",
|
||||||
|
"acceptance": "recipes.md 补配方 7-9(筛选栏、评论输入、详情页排版),只消费对外 API,随 npm run docs 进入 llms-full.txt;npm run check 全绿",
|
||||||
|
"notes": "自补:Agent 文档完善",
|
||||||
|
"status": "open"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2229,6 +2229,64 @@ affix({ position: 'bottom', offset: 0 }, h('div', { class: 'row' },
|
|||||||
- 提交期间用同一个 `saving` 信号锁三处:按钮 `disabled`、开关 `loading`(转圈 + aria-busy)、业务请求出口,防重复提交与中途改状态。
|
- 提交期间用同一个 `saving` 信号锁三处:按钮 `disabled`、开关 `loading`(转圈 + aria-busy)、业务请求出口,防重复提交与中途改状态。
|
||||||
- 长度约束一处写够:`textField` 的 `maxCount` 设原生上限并实时计数,`formItem` 的 `rules: [{ max }]` 只做提交兜底,两处数字保持一致。
|
- 长度约束一处写够:`textField` 的 `maxCount` 设原生上限并实时计数,`formItem` 的 `rules: [{ max }]` 只做提交兜底,两处数字保持一致。
|
||||||
|
|
||||||
|
## 配方 7:筛选栏(层级归属 + 日期区间)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const dept = signal('');
|
||||||
|
const from = signal('');
|
||||||
|
const to = signal('');
|
||||||
|
space({ size: 'sm', wrap: true },
|
||||||
|
treeSelect({ nodes: orgTree, value: dept, searchable: true, placeholder: '归属部门' }),
|
||||||
|
datePicker({ range: true, value: from, end: to, onRangeChange: (a, b) => reload(a, b) }),
|
||||||
|
button({ label: '重置', variant: 'ghost', onClick: () => { dept(''); from(''); to(''); } }),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 层级用 `treeSelect`(允许选中间节点、可搜索),只有「必须逐级选到叶子」时才用 `cascader`。
|
||||||
|
- 日期区间传 `range: true`:组件内部保证先后顺序(用户点早了会自动交换),`onRangeChange` 拿到的就是排好序的两端。
|
||||||
|
- 重置把三个信号清空即可:组件都是受控的,值一变界面自己回到占位态。
|
||||||
|
|
||||||
|
## 配方 8:评论输入(@ 提及 + 参与人头像组)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const text = signal('');
|
||||||
|
const members = [{ name: 'zhangsan', label: '张三', description: '前端', keywords: ['zs'] }];
|
||||||
|
card({ title: '评审讨论', extra: avatarGroup({ items: members, max: 4 }) },
|
||||||
|
mentions({ items: members, value: text, placeholder: '输入 @ 叫人评审…', onSelect: (m) => toast.info(`已提及 ${m.label}`) }),
|
||||||
|
space({ size: 'sm', justify: 'end', block: true },
|
||||||
|
button({ label: '发送', onClick: () => { toast.success('已发送'); text(''); } })),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 参与人头像用 `avatarGroup`:超出 `max` 自动折叠成 `+N`,整组 `title` 列出全部姓名,比并排 `avatar` 省一半横向空间。
|
||||||
|
- `mentions` 的 `value` 是受控信号:发送后 `text('')` 即清空,不要在组件外部再改 textarea。
|
||||||
|
- 候选人来源由调用方决定(`items` 可随 `onInput` 远程拉取后重建),组件不做远程搜索。
|
||||||
|
|
||||||
|
## 配方 9:详情页排版(栅格 + 排版文本 + 描述列表)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
grid({ columns: 2, gutter: 'lg' },
|
||||||
|
card({ title: '基本信息' },
|
||||||
|
typography({ variant: 'title', level: 4, content: '订单 RB-2048' }),
|
||||||
|
descriptions({ column: 2, items: [
|
||||||
|
{ label: '金额', value: '¥1,280.00' },
|
||||||
|
{ label: '状态', value: tag({ label: '待发货', variant: 'warning' }) },
|
||||||
|
] }),
|
||||||
|
),
|
||||||
|
card({ title: '备注' },
|
||||||
|
typography({ variant: 'paragraph', ellipsis: 3, content: longNote }),
|
||||||
|
typography({ content: 'RB-2048-0917', code: true, copyable: true }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 页面骨架用 `grid`(`columns` 固定列 / `min` 走 auto-fit),窄屏自动单列,不要在调用方写媒体查询。
|
||||||
|
- 标题一律 `typography({ variant: 'title', level })` 出语义 `h1-h5`;正文长文本用 `ellipsis` 截断并自动挂 `title` 看全文。
|
||||||
|
- 只读字段用 `descriptions`(不要用 `form`):`form` 承载输入与校验,`descriptions` 只负责 label:value 对齐。
|
||||||
|
|
||||||
## 通用约定
|
## 通用约定
|
||||||
|
|
||||||
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。
|
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。
|
||||||
|
|||||||
@@ -126,6 +126,64 @@ affix({ position: 'bottom', offset: 0 }, h('div', { class: 'row' },
|
|||||||
- 提交期间用同一个 `saving` 信号锁三处:按钮 `disabled`、开关 `loading`(转圈 + aria-busy)、业务请求出口,防重复提交与中途改状态。
|
- 提交期间用同一个 `saving` 信号锁三处:按钮 `disabled`、开关 `loading`(转圈 + aria-busy)、业务请求出口,防重复提交与中途改状态。
|
||||||
- 长度约束一处写够:`textField` 的 `maxCount` 设原生上限并实时计数,`formItem` 的 `rules: [{ max }]` 只做提交兜底,两处数字保持一致。
|
- 长度约束一处写够:`textField` 的 `maxCount` 设原生上限并实时计数,`formItem` 的 `rules: [{ max }]` 只做提交兜底,两处数字保持一致。
|
||||||
|
|
||||||
|
## 配方 7:筛选栏(层级归属 + 日期区间)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const dept = signal('');
|
||||||
|
const from = signal('');
|
||||||
|
const to = signal('');
|
||||||
|
space({ size: 'sm', wrap: true },
|
||||||
|
treeSelect({ nodes: orgTree, value: dept, searchable: true, placeholder: '归属部门' }),
|
||||||
|
datePicker({ range: true, value: from, end: to, onRangeChange: (a, b) => reload(a, b) }),
|
||||||
|
button({ label: '重置', variant: 'ghost', onClick: () => { dept(''); from(''); to(''); } }),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 层级用 `treeSelect`(允许选中间节点、可搜索),只有「必须逐级选到叶子」时才用 `cascader`。
|
||||||
|
- 日期区间传 `range: true`:组件内部保证先后顺序(用户点早了会自动交换),`onRangeChange` 拿到的就是排好序的两端。
|
||||||
|
- 重置把三个信号清空即可:组件都是受控的,值一变界面自己回到占位态。
|
||||||
|
|
||||||
|
## 配方 8:评论输入(@ 提及 + 参与人头像组)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const text = signal('');
|
||||||
|
const members = [{ name: 'zhangsan', label: '张三', description: '前端', keywords: ['zs'] }];
|
||||||
|
card({ title: '评审讨论', extra: avatarGroup({ items: members, max: 4 }) },
|
||||||
|
mentions({ items: members, value: text, placeholder: '输入 @ 叫人评审…', onSelect: (m) => toast.info(`已提及 ${m.label}`) }),
|
||||||
|
space({ size: 'sm', justify: 'end', block: true },
|
||||||
|
button({ label: '发送', onClick: () => { toast.success('已发送'); text(''); } })),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 参与人头像用 `avatarGroup`:超出 `max` 自动折叠成 `+N`,整组 `title` 列出全部姓名,比并排 `avatar` 省一半横向空间。
|
||||||
|
- `mentions` 的 `value` 是受控信号:发送后 `text('')` 即清空,不要在组件外部再改 textarea。
|
||||||
|
- 候选人来源由调用方决定(`items` 可随 `onInput` 远程拉取后重建),组件不做远程搜索。
|
||||||
|
|
||||||
|
## 配方 9:详情页排版(栅格 + 排版文本 + 描述列表)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
grid({ columns: 2, gutter: 'lg' },
|
||||||
|
card({ title: '基本信息' },
|
||||||
|
typography({ variant: 'title', level: 4, content: '订单 RB-2048' }),
|
||||||
|
descriptions({ column: 2, items: [
|
||||||
|
{ label: '金额', value: '¥1,280.00' },
|
||||||
|
{ label: '状态', value: tag({ label: '待发货', variant: 'warning' }) },
|
||||||
|
] }),
|
||||||
|
),
|
||||||
|
card({ title: '备注' },
|
||||||
|
typography({ variant: 'paragraph', ellipsis: 3, content: longNote }),
|
||||||
|
typography({ content: 'RB-2048-0917', code: true, copyable: true }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 页面骨架用 `grid`(`columns` 固定列 / `min` 走 auto-fit),窄屏自动单列,不要在调用方写媒体查询。
|
||||||
|
- 标题一律 `typography({ variant: 'title', level })` 出语义 `h1-h5`;正文长文本用 `ellipsis` 截断并自动挂 `title` 看全文。
|
||||||
|
- 只读字段用 `descriptions`(不要用 `form`):`form` 承载输入与校验,`descriptions` 只负责 label:value 对齐。
|
||||||
|
|
||||||
## 通用约定
|
## 通用约定
|
||||||
|
|
||||||
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。
|
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。
|
||||||
|
|||||||
Reference in New Issue
Block a user