You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
651 lines
18 KiB
651 lines
18 KiB
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<DetailTable[]>([])
|
|
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
|
|
|
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<DetailTable> = [
|
|
{
|
|
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 <div>
|
|
<Button type="link" onClick={()=>onShowDetail(record)}>查看结果</Button>
|
|
<Button type="link" onClick={()=>onDownloadRecord(record)}>导出</Button>
|
|
</div>
|
|
}
|
|
},
|
|
];
|
|
|
|
const [tableData, setTableData] = useState<DetailTable[]>([])
|
|
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: <ExclamationCircleFilled />,
|
|
content: '请确认是否删除选中的数据',
|
|
okText:'确认',
|
|
cancelText:'取消',
|
|
onOk() {
|
|
onHandelDelData()
|
|
},
|
|
onCancel() {
|
|
console.log('Cancel');
|
|
},
|
|
});
|
|
}
|
|
|
|
let [idList, setIdList] = useState<number[]>([]);
|
|
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<string[]>([])
|
|
const [successRecordNames, setSuccessRecordName] = useState<string[]>([])
|
|
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<Partial<DetailTable>>({})
|
|
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<KTJ_BASE_TYPE[]>([]);
|
|
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<AnalysisReport>();
|
|
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<string>()
|
|
const [dataSource, setDataSource] = useState<string>()
|
|
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<MeasurementCanvasRef>(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 (
|
|
<div>
|
|
|
|
{isModalOpen ?
|
|
<div className="pt-[5px]">
|
|
<div className="flex">
|
|
<div className="ml-[2rem]">
|
|
<Switch size="small" defaultChecked onChange={checked => setShowGrid(checked)} />
|
|
<span>参考线</span>
|
|
</div>
|
|
|
|
<div className="ml-[1rem] ">
|
|
<Switch
|
|
size="small"
|
|
checked={showStandard}
|
|
onChange={checked => {
|
|
setShowStandard(checked);
|
|
if (!checked) {
|
|
setAngleMarkBackup(showMark);
|
|
setShowMark(false);
|
|
} else {
|
|
setShowMark(angleMarkBackup);
|
|
}
|
|
}}
|
|
/>
|
|
<span>标准线</span>
|
|
</div>
|
|
|
|
<div className="ml-[1rem]">
|
|
<Switch
|
|
size="small"
|
|
checked={showMark}
|
|
onChange={checked => {
|
|
setShowMark(checked);
|
|
setAngleMarkBackup(checked);
|
|
}}
|
|
/>
|
|
<span>角度线</span>
|
|
</div>
|
|
</div>
|
|
<div className="flex ml-[2rem] mt-[5px]">
|
|
<MeasurementCanvas
|
|
width={800}
|
|
height={700}
|
|
logicalExtent={{ minX: -50, maxX: 50, minY: -20, maxY: 60 }}
|
|
gridStep={1}
|
|
origin={{ x: 0, y: 20 }}
|
|
pixelPerMm={8}
|
|
maxZoom={10}
|
|
showGrid={showGrid}
|
|
showBenchmark={showStandard}
|
|
showAnalysis={showMark}
|
|
showScale={false}
|
|
scaleInterval={1}
|
|
showCoordinates={true}
|
|
showCalibration={showCalibration}
|
|
ref={canvasRef}
|
|
/>
|
|
|
|
{analysisReport &&
|
|
<div className=" h-[550px] ml-[1rem]">
|
|
|
|
<header className="bg-[#e8f0ff] w-[300px] text-center text-lg font-medium py-2 text-primary border border-[#c1c6d4]">
|
|
分析
|
|
</header>
|
|
<div className="analysis-table">
|
|
<table
|
|
style={{
|
|
width: "100%",
|
|
borderCollapse: "collapse",
|
|
border: "1px solid #ccc",
|
|
textAlign: "center",
|
|
}}>
|
|
<tbody>
|
|
<tr style={{ height: "40px", fontSize: "18px", color: "#9E9E9E" }}>
|
|
<td style={{ padding: "8px", border: "1px solid #ccc" }}>W1垂直磨耗</td>
|
|
<td style={{ padding: "8px", border: "1px solid #ccc" }}>{analysisReport.w1}</td>
|
|
</tr>
|
|
<tr style={{ height: "40px", fontSize: "18px", color: "#9E9E9E" }}>
|
|
<td style={{ padding: "8px", border: "1px solid #ccc" }}>轨头宽度</td>
|
|
<td style={{ padding: "8px", border: "1px solid #ccc" }}>
|
|
{analysisReport.railHeadWidth}
|
|
</td>
|
|
</tr>
|
|
{analysisReport.angleAnalysisList ? analysisReport.angleAnalysisList.map((item, index) => (
|
|
<tr key={index} style={{ height: "40px", fontSize: "18px", color: "#9E9E9E" }}>
|
|
<td style={{ padding: "8px", border: "1px solid #ccc" }}>{item.describe}</td>
|
|
<td style={{ padding: "8px", border: "1px solid #ccc" }}>{item.distance}</td>
|
|
</tr>
|
|
))
|
|
:
|
|
<div className="h-[28rem]">加载中……</div>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{/* <div className="flex justify-center mt-[1.5rem]" >
|
|
<Button type="primary" onClick={handleCalibration} className='w-[150px]'>
|
|
校准
|
|
</Button>
|
|
</div> */}
|
|
<div className="flex justify-center mt-[1.5rem]" >
|
|
<Button type="primary" onClick={handleCancel} className='w-[150px]'>
|
|
返回
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
</div>
|
|
</div>
|
|
:
|
|
<>
|
|
<div className="p-[15px]">
|
|
<Button
|
|
disabled={!selectRows.length}
|
|
type="primary"
|
|
onClick={onBatchDel}>
|
|
删除
|
|
</Button>
|
|
|
|
<Button
|
|
className='ml-[2rem]'
|
|
disabled={!selectRows.length}
|
|
type="primary"
|
|
onClick={onUploadData}>
|
|
上传
|
|
</Button>
|
|
<Button
|
|
className='ml-[2rem]'
|
|
disabled={!selectRows.length}
|
|
type="primary"
|
|
onClick={onDownloadData}>
|
|
批量导出
|
|
</Button>
|
|
|
|
<Input className='ml-[2rem]' allowClear placeholder="测量名称" onChange={(e)=>setName(e.target.value)} style={{ width: 200 }}/>
|
|
<Select
|
|
placeholder="请选择数据来源"
|
|
className='ml-[2rem] w-[150px]'
|
|
allowClear
|
|
onChange={setDataSource}
|
|
options={SJLY_List.map((item) => ({
|
|
label: item.value,
|
|
value: item.key,
|
|
}))}
|
|
></Select>
|
|
<Button type="primary" className='ml-[2rem]' onClick={onSearch}>搜索</Button>
|
|
</div>
|
|
<div>
|
|
<Table<DetailTable>
|
|
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 }}
|
|
|
|
/>
|
|
<div className="float-right mt-[10px] mr-[1rem]">
|
|
<Pagination onChange={onPageChange} current={pageNum} pageSizeOptions={[5,10,20,30]} defaultCurrent={pageNum} defaultPageSize={pageSize} total={total}/>
|
|
</div>
|
|
|
|
<Modal title="上传状态" open={isModaUploadlOpen} footer={null} onCancel={onCancelModal}>
|
|
{/* {idList.length > 0 && <div className='modal_upload'>选择的道岔调查数据:<span style={{color:"green"}}>{idList.length}</span> 个</div>} */}
|
|
<Progress percent={percent} size="small" />
|
|
共上传: {selectRows.length} 个
|
|
{percent === 100 &&
|
|
<div >
|
|
<div style={{marginTop:"10px"}}>
|
|
<CheckCircleOutlined style={{color:'#52C41A', fontSize:"20px"}}/>
|
|
<span style={{paddingLeft:"20px"}}>成功:{successRecordNames.length} 个 {successRecordNames.join(',')}</span>
|
|
</div>
|
|
<div style={{marginTop:"10px"}}>
|
|
<WarningOutlined style={{color:'#ff4d4f', fontSize:"20px"}}/>
|
|
<span style={{paddingLeft:"20px"}}>失败:{failRecordNames.length} 个 {failRecordNames.join(',')}</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<br/>
|
|
<div style={{marginTop:"20px",marginLeft:"28vw"}}>
|
|
<Button type="primary" onClick={onCancelModal}>确认</Button>
|
|
</div>
|
|
</Modal>
|
|
</div>
|
|
</>
|
|
}
|
|
</div>
|
|
);
|
|
}
|