UNPKG

chatbot-antd

Version:

chatbot-antd ; 基于Antd制作的客服机器人

177 lines (176 loc) 7.38 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { Button, Input } from "antd"; import Modal from "antd/lib/modal/Modal"; import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react"; import { EnterOutlined, DeleteOutlined, PictureOutlined, } from "@ant-design/icons"; import { RobotItem } from "./listItem"; import "./index.css"; export * from "./dataValidate"; export * from "./listItem"; //客服窗口的高度 export let modalHeight = 400; //antd的输入框接口 export const defaultInputOption = {}; //antd的modal接口 export const defaultModalOption = { mask: false, style: { marginRight: 0, zIndex: 10000 }, width: 300, bodyStyle: { height: `${modalHeight}px`, overflow: "auto", }, wrapClassName: "yehuozhili", }; //初始语句延迟 export let initWelcomeDelay = 500; //功能条包裹div的样式 export const functionDivStyle = { display: "flex", paddingBottom: "10px", marginBottom: "10px", }; //功能条按钮样式 export const functionButtonStyle = { padding: 0, marginRight: "10px", }; //图片显示到聊天框的样式 export const imgStyle = { width: "100%", }; //允许图片验证通过的列表 export const imgAccept = ["image/png", "image/jpeg", "image/gif"]; //允许图片验证通过的大小 export const imgMaxSize = 500000; //验证图片的函数,不满意自行修改 export let imgValidate = (f) => { if (f.size <= imgMaxSize && imgAccept.includes(f.type)) { return true; } else { console.error("invalidate file"); return false; } }; function getBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = (error) => reject(error); }); } export function useRegister( //modal状态 state, //获取用户回话的回调 callback, modalOption, inputOption, initWelcome, initState, closeFunctionBar) { //存放渲染语句 const [list, setList] = useState(initState ? initState : []); //存放输入框内容 const [inputValue, setInputValue] = useState(""); const finalInputOption = useMemo(() => { return Object.assign(Object.assign({}, defaultInputOption), inputOption); }, [inputOption]); const submit = useCallback(() => { if (inputValue !== "") { setList((prev) => { return [...prev, { isUser: true, text: inputValue }]; }); setInputValue(""); } }, [inputValue]); const sendImg = useCallback(() => { if (uploadRef.current) { uploadRef.current.click(); } }, []); const uploadChange = (e) => __awaiter(this, void 0, void 0, function* () { if (e.target && e.target.files && e.target.files.length > 0) { const file = e.target.files[0]; if (imgValidate(file)) { //验证后获取blob let res = yield getBase64(file); const img = (React.createElement("img", { style: imgStyle, src: res, alt: "user-img" })); setList((prev) => [...prev, { isUser: true, text: img }]); } } }); const uploadRef = useRef(null); //这个是功能条渲染部分 const FunctionBar = useMemo(() => { if (closeFunctionBar) { return null; } else { return (React.createElement("div", { style: functionDivStyle }, React.createElement(Button, { title: "\u6E05\u7A7A", type: "link", onClick: () => setList([]), style: functionButtonStyle }, React.createElement(DeleteOutlined, null)), React.createElement("input", { ref: uploadRef, type: "file", accept: "image/*", style: { display: "none" }, value: "", onChange: uploadChange }), React.createElement(Button, { title: "\u53D1\u9001\u56FE\u7247", type: "link", onClick: () => sendImg(), style: functionButtonStyle }, React.createElement(PictureOutlined, null)))); } }, [closeFunctionBar, sendImg]); const finalModalOption = useMemo(() => { const footer = (React.createElement("div", null, FunctionBar, React.createElement("div", { style: { display: "flex" } }, React.createElement(Input, Object.assign({ value: inputValue, onChange: (e) => setInputValue(e.target.value), onPressEnter: submit }, finalInputOption)), React.createElement(Button, { style: { marginLeft: "5px" }, onClick: submit }, React.createElement(EnterOutlined, null))))); return Object.assign(Object.assign(Object.assign({}, defaultModalOption), { footer }), modalOption); }, [FunctionBar, finalInputOption, inputValue, modalOption, submit]); //这个为了使得滚动条始终保持最底 useLayoutEffect(() => { const dom = document.querySelector(".yehuozhili"); if (dom) { let body = dom.querySelector(".ant-modal-body"); if (body) { let height = body.scrollHeight; let bodyheight = modalHeight; let scrolltop = height - bodyheight; body.scrollTop = scrolltop; } } }, [list]); //用来制作回调,过滤机器人发送 useEffect(() => { if (list.length > 0 && callback) { let last = list[list.length - 1]; if (last.isUser) { callback(last); } } }, [callback, list]); //不能直接设到state初始值上,否则看起来怪异。 //需要第一次用户打开时把语句设上 const flag = useMemo(() => { return { sign: true }; }, []); useEffect(() => { let timer; if (flag.sign && state && initWelcome) { timer = window.setTimeout(() => { flag.sign = false; setList((prev) => [ ...prev, { isUser: false, text: initWelcome }, ]); }, initWelcomeDelay); } return () => window.clearTimeout(timer); }, [flag, initWelcome, state]); let modalRender = (React.createElement(Modal, Object.assign({ visible: state }, finalModalOption), list.map((it, index) => { return (React.createElement(RobotItem, { key: index, isUser: it.isUser, text: it.text })); }))); return [modalRender, setList]; }