Files
EST-DSX/src/components/dsxpage/ResultInfo.js
2025-09-16 16:39:48 +08:00

658 lines
30 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import StatusBar from '../lib/StatusBar';
import ResultTitleBar from '../lib/ResultTitleBar';
import TitleBar from '../lib/TitleBar';
import CopperResultMain from '../lib/CopperResultMain';
import OLTSResultMain from '../lib/OLTSResultMain';
import OTDRResultMain from '../lib/OTDRResultMain';
import Keyboard from '../lib/Keyboard';
import useDisplayStore from '@/store/displayStore';
// 初始化测试结果音效对象
const testPassSound = typeof Audio !== 'undefined' ? new Audio('/sounds/test_pass.wav') : null;
const testFailSound = typeof Audio !== 'undefined' ? new Audio('/sounds/test_fail.wav') : null;
// 自定义确认弹窗组件
const ConfirmDialog = ({ message, onConfirm, onCancel }) => (
<div className="w-[480px] h-[640px] bg-[#002842d4] absolute z-[9999] top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<div className='pl-10 pt-60'>
<div className="bg-[#2B3C5B] rounded-lg p-6 w-[400px] min-h-[200px] flex flex-col">
<h3 className="text-white text-xl font-bold mb-4">提示</h3>
<div className="flex-1 flex items-center justify-center">
<div className="text-white text-lg">{message}</div>
</div>
<div className="flex justify-center gap-4 mt-4">
<button
onClick={onConfirm}
className="bg-[#354e7a] text-white px-6 py-2 rounded hover:bg-[#1E293B] transition-colors"
>
确定
</button>
<button
onClick={onCancel}
className="bg-[#4a4a4a] text-white px-6 py-2 rounded hover:bg-[#3a3a3a] transition-colors"
>
取消
</button>
</div>
</div>
</div>
</div>
);
export default function ResultInfo() {
const [showKeyboard, setShowKeyboard] = useState(true);
const [cursorPosition, setCursorPosition] = useState(0);
const [inputValue, setInputValue] = useState('');
const [inputValue2, setInputValue2] = useState('');
const [activeInput, setActiveInput] = useState(1); // 1 表示第一个输入框2 表示第二个输入框
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [confirmDialogMessage, setConfirmDialogMessage] = useState('');
const [confirmDialogCallback, setConfirmDialogCallback] = useState(null);
const { navigation } = useDisplayStore.getState();
const tempTestResult = navigation.current.params;
// 根据测试结果播放音效
const { hasPlayedSound } = useDisplayStore.getState();
useEffect(() => {
// 只有从测试页面进入nosave视图时才播放声音
if (navigation.previous.name === 'testing' &&
tempTestResult &&
!hasPlayedSound) {
if (tempTestResult.CopperResultStatus === 'pass'||tempTestResult.CFPResultStatus === 'pass' ||tempTestResult.ofpResultStatus === 'pass') {
testPassSound?.play().catch(console.error);
} else {
testFailSound?.play().catch(console.error);
}
useDisplayStore.setState({ hasPlayedSound: true });
}
}, [navigation, tempTestResult, hasPlayedSound]);
// 从URL参数中获取临时测试结果
const {
getCurrentProject,
getCurrentCableId,
getCurrentCableId2,
updateCurrentView,
getCurrentTestConfig,
navigateTo,
setToastMessage,
updateProject
} = useDisplayStore();
const currentProject = getCurrentProject();
const { view } = useDisplayStore.getState().navigation.current;
// 获取当前的线缆ID
const currentCableId = getCurrentCableId().name || '';
const currentCableId2 = getCurrentCableId2().name || '';
// 计算下一个序号的ID
const getNextId = (currentId) => {
if (!currentId) return '';
// 检查是否以数字结尾
const numMatch = currentId.match(/^(.*?)(\d+)$/);
if (numMatch) {
const [, prefix, num] = numMatch;
const nextNum = String(Number(num) + 1).padStart(num.length, '0');
return prefix + nextNum;
}
// 检查是否以字母结尾
const letterMatch = currentId.match(/^(.*?)([a-zA-Z]+)$/);
if (letterMatch) {
const [, prefix, letters] = letterMatch;
// 将字母转换为数组以便处理
const letterArray = letters.split('');
let carry = true;
// 从右向左处理每个字母
for (let i = letterArray.length - 1; i >= 0 && carry; i--) {
if (letterArray[i] === 'z') {
letterArray[i] = 'a';
carry = true;
} else if (letterArray[i] === 'Z') {
letterArray[i] = 'A';
carry = true;
} else {
letterArray[i] = String.fromCharCode(letterArray[i].charCodeAt(0) + 1);
carry = false;
}
}
// 如果还有进位,说明需要在前面添加一个字母
if (carry) {
if (letters[0] >= 'a' && letters[0] <= 'z') {
letterArray.unshift('a');
} else {
letterArray.unshift('A');
}
}
return prefix + letterArray.join('');
}
// 如果既不是数字也不是字母结尾,直接返回原值
return currentId;
};
// 初始化输入值为当前的线缆ID
useEffect(() => {
setInputValue(currentCableId);
setInputValue2(currentCableId2);
}, [currentCableId, currentCableId2]);
// 当第一个输入框值变化时,仅在用户手动输入时自动更新第二个输入框
useEffect(() => {
if (tempTestResult?.testconfig?.moduleType === 'cfp' && inputValue && inputValue !== currentCableId) {
setInputValue2(getNextId(inputValue));
}
}, [inputValue, view, currentCableId]);
//创建保存结果存储逻辑
const handleComplete = () => {
const currentId = inputValue.trim();
// 检查是否存在重名的测试结果
const currentProject = getCurrentProject();
const existingResults = currentProject?.testResults || [];
// 检查两个ID是否重复
const isDuplicate = existingResults.some(result => result.name === currentId);
// 重名替换
if (isDuplicate) {
setConfirmDialogMessage('该线缆ID已使用是否覆盖');
setConfirmDialogCallback(() => () => {
// 更新临时测试结果的名称
const updatedTestResult = {
...tempTestResult,
name: currentId
};
// 更新当前项目的测试结果
const currentIndex = useDisplayStore.getState().projects.findIndex(p => p === currentProject);
if (currentIndex !== -1) {
// 移除旧的测试结果并添加新的
const newResults = existingResults.filter(result => result.name !== currentId);
updateProject(currentIndex, {
testResults: [...newResults, updatedTestResult]
});
// 更新navigation.current.params中的测试结果名称
useDisplayStore.setState({
navigation: {
...navigation,
current: {
...navigation.current,
params: updatedTestResult
}
}
});
}
updateCurrentView('save');
setShowConfirmDialog(false);
});
setShowConfirmDialog(true);
return;
}
// 更新临时测试结果的名称并保存到项目中
if (tempTestResult) {
const updatedTestResult = {
...tempTestResult,
name: currentId
};
// 更新当前项目的cableIds.name为下一个ID
const currentIndex = useDisplayStore.getState().projects.findIndex(p => p === currentProject);
if (currentIndex !== -1) {
//更新测试结果
updateProject(currentIndex, {
testResults: [...(currentProject.testResults || []), updatedTestResult]
});
// 更新navigation.current.params中的测试结果名称
const navigation = useDisplayStore.getState().navigation;
useDisplayStore.setState({
navigation: {
...navigation,
current: {
...navigation.current,
params: updatedTestResult
}
}
});
// 获取下一个ID
const nextId = (() => {
const currentId = inputValue.trim();
if (!currentId) return currentId;
// 获取最后一个字符
const lastChar = currentId.slice(-1);
const prefix = currentId.slice(0, -1);
// 如果最后一个字符是数字
if (/\d/.test(lastChar)) {
const match = currentId.match(/^(.*?)(\d+)$/);
if (match) {
const numPrefix = match[1];
const number = parseInt(match[2]) + 1;
return `${numPrefix}${number.toString().padStart(match[2].length, '0')}`;
}
}
// 如果最后一个字符是字母
if (/[A-Za-z]/.test(lastChar)) {
const nextChar = String.fromCharCode(lastChar.charCodeAt(0) + 1);
// 如果超过Z或z回到A或a
if ((lastChar === 'Z' && nextChar > 'Z') || (lastChar === 'z' && nextChar > 'z')) {
const baseChar = lastChar === 'Z' ? 'A' : 'a';
return `${prefix}${baseChar}`;
}
return `${prefix}${nextChar}`;
}
return currentId;
})();
// 获取当前项目的所有cableIds
const currentCableIds = currentProject?.cableIds || [];
const selectedId = getCurrentCableId().id;
// 只更新选中的ID保留其他ID不变
const updatedCableIds = currentCableIds.map(cable =>
cable.id === selectedId ? { ...cable, name: nextId } : cable
);
// 更新项目
updateProject(currentIndex, {
cableIds: updatedCableIds
});
}
updateCurrentView('save');
}
}
const handleComplete2 = () => {
const currentId = inputValue.trim();
const currentId2 = inputValue2.trim();
// 检查两个ID是否相同
if (currentId === currentId2) {
setConfirmDialogMessage('输入输出ID不能相同请检查');
setConfirmDialogCallback(() => () => {
setShowConfirmDialog(false);
});
setShowConfirmDialog(true);
return;
}
// 检查是否存在重名的测试结果
const currentProject = getCurrentProject();
const existingResults = currentProject?.testResults || [];
// 检查两个ID是否重复
const isDuplicate1 = existingResults.some(result => result.name === currentId);
const isDuplicate2 = existingResults.some(result => result.name === currentId2);
const currentConfig = getCurrentTestConfig();
const cableType = currentConfig.params.cableType;
const isMultiMode = cableType.includes('OM');
if (isDuplicate1 || isDuplicate2) {
const message = [];
if (isDuplicate1) message.push(`线缆ID ${currentId}`);
if (isDuplicate2) message.push(`线缆ID ${currentId2}`);
setConfirmDialogMessage(`${message.join(' 和 ')}已使用,是否覆盖?`);
setConfirmDialogCallback(() => () => {
// 更新临时测试结果的名称
const updatedTestResult1 = {
...tempTestResult,
name: currentId,
inputname: isMultiMode ? currentId2 : currentId,
outname: isMultiMode ? currentId : currentId2,
};
const updatedTestResult2 = {
...tempTestResult,
name: currentId2,
inputname: isMultiMode ? currentId2 : currentId,
outname: isMultiMode ? currentId : currentId2,
};
// 更新当前项目的测试结果
const currentIndex = useDisplayStore.getState().projects.findIndex(p => p === currentProject);
if (currentIndex !== -1) {
// 移除旧的测试结果并添加新的
const newResults = existingResults.filter(result =>
result.name !== currentId && result.name !== currentId2
);
updateProject(currentIndex, {
testResults: [...newResults, updatedTestResult1, updatedTestResult2]
});
// 更新navigation.current.params中的测试结果名称
useDisplayStore.setState({
navigation: {
...navigation,
current: {
...navigation.current,
params: updatedTestResult1
}
}
});
}
updateCurrentView('save');
setShowConfirmDialog(false);
});
setShowConfirmDialog(true);
return;
}
// 更新临时测试结果的名称并保存到项目中
if (tempTestResult) {
// 创建两个测试结果
const updatedTestResult1 = {
...tempTestResult,
name: currentId,
inputname: isMultiMode ? currentId2 : currentId,
outname: isMultiMode ? currentId : currentId2,
};
const updatedTestResult2 = {
...tempTestResult,
name: currentId2,
inputname: isMultiMode ? currentId2 : currentId,
outname: isMultiMode ? currentId : currentId2,
};
// 更新当前项目的cableIds.name为下一个ID
const currentIndex = useDisplayStore.getState().projects.findIndex(p => p === currentProject);
if (currentIndex !== -1) {
//更新测试结果
updateProject(currentIndex, {
testResults: [...(currentProject.testResults || []), updatedTestResult1,updatedTestResult2]
});
// 更新navigation.current.params中的测试结果名称
const navigation = useDisplayStore.getState().navigation;
useDisplayStore.setState({
navigation: {
...navigation,
current: {
...navigation.current,
params: updatedTestResult1
}
}
});
// 获取下一个ID
const nextId = getNextId(getNextId(inputValue.trim()));
// 获取下一个ID2
const nextId2 = getNextId(getNextId(inputValue2.trim()));
// 获取当前项目的所有cableIds
const currentCableIds = currentProject?.cableIds || [];
const selectedId = getCurrentCableId().id;
const selectedId2 = getCurrentCableId2().id;
// 只更新选中的ID保留其他ID不变
const updatedCableIds = currentCableIds.map(cable =>
cable.id === selectedId ? { ...cable, name: nextId } :
cable.id === selectedId2 ? { ...cable, name: nextId2 } :
cable
);
// 更新项目,添加两个测试结果
updateProject(currentIndex, {
cableIds: updatedCableIds,
});
}
updateCurrentView('save');
}
}
// 创建测试结果的视图
const renderContent = () => {
const renderResultMain = () => {
const moduleType = tempTestResult?.testconfig?.moduleType;
switch (moduleType) {
case '8000':
return <CopperResultMain testResult={tempTestResult} />;
case 'cfp':
return <OLTSResultMain testResult={tempTestResult} />;
case 'ofp':
return <OTDRResultMain testResult={tempTestResult} />;
default:
return <CopperResultMain testResult={tempTestResult} />;
}
};
const renderSetName = () => {
const moduleType = tempTestResult?.testconfig?.moduleType;
switch (moduleType) {
case 'cfp':
return(
<div className="flex-1 bg-[#303040] p-4 flex flex-col">
<div className="mb-8">
<div className="mb-1 text-white text-sm">输出光纤ID1</div>
<div className="relative cursor-pointer">
<input
type="text"
className="w-full h-[50px] bg-[#ffffe1] rounded-sm px-4 text-black overflow-x-auto whitespace-nowrap"
value={inputValue}
placeholder="请输入线缆ID1"
onChange={(e) => {
setInputValue(e.target.value);
setCursorPosition(e.target.selectionStart);
}}
onClick={(e) => {
setActiveInput(1);
setShowKeyboard(true);
setCursorPosition(e.target.selectionStart);
}}
onFocus={(e) => {
const cursorPosition = e.target.selectionStart;
e.target.setSelectionRange(cursorPosition, cursorPosition);
}}
/>
</div>
</div>
<div>
<div className="mb-1 text-white text-sm">输入光纤ID2</div>
<div className="relative cursor-pointer">
<input
type="text"
className="w-full h-[50px] bg-[#ffffe1] rounded-sm px-4 text-black overflow-x-auto whitespace-nowrap"
value={inputValue2}
placeholder="请输入线缆ID2"
onChange={(e) => {
setInputValue2(e.target.value);
setCursorPosition(e.target.selectionStart);
}}
onClick={(e) => {
setActiveInput(2);
setShowKeyboard(true);
setCursorPosition(e.target.selectionStart);
}}
onFocus={(e) => {
const cursorPosition = e.target.selectionStart;
e.target.setSelectionRange(cursorPosition, cursorPosition);
}}
/>
</div>
</div>
{showKeyboard && (
<Keyboard
value={activeInput === 1 ? inputValue : inputValue2}
cursorPosition={cursorPosition}
onChange={(newValue, newPosition) => {
if (activeInput === 1) {
setInputValue(newValue);
} else {
setInputValue2(newValue);
}
setCursorPosition(newPosition);
}}
onComplete={() => {
setShowKeyboard(false);
}}
/>
)}
</div>
);
default:
return (
<div className="flex-1 bg-[#303040] p-4 flex flex-col">
<div
className="relative mb-4 cursor-pointer"
onClick={() => setShowKeyboard(true)}
>
<input
type="text"
className="w-full h-[50px] bg-[#ffffe1] rounded-sm p-4 text-black"
value={inputValue}
placeholder="请输入线缆ID"
onChange={(e) => {
setInputValue(e.target.value);
setCursorPosition(e.target.selectionStart);
}}
onClick={(e) => {
setShowKeyboard(true);
setCursorPosition(e.target.selectionStart);
}}
onFocus={(e) => {
// 保存光标位置
const cursorPosition = e.target.selectionStart;
e.target.setSelectionRange(cursorPosition, cursorPosition);
}}
/>
</div>
{showKeyboard && (
<Keyboard
value={inputValue}
cursorPosition={cursorPosition}
onChange={(newValue, newPosition) => {
setInputValue(newValue);
setCursorPosition(newPosition);
}}
onComplete={() => {
setShowKeyboard(false);
}}
/>
)}
</div>
);
}
};
switch (view) {
case 'nosave':
return (
<div className="w-full h-full flex flex-col overflow-hidden">
<StatusBar />
{tempTestResult?.testconfig?.moduleType !== 'cfp' ? (
<ResultTitleBar title="未保存结果" testResult={tempTestResult} backTo="home" view="main" />
) : (<ResultTitleBar title=" " testResult={tempTestResult} backTo="home" view="main" />
)}
{renderResultMain()}
<div className="h-[60px] bg-[#303030] flex items-center justify-end px-4">
<button
onClick={() => updateCurrentView('setname')}
className="w-[100px] h-[40px] bg-gradient-to-b from-[#ffd773] to-[#e7aa29] rounded-sm flex items-center justify-center text-black font-bold shadow-lg"
>
保存
</button>
</div>
</div>
);
case 'setname':
return (
<div className="w-full h-full flex flex-col overflow-hidden">
<StatusBar />
<TitleBar
title="保存结果"
backTo={useDisplayStore.getState().navigation.previous?.name || 'home'}
view={useDisplayStore.getState().navigation.previous?.view || 'main'}
/>
<div className="flex-1 bg-[#303040] p-2 flex flex-col">
{renderSetName()}
</div>
<div className="h-[60px] bg-[#303030] flex items-center justify-end px-4">
{tempTestResult?.testconfig?.moduleType === "cfp" ? (
!showKeyboard && (
<button
onClick={() => handleComplete2()}
className="w-[100px] h-[40px] bg-gradient-to-b from-[#ffd773] to-[#e7aa29] rounded-sm flex items-center justify-center text-black font-bold shadow-lg"
>
保存
</button>
)
) : (
!showKeyboard && (<button
onClick={() => handleComplete()}
className="w-[100px] h-[40px] bg-gradient-to-b from-[#ffd773] to-[#e7aa29] rounded-sm flex items-center justify-center text-black font-bold shadow-lg"
>
保存
</button>
)
)}
</div>
</div>
);
case 'save':
return (
<div className="w-full h-full flex flex-col overflow-hidden">
<StatusBar />
{tempTestResult?.testconfig?.moduleType !== 'cfp' ? (
<ResultTitleBar testResult={tempTestResult} backTo="result" view="main" />
) : (<ResultTitleBar title=" " testResult={tempTestResult} backTo="result" view="main" />
)}
{renderResultMain()}
<div className="h-[60px] bg-[#303030] flex items-center justify-end px-4">
<button
onClick={() => {
navigateTo('home', 'main');
}}
className="w-[100px] h-[40px] bg-gradient-to-b from-[#ffd773] to-[#e7aa29] rounded-sm flex items-center justify-center text-black font-bold shadow-lg"
>
主页
</button>
</div>
</div>
);
default:
return null;
}
};
const content = renderContent();
return (
<div className="relative w-full h-full">
{content}
{showConfirmDialog && (
<ConfirmDialog
message={confirmDialogMessage}
onConfirm={confirmDialogCallback}
onCancel={() => setShowConfirmDialog(false)}
/>
)}
</div>
);
}