fix: 多次点击加入房间
parent
1270723821
commit
27edb84470
|
|
@ -3,7 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>六维填报师</title>
|
<title>六纬AI填报师</title>
|
||||||
<meta name="description" content="AIGC对话" />
|
<meta name="description" content="AIGC对话" />
|
||||||
<meta name="generator" content="React" />
|
<meta name="generator" content="React" />
|
||||||
<meta name="keywords" content="music, music-site" />
|
<meta name="keywords" content="music, music-site" />
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
|
|
@ -8,22 +8,22 @@ import { useSearchParams } from "react-router-dom";
|
||||||
import { fetchUserToken } from "@/apis/user";
|
import { fetchUserToken } from "@/apis/user";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import { useAbortController } from "@/hooks/useAbortController";
|
import { useAbortController } from "@/hooks/useAbortController";
|
||||||
// import { ReportContext } from "@/components/Provider/ReportResolveProvider";
|
|
||||||
import AntechamberFile from "@/components/AntechamberFile";
|
import AntechamberFile from "@/components/AntechamberFile";
|
||||||
import AntechamberReport from "@/components/AntechamberReport";
|
import AntechamberReport from "@/components/AntechamberReport";
|
||||||
import AntechamberWishList from "@/components/AntechamberWishList";
|
import AntechamberWishList from "@/components/AntechamberWishList";
|
||||||
|
import { ReportContext } from "@/components/Provider/ReportResolveProvider";
|
||||||
|
|
||||||
export default function Antechamber() {
|
export default function Antechamber() {
|
||||||
|
|
||||||
const { handleConnect } = useContext(RealtimeClientContext);
|
const { handleConnect} = useContext(RealtimeClientContext);
|
||||||
|
const { hasHandledReport } = useContext(ReportContext);
|
||||||
|
|
||||||
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const [disable,setDisable] = useState(true);
|
const [disable,setDisable] = useState(true);
|
||||||
|
const [isLoading,setIsLoading] = useState(false);
|
||||||
|
|
||||||
const token = searchParams.get("token") || '';
|
const token = searchParams.get("token") || '';
|
||||||
// const reportId = searchParams.get("reportId") || '';
|
|
||||||
// const reportType = searchParams.get("reportType") || '';
|
|
||||||
|
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { getSignal } = useAbortController();
|
const { getSignal } = useAbortController();
|
||||||
|
|
@ -57,54 +57,35 @@ export default function Antechamber() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// const getReport = async () => {
|
|
||||||
// try {
|
|
||||||
// const { result, message } = await fetchReport({
|
|
||||||
// params:{Type:reportType,Id:reportId},
|
|
||||||
// options: {
|
|
||||||
// signal: getSignal(),
|
|
||||||
// headers: {
|
|
||||||
// "Authorization": `Bearer ${encodeURIComponent(token)}`
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// if (message) {
|
|
||||||
// console.log(message);
|
|
||||||
// } else {
|
|
||||||
// handleConnect({initMessage:result as string});
|
|
||||||
// setHasHandledReport(true)
|
|
||||||
// }
|
|
||||||
// } catch (error: any) {
|
|
||||||
// if (error.name !== 'AbortError') {
|
|
||||||
// console.error('获取报告失败:', error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getUserToken();
|
getUserToken();
|
||||||
}, [token]);
|
}, [token]);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if(reportId && reportType && !hasHandledReport){
|
|
||||||
// getReport();
|
|
||||||
// }
|
|
||||||
// }, [reportId, reportType,hasHandledReport]);
|
|
||||||
|
|
||||||
const toRoom = (params:{initMessage?:string,fileUrl?:string}) => {
|
const toRoom = (params:{initMessage?:string,fileUrl?:string}) => {
|
||||||
if(disable){
|
if(!hasHandledReport && (disable || isLoading)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleConnect(params);
|
setIsLoading(true)
|
||||||
|
handleConnect(params).then(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center h-full">
|
<div className="flex flex-col items-center h-full overflow-y-auto relative">
|
||||||
<AntechamberHeader />
|
<AntechamberHeader />
|
||||||
<AntechamberScore />
|
<AntechamberScore />
|
||||||
<AntechamberWishList />
|
<AntechamberWishList />
|
||||||
<AntechamberFile />
|
<AntechamberFile handleLoading={setIsLoading} />
|
||||||
<AntechamberReport />
|
<AntechamberReport handleLoading={setIsLoading} />
|
||||||
<InvokeButton disable={disable} onClick={() => toRoom({})} />
|
<InvokeButton disable={disable} onClick={() => toRoom({})} />
|
||||||
|
{
|
||||||
|
isLoading ? <div className="w-[108px] h-[108px] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] bg-black/60 rounded-[20px] flex flex-col items-center justify-center">
|
||||||
|
<img src="/icons/loading.gif" alt="loading" className="w-[68px] h-[68px]" />
|
||||||
|
<span className="text-[14px] text-[#fff]">加载中</span>
|
||||||
|
</div> : <></>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ import {
|
||||||
} from "@/components/Provider/RealtimeClientProvider";
|
} from "@/components/Provider/RealtimeClientProvider";
|
||||||
import { ReportProvider } from "@/components/Provider/ReportResolveProvider";
|
import { ReportProvider } from "@/components/Provider/ReportResolveProvider";
|
||||||
import { RealtimeUtils } from "@coze/realtime-api";
|
import { RealtimeUtils } from "@coze/realtime-api";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
|
||||||
function MainContent() {
|
function MainContent() {
|
||||||
const { isConnected } = useContext(RealtimeClientContext);
|
const { isConnected, handleDisconnect } = useContext(RealtimeClientContext);
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
const handlePromise = async() => {
|
const handlePromise = async() => {
|
||||||
await RealtimeUtils.checkDevicePermission(false);
|
await RealtimeUtils.checkDevicePermission(false);
|
||||||
|
|
@ -21,11 +21,16 @@ function MainContent() {
|
||||||
handlePromise();
|
handlePromise();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected) {
|
||||||
|
handleDisconnect();
|
||||||
|
}
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReportProvider>
|
<ReportProvider>
|
||||||
{isConnected ? <Room /> : <Antechamber />}
|
{isConnected ? <Room /> : <Antechamber />}
|
||||||
</ReportProvider>
|
</ReportProvider>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
.wrapper {
|
.wrapper {
|
||||||
width: 88px;
|
width: 88px;
|
||||||
height: 88px;
|
height: 88px;
|
||||||
|
min-height: 88px;
|
||||||
|
min-width: 88px;
|
||||||
background: linear-gradient(180deg, #64c7ff 0%, #0165ff 100%);
|
background: linear-gradient(180deg, #64c7ff 0%, #0165ff 100%);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -8,8 +10,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: auto;
|
|
||||||
margin-bottom: 80px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,11 @@ export default function InvokeButton(props: IInvokeButtonProps) {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${style.wrapper} ${className}`} {...rest}>
|
<div className={`${className} mt-auto mb-[80px]`} {...rest}>
|
||||||
|
<div className={`mt-[20px] ${style.wrapper}`}>
|
||||||
<img className={style.call} src={CallPng} alt="call" />
|
<img className={style.call} src={CallPng} alt="call" />
|
||||||
<div className={style.text}>{disable ? '暂不可用':isConnecting?'连接中':'发起通话'}</div>
|
<div className={style.text}>{disable ? '暂不可用':isConnecting?'连接中':'发起通话'}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -6,9 +6,11 @@ import { useSearchParams } from "react-router-dom";
|
||||||
import { ReportContext } from "../Provider/ReportResolveProvider";
|
import { ReportContext } from "../Provider/ReportResolveProvider";
|
||||||
import { FileInfo, RealtimeClientContext } from "../Provider/RealtimeClientProvider";
|
import { FileInfo, RealtimeClientContext } from "../Provider/RealtimeClientProvider";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
handleLoading:(val:boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AntechamberFile({handleLoading}:Props) {
|
||||||
export default function AntechamberFile() {
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const fileId = searchParams.get("fileId") || "";
|
const fileId = searchParams.get("fileId") || "";
|
||||||
const locationCode = searchParams.get("locationCode") || "";
|
const locationCode = searchParams.get("locationCode") || "";
|
||||||
|
|
@ -32,7 +34,7 @@ export default function AntechamberFile() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let resp = result.result as FileInfo;
|
let resp = result.result as FileInfo;
|
||||||
|
handleLoading(true)
|
||||||
handleConnect({
|
handleConnect({
|
||||||
fileInfo: {type: resp.type,url: resp.url,tableName: resp.tableName,provinceName: resp.provinceName,subjectClaim: resp.subjectClaim},
|
fileInfo: {type: resp.type,url: resp.url,tableName: resp.tableName,provinceName: resp.provinceName,subjectClaim: resp.subjectClaim},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
backdrop-filter:blur(10px);
|
backdrop-filter:blur(10px);
|
||||||
min-height: 213px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ export default function HeaderGroup() {
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => handleQuestion(item)}
|
onClick={() => handleQuestion(item)}
|
||||||
>
|
>
|
||||||
<div>{item}</div>
|
<div className="text-[14px] text-[#000]">{item}</div>
|
||||||
<img
|
<img
|
||||||
src={RightIcon}
|
src={RightIcon}
|
||||||
alt="right-icon"
|
alt="right-icon"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@ import { useSearchParams } from "react-router-dom";
|
||||||
import { useAbortController } from "@/hooks/useAbortController";
|
import { useAbortController } from "@/hooks/useAbortController";
|
||||||
import { RealtimeClientContext } from "../Provider/RealtimeClientProvider";
|
import { RealtimeClientContext } from "../Provider/RealtimeClientProvider";
|
||||||
|
|
||||||
export default function AntechamberReport() {
|
type Props = {
|
||||||
|
handleLoading:(val:boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AntechamberReport({handleLoading}:Props) {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const token = searchParams.get("token") || '';
|
const token = searchParams.get("token") || '';
|
||||||
const reportId = searchParams.get("reportId") || '';
|
const reportId = searchParams.get("reportId") || '';
|
||||||
|
|
@ -30,6 +34,7 @@ export default function AntechamberReport() {
|
||||||
if (message) {
|
if (message) {
|
||||||
console.log(message);
|
console.log(message);
|
||||||
} else {
|
} else {
|
||||||
|
handleLoading(true)
|
||||||
handleConnect({initMessage:result as string});
|
handleConnect({initMessage:result as string});
|
||||||
setHasHandledReport(true)
|
setHasHandledReport(true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.innerWrapper {
|
.innerWrapper {
|
||||||
padding: 15px;
|
padding: 12px 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: rgba(255, 255, 255, 0.7);
|
background: rgba(255, 255, 255, 0.7);
|
||||||
border-radius: 13px;
|
border-radius: 13px;
|
||||||
|
|
@ -21,7 +21,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
font-size: 16px;
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right{
|
.right{
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export default function AntechamberWishList() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{wishList.length > 0 ? (
|
{wishList.length > 0 ? (
|
||||||
<div className="w-full p-[15px]">
|
<div className="w-full px-[15px]">
|
||||||
<div className="px-[12px] pt-[14px] pb-[16px] rounded-[13px] bg-[#fff]">
|
<div className="px-[12px] pt-[14px] pb-[16px] rounded-[13px] bg-[#fff]">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="w-[96px] h-[16px] object-contain">
|
<div className="w-[96px] h-[16px] object-contain">
|
||||||
|
|
@ -95,7 +95,6 @@ export default function AntechamberWishList() {
|
||||||
<div className="text-[10px] px-[4px] py-[2px] rounded-[4px] text-[#636363] bg-[#fff]">
|
<div className="text-[10px] px-[4px] py-[2px] rounded-[4px] text-[#636363] bg-[#fff]">
|
||||||
{item.type}
|
{item.type}
|
||||||
</div>
|
</div>
|
||||||
<div></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[#303030] text-[11px] flex items-center">
|
<div className="text-[#303030] text-[11px] flex items-center">
|
||||||
<span>
|
<span>
|
||||||
|
|
@ -118,7 +117,7 @@ export default function AntechamberWishList() {
|
||||||
<img
|
<img
|
||||||
src="/icons/rightBlue.png"
|
src="/icons/rightBlue.png"
|
||||||
alt=""
|
alt=""
|
||||||
className="ml-[2px]"
|
className="ml-[2px] w-[10px] h-[10px]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -163,7 +162,7 @@ export default function AntechamberWishList() {
|
||||||
onClick={() => handleNavigate(wishList[0])}
|
onClick={() => handleNavigate(wishList[0])}
|
||||||
>
|
>
|
||||||
智能分析
|
智能分析
|
||||||
<img src="/icons/rightBlue.png" alt="" className="ml-[2px]" />
|
<img src="/icons/rightBlue.png" alt="" className="ml-[2px] w-[10px] h-[10px]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,8 @@ export const RealtimeClientProvider = ({
|
||||||
const connectorId = "1024";
|
const connectorId = "1024";
|
||||||
|
|
||||||
const clientRef = useRef<RealtimeClient | null>(null);
|
const clientRef = useRef<RealtimeClient | null>(null);
|
||||||
|
// 添加连接锁
|
||||||
|
const connectingLockRef = useRef<boolean>(false);
|
||||||
// 实时语音回复消息列表
|
// 实时语音回复消息列表
|
||||||
const [messageList, setMessageList] = useState<
|
const [messageList, setMessageList] = useState<
|
||||||
{ content: string; role: RoleType; event?: any }[]
|
{ content: string; role: RoleType; event?: any }[]
|
||||||
|
|
@ -166,6 +168,18 @@ export const RealtimeClientProvider = ({
|
||||||
fileInfo?: FileInfo;
|
fileInfo?: FileInfo;
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
|
// 使用连接锁确保原子性
|
||||||
|
if (connectingLockRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connectingLockRef.current = true;
|
||||||
|
|
||||||
|
// 如果已经连接或正在连接中,直接返回
|
||||||
|
if (isConnected || isConnecting) {
|
||||||
|
connectingLockRef.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!clientRef.current) {
|
if (!clientRef.current) {
|
||||||
await initClient({ initMessage, fileInfo });
|
await initClient({ initMessage, fileInfo });
|
||||||
}
|
}
|
||||||
|
|
@ -192,6 +206,9 @@ export const RealtimeClientProvider = ({
|
||||||
} else {
|
} else {
|
||||||
console.error("连接错误:" + error);
|
console.error("连接错误:" + error);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
// 确保在任何情况下都释放连接锁
|
||||||
|
connectingLockRef.current = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue