chatbot-antd
Version:
chatbot-antd ; 基于Antd制作的客服机器人
177 lines (176 loc) • 7.38 kB
JavaScript
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];
}