export interface TailchatWidgetOptions { /** * @default https://nightly.paw.msgbyte.com/ */ host?: string; groupId: string; channelId: string; widgetStyle?: Partial; iconStyle?: Partial; frameStyle?: Partial; } const defaultTailchatWidgetOptions: Partial = { host: 'https://nightly.paw.msgbyte.com/', }; const defaultWidgetStyle: Partial = { position: 'absolute', right: '20px', bottom: '20px', }; const iconContainerSize = 48; const defaultIconContainerStyle: Partial = { width: `${iconContainerSize}px`, height: `${iconContainerSize}px`, boxShadow: '0 1px 4px rgba(0, 0, 0, 0.2)', borderRadius: '50%', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', }; const defaultFrameStyle: Partial = { width: '414px', height: '736px', border: '0', borderRadius: '3px', boxShadow: '0 1px 4px rgba(0, 0, 0, 0.2)', }; const iconSize = 32; const iconSvg = ``; const closeIconSvg = ``; /** * 创建聊天小部件 */ export function createTailchatWidget(_options: TailchatWidgetOptions) { const options = { ...defaultTailchatWidgetOptions, ..._options }; const url = `${options.host}${options.groupId}/${options.channelId}`; // 容器 const container = document.createElement('div'); applyStyle(container, { ...defaultWidgetStyle, ..._options.widgetStyle, }); // 图标 const iconContainer = document.createElement('div'); applyStyle(iconContainer, { ...defaultIconContainerStyle, ..._options.iconStyle, }); iconContainer.innerHTML = iconSvg; container.appendChild(iconContainer); // Iframe 容器 let frameContainer: HTMLDivElement | null = null; iconContainer.addEventListener('click', () => { // 展开iframe if (!frameContainer) { // 元素不存在 // 容器 const _frameContainer = document.createElement('div'); frameContainer = _frameContainer; // Iframe const frameEl = document.createElement('iframe'); frameEl.src = url; applyStyle(frameEl, { ...defaultFrameStyle, ..._options.frameStyle, }); // closeBtn const closeBtnEl = document.createElement('div'); closeBtnEl.innerHTML = closeIconSvg; applyStyle(closeBtnEl, { position: 'absolute', right: '0', top: `-${iconSize}px`, backgroundColor: 'white', cursor: 'pointer', boxShadow: '0px -1px 4px rgba(0, 0, 0, 0.2)', borderRadius: '50% 50% 0 0', }); closeBtnEl.addEventListener('click', () => { // 关闭操作 iconContainer.style.display = 'flex'; if (frameContainer) { frameContainer.style.display = 'none'; } }); _frameContainer.appendChild(frameEl); _frameContainer.appendChild(closeBtnEl); container.appendChild(_frameContainer); } else { // 已创建 frameContainer.style.display = 'block'; } iconContainer.style.display = 'none'; }); document.body.appendChild(container); } /** * 应用样式到元素 * @param el 元素 * @param styles 样式 */ function applyStyle(el: HTMLElement, styles: Partial) { for (const key in styles) { const val = styles[key]; if (typeof val === 'string') { el.style[key] = val; } } }