您的位置:首页 > 文旅 > 美景 > 淮南市招标投标信息网_网络服务能力_网络广告销售_整站优化是什么意思

淮南市招标投标信息网_网络服务能力_网络广告销售_整站优化是什么意思

2024/12/26 22:28:20 来源:https://blog.csdn.net/m0_60676278/article/details/144671790  浏览:    关键词:淮南市招标投标信息网_网络服务能力_网络广告销售_整站优化是什么意思
淮南市招标投标信息网_网络服务能力_网络广告销售_整站优化是什么意思
import React, { useState, useEffect, useRef, useMemo } from 'react';
import './index.less';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { getAccessToken, getCurrentOrganizationId } from 'hzero-front/lib/utils/utils';
import { getQuestionHistory, getTreeList, getRole, getTreeByOrgName, getTreeByUnitId } from "@/services/api-page";
import chatGPT from '@/assets/images/chatGPT.webp';
import user from '@/assets/images/user.webp';
import { Form, Tooltip, TreeSelect, useDataSet, Icon } from 'choerodon-ui/pro';
import { dataSet, optionDs } from "./store/index";
import { ButtonColor } from 'choerodon-ui/pro/lib/button/enum';
import { Button } from 'choerodon-ui/pro';
import { message } from 'hzero-ui';
import Search from 'choerodon-ui/lib/input/Search';
import { Input } from 'element-react';
import { Select } from 'element-react'
import 'element-theme-default';
const { TreeNode } = TreeSelect;
interface Message {errorTip: string | undefined;id: string;sender: 'user' | 'bot';text: string | undefined;files?: any[];fileName?: string; // 新增用于存储文件名的属性truncatedContent?: string; // 新增用于存储截断内容的属性finish?: boolean; // 新增用于存储是否完成的状态
}const ChatApp: React.FC = () => {const [messages, setMessages] = useState<Message[]>([]); // 渲染的消息列表const [userInput, setUserInput] = useState('');const [showButton, setShowButton] = useState(false)const showData = useDataSet(dataSet, []);const currentBotMessageRef = useRef<{truncatedContent: any;fileName: any; id: string; text: string; files?: any[];}>({id: '',text: '',files: [], // 初始化为空数组truncatedContent: '',fileName: '',// id: '',//  text: '', //  files?: any[] | undefined,}); // 当前正在更新的机器人消息const [process, setProcess] = useState([]);const controllerRef = useRef(new AbortController());const [orgId, setOrgId] = useState<string>();  //获取组织idconst [userId, setUserId] = useState('') //当亲登录的用户idconst [selectValue, setSelectValue] = useState() //组织机构树选择的值const [selectionOptions, setSelectionOptions] = useState([])  //组织机构树的数据const [isSelectVisible, setIsSelectVisible] = useState(false); //控制组织机构树是否显示// 通过sse流获取到流数据const startSseWithPost = async (userMessageId: string) => {currentBotMessageRef.current = { id: `${userMessageId}-bot`, text: '' }; // 初始化机器人消息await fetchEventSource(`http://${IP.TEST}${BASIC.CWDMX_MODEL}/${tenantId}/knowledgeBase/getQuestionAnswer`, {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer ' + getAccessToken(),},body: JSON.stringify({orgId: orgId,question: userInput,stream: true,}),signal: controllerRef.current.signal,onmessage(event) {try {if (event.data) {try {const messageData = JSON.parse(event.data)const process = messageData?.message?.features?.progress;setProcess(process);// if (messageData?.message?.type === 'text') {const content = messageData?.message?.content;// 累积回答内容currentBotMessageRef.current.text += content;if (messageData?.message?.features && messageData?.message?.features?.doc_citations) {let fileInfoString = '';// 遍历 doc_citations 数组messageData?.message?.features?.doc_citations.forEach(citation => {citation?.documents && citation?.documents.forEach((item) => {// setFileName(item.metadata.name)const fileName = item?.metadata?.nameconst truncatedContent = item?.metadata?.doc_ref?.content.length > 14 ? item.metadata?.doc_ref?.content.substring(0, 14) + '...' : item.metadata.doc_ref.content;const fileObject = {content: truncatedContent,url: item?.metadata?.doc_ref?.documentUrl};const files: any[] = currentBotMessageRef.current.files || [];files.push(fileObject)currentBotMessageRef.current.fileName = fileName;currentBotMessageRef.current.truncatedContent = truncatedContent;currentBotMessageRef?.current && (currentBotMessageRef.current.files = files)});})// 动态更新消息状态setMessages((prevMessages) =>prevMessages.map((msg) =>msg.id === currentBotMessageRef.current.id? {...msg,text: `${currentBotMessageRef.current.text}\n${fileInfoString}`,fileName: currentBotMessageRef.current.fileName,truncatedContent: currentBotMessageRef.current.truncatedContent,files: currentBotMessageRef.current.files,finish: messageData?.finish, // 设置完成状态errorTip: messageData?.error}: msg));} else {// 动态更新消息状态,如果没有文件相关信息,只更新文本内容setMessages((prevMessages) =>prevMessages.map((msg) =>msg.id === currentBotMessageRef.current.id? {...msg, text: currentBotMessageRef.current.text,finish: messageData?.finish,errorTip: messageData?.error}: msg));}// }} catch (err) {console.error('Error parsing message data:', err);}}} catch (error) {message.error('获取失败');}},onerror(err) {console.error('SSE error:', err);throw (err)},onclose() {setShowButton(false)controllerRef.current.abort();},});};// 发送消息事件,包括发送的用户输入的消息const handleSendMessage = () => {setShowButton(true)if (userInput.trim()) {const userMessageId = `${Date.now()}`; // 唯一标识符// 插入用户消息和占位的机器人消息setMessages((prevMessages) => [...prevMessages,{ id: userMessageId, sender: 'user', text: userInput },{ id: `${userMessageId}-bot`, sender: 'bot', text: '' }, // 机器人占位消息]);startSseWithPost(userMessageId); // 启动 SSEsetUserInput(''); // 清空用户输入}};//停止发送消息const handleStopFetch = () => {if (controllerRef.current) {controllerRef.current.abort();}}// 这里面可以控制node结点的判断来实现是否展示为叶结点const nodeCover = ({ record }) => {const nodeProps = {title: record.get('unitName'),};if (record.get('power') === 'false') {nodeProps.disabled = true;}return nodeProps;}// 获取选中的组织机构id,需要给问答的接口传参const handleChange = (val) => {setOrgId(val)}//获取当前登录的用户,并设置userIdconst [displayFlag, setdisplayFlag] = useState('false')  //是否展示单位useEffect(() => {console.log('logfangwende第一次');const user = async () => {const res = await getRole();if (res) {setUserId(res?.user?.id)if (userId) {const res = await getTreeList({ guestId: userId, displayFlag: 'true' });setdisplayFlag(res?.data?.displayFlag)}}}user()}, [userId])useEffect(() => {console.log('logfangwende第二次');if (displayFlag === 'true') {optionDs.setQueryParameter("guestId", userId);optionDs.query()}}, [displayFlag])// 获取组织树useEffect(() => {console.log('logfangwende第三次');const chatBox = document.querySelector('.chat-box');if (chatBox) {chatBox.scrollTop = chatBox.scrollHeight;}}, [messages]);// 获取问答页历史消息useEffect(() => {console.log('logfangwende第四次');const fetchData = async () => {try {const res = await getQuestionHistory();res.data.forEach((item) => {if (item?.direction === 1) {setMessages((prevMessages) => [...prevMessages,{ id: item?.mesTime, sender: 'user', text: item?.content, },// { id: `${item?.mesTime}-bot`, sender: 'bot', text: '' }, // 机器人占位消息]);} else if (item?.direction === 2) {const fileName = item?.ref?.[0]?.title;const files: any[] = []item?.ref?.forEach((item) => {if (item?.content) {if (item?.content.length > 14) {const fileObject = {content: item?.content.substring(0, 14) + '...',url: item?.docUrl};files.push(fileObject);}}})setMessages((prevMessages) => [...prevMessages,{ id: `${item?.mesTime}-bot`, sender: 'bot', text: item?.content, fileName: fileName, files: files, finish: true }, // 机器人占位消息]);}})} catch (error) {console.error('Error fetching data:', error);}};fetchData();}, []);// 处理选中的组织机构const selectChange = (val) => {if (!val) returnsetIsSelectVisible(false)setSelectValue(val)showData.loadData([{ unitName: val, unitCode: val }])}// 输入组织机构获取到的数据const handleEnter = async (value) => {setSelectionOptions([])if (value !== '') {const params = { guestId: userId, unitName: value }const result = await getTreeByOrgName(params)if (Array.isArray(result.data)) {const newArray = result.data.map(item => {return {value: item.unitCode,label: item.unitName}})setSelectionOptions(newArray)}}}//控制搜索摁扭展示const handleIconClick = () => {setSelectValue(undefined)setIsSelectVisible(true);setSelectionOptions([])};//控制树形组件和下拉选择组件的切换const handleVisibleChange = (isVisible) => {if (!isVisible) {setIsSelectVisible(false);}};// //自动聚焦操作(没实现// const selectRef = useRef(null);// useEffect(() => {//     if (selectRef.current) {//         selectRef.current?.focus();//     }// }, []);console.log(displayFlag, 'displayFlag');return (<div className="chat-container"><div className="+">{displayFlag === 'true' && <div className='search-box'>{isSelectVisible ? (<Select// ref={selectRef}filterable={true}remote={true}remoteMethod={(value) => { handleEnter(value) }}value={selectValue}onChange={selectChange}clearable={true}placeholder="请输入单位名称"onVisibleChange={handleVisibleChange}>{selectionOptions.map((el, index) => {return <Select.Option key={el?.value} label={el.label} value={el.value} />})}</Select>) : (<><TreeSelectplaceholder="请选择公司名称"name="unitName"dataSet={showData}onOption={nodeCover}onChange={handleChange}style={{ marginRight: '7px' }}popupCls={'down_select'}/><Icon type="search" onClick={handleIconClick} style={{ cursor: 'pointer', fontSize: '20px' }} /></>)}</div>}{messages.map((msg) => (<div key={msg.id} className={`message-wrapper ${msg.sender}`}><div className="avatar"><img src={msg.sender === 'user' ? user : chatGPT} alt="avatar" /></div><div className="message">{msg.errorTip ?? msg.text ?? '...'}{msg.sender === 'bot' && msg.fileName && msg.finish === true && <div ><br />文档来源:{msg.fileName}<br /></div>}{msg.files && msg.finish === true && msg.files?.map((item, index) => {const url = `https://${item?.url}`return <div key={index}>{item?.content} &nbsp;&nbsp;&nbsp;&nbsp; <a href={url} target="_blank">查看文档</a></div>})}</div></div>))}</div><div className='tip'><div className='process'>当前进度:{process}</div>{showButton ? <p className='stop' onClick={handleStopFetch}>停止生成</p> : ''}</div><div className="input-box"><inputtype="text"value={userInput}onChange={(e) => setUserInput(e.target.value)}onKeyDown={(e) => e.key === 'Enter' && handleSendMessage()}placeholder="请输入消息"/>{<Tooltip title="请选择单位名称"><Button color="primary" disabled={displayFlag === 'true' && !orgId} onClick={handleSendMessage}>发送</Button></Tooltip>}</div></div>);
};export default ChatApp;
.chat-container {display: flex;flex-direction: column;height: 100vh; /* 高度占满整个屏幕 */width: 100%;background-color: rgb(230, 230, 230);font-family: Arial, sans-serif;overflow: auto;:global {.el-select .el-input__inner {height: 27px;width: 183px;margin-right: 27px;font-size: 12px;border-color: #e6e6e6;border-radius: 0;}}
}.chat-box {flex: 1; /* chat-box 占用剩余空间 */overflow-y: auto; /* 允许滚动 */padding: 16px;display: flex;flex-direction: column;gap: 8px;background-color: #ffffff;
}.message-wrapper {display: flex;gap: 10px;
}.message-wrapper.user {flex-direction: row-reverse;
}.message-wrapper.bot {justify-content: flex-start;
}.message {padding: 10px 14px;border-radius: 12px;background-color: #007bff;color: #ffffff;word-break: break-word;white-space: pre-wrap;
}.message-wrapper.bot .message {background-color: #f1f1f1;color: #333333;
}.search-box {position: sticky;top: 0; /* 吸顶 */margin: 10px;margin-left: auto; /* 将下拉框移到右侧 */z-index: 9999; /* 确保层级足够高 */background-color: #007bff;padding: 5px;border-radius: 4px;display: flex;align-items: center;justify-content: flex-end; /* 确保内容靠右对齐 */
}.tip {display: flex;justify-content: space-between;.process {color: #999;font-size: 16px;margin: 10px;margin-left: 20px;}.stop {color: #0078d4;font-size: 16px;margin: 10px;cursor: pointer;margin-right: 20px;}
}.input-box {position: sticky;bottom: 0; /* 吸底 */display: flex;justify-content: space-between;padding: 20px;background-color: #fff;border-top: 1px solid #e0e0e0;
}.input-box input {flex: 1;padding: 4px;border-radius: 20px;border: 1px solid #ccc;margin-right: 14px;font-size: 14px;
}.avatar {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;margin-right: 10px;
}.avatar img {width: 100%;height: 100%;object-fit: cover;
}:global {.el-select-dropdown {top: 33px !important;}.down_select {.c7n-tree-treenode {.c7n-tree-node-content-wrapper {.c7n-tree-title {color: #007bff !important;}}}.c7n-tree-treenode-disabled {.c7n-tree-node-content-wrapper {.c7n-tree-title {color: #d9d9d9 !important;}}}}.aipage_form {.c7n-pro-field-label {width: 35px !important;color: #333333 !important;}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com