import {getDetailList, delDetail, getDetail, getPointByUuid, getPointsById, getAlignPointById} from '../../../services/measure/analysis' import { useState, useEffect, useRef } from 'react' import {message, Button, type TableColumnsType, type TableProps, Modal, Table, Pagination, Input, Select, Switch, Progress, Flex, Spin } from 'antd'; import type { AnalysisReport, DetailTable, SearchParams } from "../../../services/measure/type"; import { ExclamationCircleFilled, CheckCircleOutlined, WarningOutlined } from '@ant-design/icons'; import { AnalysisData, BenchmarkShape, MeasurementCanvasRef } from './konva/MeasurementCanvas'; import MeasurementCanvas from "./konva/MeasurementCanvas"; import { dictionaryListService, kljUpload } from "../../../services/ktj/org"; import { getReport } from "../../../services/measure/analysis"; import { getBaseRecordPointSetByCode } from "../../../services/track/trackShape" import { extraDescType, KTJ_BASE_TYPE } from '../../../services/ktjTypes'; import { GX_CODE } from '../../../constant'; import { exportFile, padNumber } from '../../../utils'; export default function MeasureDetail() { useEffect(()=>{ queryDictionaryList() const params = { pageSize, pageNum, } getDetailDataList(params) }, []) const [selectRows, setSelectedRow] = useState([]) const [selectedRowKeys, setSelectedRowKeys] = useState([]); const rowSelection = { selectedRowKeys, onChange: (selectedRowKeys: React.Key[], selectedRows: DetailTable[]) => { console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); setSelectedRow(selectedRows) setSelectedRowKeys(selectedRowKeys) }, getCheckboxProps: (record: DetailTable) => ({ name: record.name, }), }; const columns: TableColumnsType = [ { title: '序号', dataIndex: 'seq', render:(_, record, index)=>{ return index + 1 } }, { title: '测量名称', dataIndex: 'name', }, { title: '数据来源', dataIndex: 'dataSource', render:(_, record)=>{ const dataSource = record.dataSource return dataSource === 'DCDC' ? '道岔调查' : '线路调查' } }, { title: '轨型', dataIndex: 'railSize', }, { title: '当天测量序号', dataIndex: 'todayNumber', render: (_, record) => ( padNumber(record.todayNumber, 4) ) }, { title: '创建者', dataIndex: 'operator', }, { title: '时间', dataIndex: 'createTime', }, { title: '操作', dataIndex: 'op', width:180, align:'center', render:(_, record)=>{ return
} }, ]; const [tableData, setTableData] = useState([]) const [total, setTotal] = useState(0) const getDetailDataList = (params:SearchParams) => { setLoading(true) getDetailList(params).then(res => { if(res.success){ setLoading(false) //@ts-ignore setTableData(res.data.list) setTotal(res.data.total) }else{ } }).catch(e=>{ }).finally(()=>{ setLoading(false) }) } const [selectionType, setSelectionType] = useState<'checkbox'>('checkbox'); const { confirm } = Modal; const onBatchDel = () => { confirm({ title: '提示', icon: , content: '请确认是否删除选中的数据', okText:'确认', cancelText:'取消', onOk() { onHandelDelData() }, onCancel() { console.log('Cancel'); }, }); } let [idList, setIdList] = useState([]); let [isModaUploadlOpen, setIsModaUploadlOpen] = useState(false) const onUploadData = () => { setIdList([]) let list = [...selectRows] let Ids:number[] = [] list.map(item => { Ids.push(item.id) }) setIdList(Ids) handleUpload(Ids) setIsModaUploadlOpen(true) } const onDownloadData = async () => { // 1. 准备 id 列表 const Ids = selectRows.map(r => r.id); // 2. 发起请求 const response = await fetch(`/api/measurement-data/downloads-zip/${Ids.join(',')}`); // 3. 拿到 Blob const blob = await response.blob(); // 4. 解析后端文件名 const contentDisp = response.headers.get('content-disposition'); const filename = parseFilename(contentDisp) || 'download.zip'; // 5. 触发下载 exportFile(blob, filename); }; const [percent, setPercent] = useState(0) const [failRecordNames, setFailRecordName] = useState([]) const [successRecordNames, setSuccessRecordName] = useState([]) const handleUpload = (Ids:number[]) => { if(Ids && Ids.length){ kljUpload({ ids:Ids }).then(res => { if(res.status !== 0){ message.error('道岔数据上传失败') }else{ message.success('上传成功') if(res.data.successList && res.data.successList.length){ let list:string[] = [] res.data.successList.map((item:string) => { let recordName = item.split(":")[0] list.push(recordName) }) setSuccessRecordName(list) } if(res.data.failList && res.data.failList.length){ let list:string[] = [] res.data.failList.map((item:string) => { let recordName = item.split(":")[0] list.push(recordName) }) setFailRecordName(list) } setPercent(100) } }).catch(e=>{ }) } } //关闭上传 const handleCloseUpload = () => { } const [currentRecord, setCurrentRecord] = useState>({}) const onShowDetail = async (item:DetailTable)=> { //获取基线 setIsModalOpen(true) setCurrentRecord(item) setshowCalibration(false) let res = await getBaseRecordPointSetByCode(item.railSize) if (res.success && res.data && res.data.points) { const benchmarkShapes = JSON.parse(res.data.points) as BenchmarkShape[]; if(!benchmarkShapes || !benchmarkShapes.length){ message.error('选择的测量记录没有数据') return; } setTimeout(()=>{ if (canvasRef.current) { console.log("解析后的基础图形数据:", benchmarkShapes); canvasRef.current.setBenchmarkData(benchmarkShapes); } },100) } let resData = await getDetail({id:item.id}) if(resData){ // navigate(`/measure/detail/${item.id}`) //@ts-ignore // getRecordByUuid(resData.data.uuid) //@ts-ignore onDetaiResult(resData.data.uuid) } //获取测量的坐标点 getMeasurePoints(item) } function parseFilename(disposition: string | null): string | null { if (!disposition) return null; // 匹配 filename*=UTF-8''xxx 或 filename=xxx(带不带引号都能捕获) const match = disposition.match(/filename\*?=(?:UTF-8'')?["']?([^"';]+)["']?/i); return match ? decodeURIComponent(match[1]) : null; } //导出 const onDownloadRecord = async (item: DetailTable) => { // 1. 发请求 const response = await fetch(`/api/measurement-data/download/${item.id}`); // 2. 拿到 Blob const blob = await response.blob(); // 3. 解析头里的文件名 const contentDisp = response.headers.get('content-disposition'); // fallback 到 item.name + .txt const filename = parseFilename(contentDisp) || `${item.name}.txt`; // 4. 触发下载 exportFile(blob, filename); }; const getMeasurePoints = (recordItem:DetailTable) => { getPointsById({id:recordItem.id}).then(res=>{ if (canvasRef.current) { // canvasRef.current.setMeasurementDataLeft(res.data.leftPoints) // canvasRef.current.setMeasurementDataRight(res.data.rightPoints) setshowCalibration(true) canvasRef.current?.setMeasurementCalibrationData(res.data.alignPoints) } }) } //初始化科天健机构数据 let [SJLY_List, setSJLYList] = useState([]); const queryDictionaryList = () => { dictionaryListService().then((res) => { if (res && res.data) { const SJLY:KTJ_BASE_TYPE[] = res.data.SJLY if(SJLY && SJLY.length){ let sjlylist = SJLY.filter(item => item.key === 'XLDC' || item.key === 'DCDC') setSJLYList(sjlylist); } } }); }; const onCancelModal = () => { setIsModaUploadlOpen(false) setPercent(0) setFailRecordName([]) setSuccessRecordName([]) } //法线 const [analysisReport, setAnalysisReport] = useState(); const onDetaiResult = (uuid:string) => { const gxValue= currentRecord.railSize || GX_CODE const params = { uuid, code:gxValue } getReport(params).then(res=> { if (res.success) { const report: AnalysisReport = res.data; console.log(report); // 更新 canvas 的分析数据 if (report && report.angleAnalysisList) { // 先过滤掉 distance 为 null 的数据 const validItems = report.angleAnalysisList.filter(item => item.distance !== null); const analysisData: AnalysisData[] = validItems.map(item => ({ pointA: { x: parseFloat(item.pointA ? item.pointA.x : '0'), y: parseFloat(item.pointA ? item.pointA.y : '0') }, pointB: { x: parseFloat(item.pointB ? item.pointB.x : '0'), y: parseFloat(item.pointB ? item.pointB.y : '0') }, base: { x: parseFloat(item.pointA ? item.pointA.x : '0'), y: parseFloat(item.pointA ? item.pointA.y : '0') }, measure: { x: parseFloat(item.pointB ? item.pointB.x : '0'), y: parseFloat(item.pointB ? item.pointB.y : '0') }, distance: parseFloat(item.distance), describe: item.describe, })); canvasRef.current?.setAnalysisData(analysisData); } setAnalysisReport(report); } else { message.error("分析报告请求失败: " + res.data.info); } }) } const getRecordByUuid = (uuid:string) => { getPointByUuid({uuid}).then(res=>{ if(res.data && res.data.points){ canvasRef.current?.setMeasurementData(res.data.points); } }) } type DelParams = { ids: string | number; } const onHandelDelData = () =>{ let list = [...selectRows] const ids = list.map(item => item.id) if(!ids || !ids.length){ return; } const params = { ids:ids.join(',') } doDel(params) } const doDel = (params:DelParams) => { delDetail(params).then(res => { if(res.success){ message.success('删除成功') const params = { pageSize, pageNum, } getDetailDataList(params) setSelectedRowKeys([]) setSelectedRow([]) } }).catch(e=> { }) } const [pageNum, setPageNum] = useState(1) const [pageSize, setPageSize] = useState(8) const onPageChange = (pageNumValue:number, pageSizeValue:number) => { setPageNum(pageNumValue) setPageSize(pageSizeValue) searchParams = { ...searchParams, pageSize:pageSizeValue, pageNum:pageNumValue, } getDetailDataList(searchParams) } const [name, setName] = useState() const [dataSource, setDataSource] = useState() let searchParams:SearchParams = { pageNum, pageSize, } const onSearch = ()=> { setPageNum(1) setPageSize(5) searchParams = { pageSize, pageNum: 1, name, dataSource } getDetailDataList(searchParams) } let [loading, setLoading] = useState(false) let [isModalOpen, setIsModalOpen] = useState(false) const canvasRef = useRef(null); const [showGrid, setShowGrid] = useState(true); const [angleMarkBackup, setAngleMarkBackup] = useState(true); const [showStandard, setShowStandard] = useState(true); const [showMark, setShowMark] = useState(true); const handleCancel = () => { canvasRef.current?.setAnalysisData([]); canvasRef.current?.setMeasurementData([]); canvasRef.current?.setBenchmarkData([]) //@ts-ignore setAnalysisReport({}) setIsModalOpen(false) } //校准 const [showCalibration, setshowCalibration] = useState(false) const [caloading, setCaLoading] = useState(false) const handleCalibration = () => { setCaLoading(true) if(currentRecord && currentRecord.id){ getAlignPointById({id:currentRecord.id}).then(res=>{ if(res.success){ setshowCalibration(true) canvasRef.current?.setMeasurementCalibrationData(res.data) }else{ message.error('校准失败!') } setCaLoading(false) }).catch(e=>{ message.error('校准失败!') }) } } useEffect(() => { const intervalId = setInterval(() => { if (percent < 100) { const randomIncrement = Math.floor(Math.random() * 3) + 1; const newProgress = Math.min(percent + randomIncrement, 100); setPercent(newProgress); } else { clearInterval(intervalId); } }, 1000); if(percent >= 90){ clearInterval(intervalId); } return () => { clearInterval(intervalId); }; }, [isModaUploadlOpen,percent]); return (
{isModalOpen ?
setShowGrid(checked)} /> 参考线
{ setShowStandard(checked); if (!checked) { setAngleMarkBackup(showMark); setShowMark(false); } else { setShowMark(angleMarkBackup); } }} /> 标准线
{ setShowMark(checked); setAngleMarkBackup(checked); }} /> 角度线
{analysisReport &&
分析
{analysisReport.angleAnalysisList ? analysisReport.angleAnalysisList.map((item, index) => ( )) :
加载中……
}
W1垂直磨耗 {analysisReport.w1}
轨头宽度 {analysisReport.railHeadWidth}
{item.describe} {item.distance}
{/*
*/}
}
: <>
setName(e.target.value)} style={{ width: 200 }}/>
style={{height:"70vh"}} locale={{ emptyText: '无数据', }} loading={loading} rowSelection={{ type: selectionType, ...rowSelection }} columns={columns} rowKey="id" dataSource={tableData && tableData.map(item => ({ ...item, key: item.name }))} pagination={false} scroll={{ y: 500 }} />
{/* {idList.length > 0 &&
选择的道岔调查数据:{idList.length}  个
} */} 共上传: {selectRows.length} 个 {percent === 100 &&
成功:{successRecordNames.length} 个 {successRecordNames.join(',')}
失败:{failRecordNames.length} 个 {failRecordNames.join(',')}
}
}
); }