ServiceMessage
service-message服务通知卡片 · 复刻微信「服务通知」会话内消息卡(模板/订阅消息) · 头部(头像+来源+⋯)/正文(标题+键值字段或自定义 children)/底部(引导文字+小程序入口) · 数据驱动 fields + onMore/onAction 交互 + footer/action 可定制 · 区别 Notification(命令式四角 toast) · 复用 Avatar/_icons·全吃 token 明暗自适配
用法
基础用法
头像 + 来源 + 键值字段 + 底部入口,复刻微信服务通知卡片。
瑞luckincoffee 瑞幸咖啡
商品领取提醒
取餐号361
商品数量1
商品详情橙C冰茶
tsx
<ServiceMessage
avatar={{ fallback: "瑞", className: "bg-primary/10 text-primary" }}
source="luckincoffee 瑞幸咖啡"
onMore={() => openMore()}
title="商品领取提醒"
fields={[
{ label: "取餐号", value: "361" },
{ label: "商品数量", value: "1" },
{ label: "商品详情", value: "橙C冰茶" },
]}
action={{ icon: <MiniProgramIcon /> }}
onAction={() => openMiniProgram()}
/>自定义正文
传 children 覆盖 fields,承载非键值结构的内容。
顺顺丰速运
您的包裹已签收
您的快件已由 本人 签收,感谢使用顺丰速运。期待再次为您服务。
运单号 SF1234567890123 · 今天 14:32
tsx
<ServiceMessage
avatar={{ fallback: "顺", className: "bg-warning/15 text-warning" }}
source="顺丰速运"
title="您的包裹已签收"
footer="查看物流详情"
action={{ label: "详情", icon: <MiniProgramIcon /> }}
onAction={() => openTracking()}
>
<p className="text-sm leading-relaxed text-foreground">
您的快件已由 <span className="font-medium">本人</span> 签收,感谢使用顺丰速运。
</p>
</ServiceMessage>无更多按钮
不传 onMore 即隐藏头部 ⋯ 按钮;action.label 可自定义动作文字。
OA企业 OA · 审批助手
报销单已通过
单据编号BX-2026-000812
报销金额¥ 1,280.00
审批结果已通过
tsx
<ServiceMessage
avatar={{ fallback: "OA", className: "bg-success/15 text-success" }}
source="企业 OA · 审批助手"
title="报销单已通过"
fields={[
{ label: "单据编号", value: "BX-2026-000812" },
{ label: "报销金额", value: "¥ 1,280.00" },
{ label: "审批结果", value: "已通过" },
]}
footer="进入审批中心"
action={{ label: "查看", icon: <MiniProgramIcon /> }}
onAction={() => openApproval()}
/>极简
仅标题 + 底部入口(无头像 / 字段)。
系统通知
您有 1 条新的系统消息待查看
tsx
<ServiceMessage
source="系统通知"
title="您有 1 条新的系统消息待查看"
footer="查看详情"
onAction={() => openDetail()}
/>何时用
在「消息流 / 会话内」展示服务方下发的模板/订阅消息卡片时用(取餐提醒、物流签收、审批结果等):头部来源、正文键值字段、底部小程序入口三段式。它是声明式静态卡片,渲染在内容流里;要弹出短暂反馈用 Notification(命令式四角 toast)或 Toast。
导入
ts
import { ServiceMessage } from "@hulianui/ui"Props
继承 Omit<HTMLAttributes<HTMLDivElement>, "title">。
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| avatar | AvatarProps | — | 头部头像(复用瑚琏 Avatar 的 props,如 {src, fallback}) |
| fields | ServiceMessageField[] | — | 正文键值对字段({label, value} 左标右值);children 提供时被覆盖 |
| action | ServiceMessageAction | label "小程序" | 底部右侧动作({label?, icon?} + chevron) |
Events
| 事件 | 类型 | 说明 |
|---|---|---|
| onMore | () => void | 头部右侧「更多」回调;提供则渲染 ⋯ 按钮 |
| onAction | () => void | 底部行点击回调;提供则整行成为可点击 button |
Slots
| 插槽 | 类型 | 说明 |
|---|---|---|
| source | ReactNode | 头部来源名称,如「luckincoffee 瑞幸咖啡」 |
| title | ReactNode | 正文主标题,如「商品领取提醒」 |
| children | ReactNode | 自定义正文(覆盖 fields),用于非键值结构内容 |
| footer | ReactNode | 底部左侧引导文字(默认「进入小程序查看」);传 null 隐藏整个底部 |
禁忌 / 坑
children与fields互斥:传了children则fields被忽略,二选一。- 不传
onMore就不渲染 ⋯ 按钮;不传onAction则底部行不可点击——交互按需挂回调,别给空函数误以为生效。 footer={null}会隐藏整个底部(含右侧 action),不只是引导文字。- 暂无其它已知坑。
相关
Playground
瑞luckincoffee 瑞幸咖啡
商品领取提醒
取餐号361
商品数量1
商品详情橙C冰茶
<ServiceMessage
avatar={{ src: logo, fallback: "瑞" }}
source="luckincoffee 瑞幸咖啡"
onMore={() => openMore()}
title="商品领取提醒"
fields={[
{ label: "取餐号", value: "361" },
{ label: "商品数量", value: "1" },
{ label: "商品详情", value: "橙C冰茶" },
]}
footer="进入小程序查看"
action={{ icon: <MiniProgramIcon />, label: "小程序" }}
onAction={() => openMiniProgram()}
/>