定制空会话内容与位置

空会话默认显示欢迎内容。只改文字和推荐问题,使用 settings.welcome 和 settings.recommendations;需要调整布局或换成业务内容时,使用 slots['session.empty']。下面的示例用完整的“项目助手”空态替换默认欢迎内容,可切换同一组件在顶部或居中显示。卡片里的推荐入口可以直接发送消息。左侧展示的就是右侧运行的完整组件源码。

empty-state.tsx
import '@volcengine/chatkit/styles.css';

import { Chatkit, useChatkitActions, useChatRuntime } from '@volcengine/chatkit';
import { createMockAdapter } from '@volcengine/chatkit/adapters/mock';
import { useState } from 'react';

const adapter = createMockAdapter({});

type Position = 'top' | 'center';

function BusinessEmptyState() {
  const { send } = useChatkitActions();
  const suggestions = [
    { title: '整理本周进展', prompt: '帮我整理一份本周工作周报' },
    { title: '梳理项目计划', prompt: '帮我列出一份项目启动计划' },
  ];

  return (
    <section
      style={{
        width: '100%',
        maxWidth: 500,
        padding: 24,
        border: '1px solid #e2e4ea',
        borderRadius: 20,
        background: '#fff',
        boxShadow: '0 12px 36px rgba(26, 32, 44, 0.06)',
        boxSizing: 'border-box',
      }}
    >
      <span style={{ color: '#4758a8', fontSize: 13, fontWeight: 600 }}>项目助手</span>
      <h2 style={{ margin: '12px 0 8px', fontSize: 26, lineHeight: 1.25 }}>今天从哪里开始?</h2>
      <p style={{ margin: 0, color: '#626979', lineHeight: 1.6 }}>
        可以直接在下方提问,也可以从常用任务开始。项目助手会帮你整理信息并给出下一步建议。
      </p>
      <div style={{ display: 'grid', gap: 10, marginTop: 24 }}>
        {suggestions.map(({ title, prompt }) => (
          <button
            key={title}
            type="button"
            onClick={() => void send(prompt)}
            style={{
              padding: '12px 16px',
              border: '1px solid #dfe3ef',
              borderRadius: 12,
              background: '#f8f9fd',
              color: '#242a38',
              font: 'inherit',
              textAlign: 'left',
              cursor: 'pointer',
            }}
          >
            {title}{' '}
            <span aria-hidden="true" style={{ float: 'right' }}>
              →
            </span>
          </button>
        ))}
      </div>
    </section>
  );
}

function EmptyLayout({ position }: { position: Position }) {
  return (
    <div
      style={{
        display: 'flex',
        alignItems: position === 'center' ? 'center' : 'flex-start',
        justifyContent: 'center',
        minHeight: '100%',
        padding: '24px 16px',
        boxSizing: 'border-box',
      }}
    >
      <BusinessEmptyState />
    </div>
  );
}

export default function EmptyState() {
  const runtime = useChatRuntime({ sessionId: 'empty-state', adapter });
  const [position, setPosition] = useState<Position>('center');

  if (!runtime) return null;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 16, padding: 12, borderBottom: '1px solid #e8e8ec' }}>
        <fieldset style={{ display: 'flex', gap: 8, margin: 0, padding: 0, border: 0 }}>
          <legend>空态位置</legend>
          {(['top', 'center'] as const).map(value => (
            <label key={value}>
              <input
                type="radio"
                name="empty-position"
                checked={position === value}
                onChange={() => setPosition(value)}
              />
              {value === 'top' ? '顶部' : '居中'}
            </label>
          ))}
        </fieldset>
      </div>
      <div style={{ flex: 1, minHeight: 0 }}>
        <Chatkit
          runtime={runtime}
          slots={{
            'session.empty': () => <EmptyLayout position={position} />,
          }}
        />
      </div>
    </div>
  );
}
切换业务空态位置新窗口打开

控制位置

session.empty 位于消息区内。示例的 EmptyLayout 用 minHeight: '100%' 占满消息区可用高度;居中时把业务卡片对齐到中间,切换到顶部时改为顶端对齐。内容超过消息区高度后,空态区域可从顶部向下滚动。宿主需要给 <Chatkit> 一个可解析的高度;示例使用撑满 iframe 的容器。

切换位置只改变空会话内容的位置。示例保持 settings.emptyState.composerPlacement 的默认值 bottom,因此输入框仍在消息区下方,不随空态内容移动。

替换与保留默认内容

session.empty 是单项插槽:登记后,插槽的返回值替换整个默认空态,不会自动叠加。上面的主示例只返回业务卡片,没有渲染默认欢迎内容,因此页面不会出现两组标题或推荐入口。

如果仅需要调整默认欢迎内容的位置,插槽参数里的 defaultNode 是 Chatkit 原本的欢迎内容,包括已配置的欢迎语和推荐问题;可以单独返回它并用布局容器包裹。此时不要再添加另一组标题或推荐入口,以免视觉重复。

需要明确隐藏空态时返回 () => null;直接把插槽值写成 null 或 false 会被视为未配置。其他插槽规则见插槽。

把输入框放进空态

若业务布局需要让原生输入框跟随空态内容,设置 settings.emptyState.composerPlacement: 'embedded',并在 session.empty 插槽返回的 JSX 中渲染参数 composer。这时空会话的默认底部输入框会隐藏;如果漏掉 {composer},空会话将没有输入框。出现消息后,输入框回到底部。默认值 bottom 下参数 composer 为 null,输入框一直留在消息区下方。

默认加载历史时显示内置骨架屏。设置 settings.emptyState.renderWhenLoading: true 后,加载期间改为展示该插槽返回的节点;可用参数 loading 区分加载状态。