This commit is contained in:
hu xiaotong
2025-07-02 16:29:14 +08:00
parent 0246bc7060
commit 50281ce812
3 changed files with 212 additions and 165 deletions

View File

@@ -12,7 +12,8 @@
"antd": "^5.12.8", "antd": "^5.12.8",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^7.6.3" "react-router-dom": "^7.6.3",
"zustand": "^5.0.6"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.43", "@types/react": "^18.2.43",
@@ -1583,14 +1584,14 @@
"version": "15.7.15", "version": "15.7.15",
"resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz", "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"dev": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "18.3.23", "version": "18.3.23",
"resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.23.tgz", "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.23.tgz",
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
"dev": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
@@ -4487,6 +4488,35 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
},
"node_modules/zustand": {
"version": "5.0.6",
"resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.6.tgz",
"integrity": "sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A==",
"license": "MIT",
"engines": {
"node": ">=12.20.0"
},
"peerDependencies": {
"@types/react": ">=18.0.0",
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
},
"use-sync-external-store": {
"optional": true
}
}
} }
} }
} }

View File

@@ -14,7 +14,8 @@
"antd": "^5.12.8", "antd": "^5.12.8",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^7.6.3" "react-router-dom": "^7.6.3",
"zustand": "^5.0.6"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.43", "@types/react": "^18.2.43",

View File

@@ -1,12 +1,19 @@
import React, {useEffect, useState, useRef} from 'react' import React, {useEffect, useRef, useState} from 'react';
import {Button, Card, Layout, message, Select, Spin, Table} from 'antd' import {Button, Card, Layout, message, Select, Spin, Table} from 'antd';
import {DownloadOutlined, PlayCircleOutlined, SettingOutlined, StopOutlined} from '@ant-design/icons' import {DownloadOutlined, PlayCircleOutlined, SettingOutlined, StopOutlined} from '@ant-design/icons';
import '../App.css' import '../App.css';
import {ExportData, GetCapturedData,GetNetworkInterfaces, import {
ParseData,StartCapture,StopCapture, ReadRawJsonFile ExportData,
} from "../../wailsjs/go/service/App"; GetCapturedData,
GetNetworkInterfaces,
ParseData,
ReadRawJsonFile,
StartCapture,
StopCapture
} from '../../wailsjs/go/service/App';
import {useCaptureStore} from '../store/useCaptureStore';
const {Header, Content, Sider} = Layout const { Header, Content, Sider } = Layout;
interface NetworkInterface { interface NetworkInterface {
name: string name: string
@@ -35,15 +42,25 @@ interface CaptureResult {
} }
function CapturePage() { function CapturePage() {
const [interfaces, setInterfaces] = useState<NetworkInterface[]>([]) // 只用全局 parsedData
const [selectedInterface, setSelectedInterface] = useState<string>('') const parsedData = useCaptureStore(state => state.parsedData);
const [isCapturing, setIsCapturing] = useState(false) const setParsedData = useCaptureStore(state => state.setParsedData);
const [capturedData, setCapturedData] = useState<string[]>([])
const [parsedData, setParsedData] = useState<CaptureResult | null>(null) // 其余状态全部本地 useState
const [loading, setLoading] = useState(false) const [interfaces, setInterfaces] = useState<NetworkInterface[]>([]);
const [interfaceLoading, setInterfaceLoading] = useState(false) const [selectedInterface, setSelectedInterface] = useState('');
const [uploadedFileName, setUploadedFileName] = useState<string>('') const [isCapturing, setIsCapturing] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null) const [capturedData, setCapturedData] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const [interfaceLoading, setInterfaceLoading] = useState(false);
const [uploadedFileName, setUploadedFileName] = useState('');
const fileInputRef = useRef<HTMLInputElement>(null);
// 顶部 message 只显示一次
const showMessage = (type: 'success' | 'error' | 'warning', content: string) => {
message.destroy();
message[type](content);
};
const safeApiCall = async <T,>( const safeApiCall = async <T,>(
apiCall: () => Promise<T>, apiCall: () => Promise<T>,
@@ -51,20 +68,20 @@ function CapturePage() {
fallbackValue: T fallbackValue: T
): Promise<T> => { ): Promise<T> => {
try { try {
return await apiCall() return await apiCall();
} catch (error) { } catch (error) {
console.error(`${errorMessage}:`, error) console.error(`${errorMessage}:`, error);
message.error(errorMessage) showMessage('error', errorMessage);
return fallbackValue return fallbackValue;
}
} }
};
const fetchInterfaces = async () => { const fetchInterfaces = async () => {
setIsCapturing(false) setIsCapturing(false);
setCapturedData([]) setCapturedData([]);
setParsedData(null) setParsedData(null);
setLoading(false) setLoading(false);
setInterfaceLoading(true) setInterfaceLoading(true);
try { try {
const response = await safeApiCall( const response = await safeApiCall(
() => GetNetworkInterfaces(), () => GetNetworkInterfaces(),
@@ -74,85 +91,85 @@ function CapturePage() {
{ name: 'wlan0', description: 'Wireless', addresses: ['192.168.1.101'], is_loopback: false }, { name: 'wlan0', description: 'Wireless', addresses: ['192.168.1.101'], is_loopback: false },
{ name: 'lo', description: 'Loopback', addresses: ['127.0.0.1'], is_loopback: true } { name: 'lo', description: 'Loopback', addresses: ['127.0.0.1'], is_loopback: true }
] ]
) );
setInterfaces(response) setInterfaces(response);
let defaultSelected = '' let defaultSelected = '';
for (const iface of response) { for (const iface of response) {
if (iface.addresses && iface.addresses.some(ip => ip.includes('192.168'))) { if (iface.addresses && iface.addresses.some(ip => ip.includes('192.168'))) {
defaultSelected = iface.name defaultSelected = iface.name;
break break;
} }
} }
if (!defaultSelected && response.length > 0) { if (!defaultSelected && response.length > 0) {
defaultSelected = response[0].name defaultSelected = response[0].name;
} }
setSelectedInterface(defaultSelected) setSelectedInterface(defaultSelected);
} catch (error) { } catch (error) {
console.error('获取网络接口时发生未知错误:', error) console.error('获取网络接口时发生未知错误:', error);
const defaultInterfaces = [ const defaultInterfaces = [
{ name: 'eth0', description: 'Ethernet', addresses: ['192.168.1.100'], is_loopback: false }, { name: 'eth0', description: 'Ethernet', addresses: ['192.168.1.100'], is_loopback: false },
{ name: 'wlan0', description: 'Wireless', addresses: ['192.168.1.101'], is_loopback: false }, { name: 'wlan0', description: 'Wireless', addresses: ['192.168.1.101'], is_loopback: false },
{ name: 'lo', description: 'Loopback', addresses: ['127.0.0.1'], is_loopback: true } { name: 'lo', description: 'Loopback', addresses: ['127.0.0.1'], is_loopback: true }
] ];
setInterfaces(defaultInterfaces) setInterfaces(defaultInterfaces);
setSelectedInterface(defaultInterfaces[0].name) setSelectedInterface(defaultInterfaces[0].name);
} finally { } finally {
setInterfaceLoading(false) setInterfaceLoading(false);
}
} }
};
const startCapture = async () => { const startCapture = async () => {
if (!selectedInterface) { if (!selectedInterface) {
message.warning('请选择网络接口') showMessage('warning', '请选择网络接口');
return return;
} }
setLoading(true) setLoading(true);
try { try {
await safeApiCall( await safeApiCall(
() => StartCapture(selectedInterface), () => StartCapture(selectedInterface),
'开始抓包失败,但界面将继续工作', '开始抓包失败,但界面将继续工作',
undefined undefined
) );
setIsCapturing(true) setIsCapturing(true);
message.success('开始抓包') showMessage('success', '开始抓包');
} catch (error) { } catch (error) {
console.error('开始抓包时发生未知错误:', error) console.error('开始抓包时发生未知错误:', error);
setIsCapturing(true) setIsCapturing(true);
message.success('开始抓包(模拟模式)') showMessage('success', '开始抓包(模拟模式)');
} finally { } finally {
setLoading(false) setLoading(false);
}
} }
};
const stopCapture = async () => { const stopCapture = async () => {
setLoading(false) setLoading(false);
setIsCapturing(false) setIsCapturing(false);
setCapturedData([]) setCapturedData([]);
setParsedData(null) setParsedData(null);
try { try {
setLoading(true) setLoading(true);
await safeApiCall( await safeApiCall(
() => StopCapture(), () => StopCapture(),
'停止抓包失败,但界面将继续工作', '停止抓包失败,但界面将继续工作',
undefined undefined
) );
setIsCapturing(false) setIsCapturing(false);
const data = await safeApiCall( const data = await safeApiCall(
() => GetCapturedData(), () => GetCapturedData(),
'获取抓包数据失败,使用模拟数据', '获取抓包数据失败,使用模拟数据',
['mock_data_1', 'mock_data_2', 'mock_data_3'] ['mock_data_1', 'mock_data_2', 'mock_data_3']
) );
setCapturedData(data) setCapturedData(data);
if (data && data.length > 0) { if (data && data.length > 0) {
data.forEach((item, idx) => { data.forEach((item, idx) => {
let hexStr = '' let hexStr = '';
if (/^[0-9a-fA-F\s]+$/.test(item)) { if (/^[0-9a-fA-F\s]+$/.test(item)) {
hexStr = item hexStr = item;
} else { } else {
hexStr = Array.from(item).map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join(' ') hexStr = Array.from(item).map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join(' ');
} }
console.log(`抓包数据[${idx}]:`, hexStr) console.log(`抓包数据[${idx}]:`, hexStr);
}) });
} }
if (data.length > 0) { if (data.length > 0) {
const parsed = await safeApiCall( const parsed = await safeApiCall(
@@ -166,13 +183,13 @@ function CapturePage() {
], ],
heroes: [] heroes: []
}) })
) );
try { try {
const parsedData = JSON.parse(parsed) const parsedData = JSON.parse(parsed);
setParsedData(parsedData) setParsedData(parsedData);
message.success('数据处理完成') showMessage('success', '数据处理完成');
} catch (parseError) { } catch (parseError) {
console.error('解析JSON失败:', parseError) console.error('解析JSON失败:', parseError);
setParsedData({ setParsedData({
items: [ items: [
{ id: '1', code: 'SWORD001', ct: 100, e: 1500, g: 5, l: false, mg: 10, op: [], p: 25, s: 'Legendary', sk: 3 }, { id: '1', code: 'SWORD001', ct: 100, e: 1500, g: 5, l: false, mg: 10, op: [], p: 25, s: 'Legendary', sk: 3 },
@@ -180,110 +197,109 @@ function CapturePage() {
{ id: '3', code: 'HELMET003', ct: 60, e: 800, g: 3, l: false, mg: 8, op: [], p: 12, s: 'Common', sk: 1 } { id: '3', code: 'HELMET003', ct: 60, e: 800, g: 3, l: false, mg: 8, op: [], p: 12, s: 'Common', sk: 1 }
], ],
heroes: [] heroes: []
}) });
message.success('数据处理完成(使用模拟数据)') showMessage('success', '数据处理完成(使用模拟数据)');
} }
} else { } else {
message.warning('未捕获到数据') showMessage('warning', '未捕获到数据');
} }
} catch (error) { } catch (error) {
console.error('停止抓包时发生未知错误:', error) console.error('停止抓包时发生未知错误:', error);
setIsCapturing(false) setIsCapturing(false);
setCapturedData([]) setCapturedData([]);
setParsedData(null) setParsedData(null);
setLoading(false) setLoading(false);
message.error('抓包失败,已重置状态') showMessage('error', '抓包失败,已重置状态');
return return;
} finally { } finally {
setLoading(false) setLoading(false);
}
} }
};
const exportData = async () => { const exportData = async () => {
if (!capturedData.length) { if (!capturedData.length) {
message.warning('没有数据可导出') showMessage('warning', '没有数据可导出');
return return;
} }
try { try {
const filename = `equipment_data_${Date.now()}.json` const filename = `equipment_data_${Date.now()}.json`;
await safeApiCall( await safeApiCall(
() => ExportData(capturedData, filename), () => ExportData(capturedData, filename),
'导出数据失败', '导出数据失败',
undefined undefined
) );
message.success('数据导出成功') showMessage('success', '数据导出成功');
} catch (error) { } catch (error) {
console.error('导出数据时发生未知错误:', error) console.error('导出数据时发生未知错误:', error);
message.success('数据导出成功(模拟模式)') showMessage('success', '数据导出成功(模拟模式)');
}
} }
};
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => { const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0] const file = event.target.files?.[0];
if (!file) return if (!file) return;
setUploadedFileName(file.name) setUploadedFileName(file.name);
const reader = new FileReader() const reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
try { try {
const text = e.target?.result as string const text = e.target?.result as string;
const json = JSON.parse(text) const json = JSON.parse(text);
const safeData = { const safeData = {
items: Array.isArray(json.items) ? json.items : [], items: Array.isArray(json.items) ? json.items : [],
heroes: Array.isArray(json.heroes) ? json.heroes : [] heroes: Array.isArray(json.heroes) ? json.heroes : []
} };
setParsedData(safeData) setParsedData(safeData);
if (safeData.items.length === 0 && safeData.heroes.length === 0) { if (safeData.items.length === 0 && safeData.heroes.length === 0) {
message.warning('上传文件数据为空,请检查文件内容') showMessage('warning', '上传文件数据为空,请检查文件内容');
} else { } else {
message.success(`文件解析成功:${safeData.items.length}件装备,${safeData.heroes.length}个英雄`) showMessage('success', `文件解析成功:${safeData.items.length}件装备,${safeData.heroes.length}个英雄`);
} }
} catch (err) { } catch (err) {
console.error('文件格式错误,无法解析:', err) console.error('文件格式错误,无法解析:', err);
message.error('文件格式错误,无法解析') showMessage('error', '文件格式错误,无法解析');
setParsedData({ items: [], heroes: [] }) setParsedData({ items: [], heroes: [] });
}
}
reader.readAsText(file)
} }
};
reader.readAsText(file);
};
const fetchParsedDataFromBackend = async () => { const fetchParsedDataFromBackend = async () => {
setLoading(true) setLoading(true);
try { try {
const raw = await ReadRawJsonFile() const raw = await ReadRawJsonFile();
const json = JSON.parse(raw) const json = JSON.parse(raw);
console.log('已加载本地解析数据:', json) console.log('已加载本地解析数据:', json);
const safeData = { const safeData = {
items: Array.isArray(json.items) ? json.items : [], items: Array.isArray(json.items) ? json.items : [],
heroes: Array.isArray(json.heroes) ? json.heroes : [] heroes: Array.isArray(json.heroes) ? json.heroes : []
} };
setParsedData(safeData) setParsedData(safeData);
if (safeData.items.length === 0 && safeData.heroes.length === 0) { if (safeData.items.length === 0 && safeData.heroes.length === 0) {
message.warning('解析数据为空,请检查数据源') showMessage('warning', '解析数据为空,请检查数据源');
} else { } else {
message.success(`已加载本地解析数据:${safeData.items.length}件装备,${safeData.heroes.length}个英雄`) showMessage('success', `已加载本地解析数据:${safeData.items.length}件装备,${safeData.heroes.length}个英雄`);
} }
} catch (err) { } catch (err) {
console.error('读取本地解析数据失败:', err) console.error('读取本地解析数据失败:', err);
message.error('读取本地解析数据失败') showMessage('error', '读取本地解析数据失败');
setParsedData({ items: [], heroes: [] }) setParsedData({ items: [], heroes: [] });
} finally { } finally {
setLoading(false) setLoading(false);
}
} }
};
const handleRefreshParsedData = () => { const handleRefreshParsedData = () => {
setParsedData(null) setParsedData(null);
setUploadedFileName('') setUploadedFileName('');
fetchParsedDataFromBackend() fetchParsedDataFromBackend();
} };
const handleUploadButtonClick = () => { const handleUploadButtonClick = () => {
fileInputRef.current?.click(); fileInputRef.current?.click();
} };
useEffect(() => { useEffect(() => {
fetchInterfaces(); fetchInterfaces();
fetchParsedDataFromBackend();
}, []); }, []);
const equipmentColumns = [ const equipmentColumns = [
@@ -328,107 +344,107 @@ function CapturePage() {
dataIndex: 'sk', dataIndex: 'sk',
key: 'sk', key: 'sk',
}, },
] ];
return ( return (
<Layout style={{minHeight: '100vh'}}> <Layout style={{ minHeight: '100vh' }}>
<Header style={{background: '#fff', padding: '0 20px'}}> <Header style={{ background: '#fff', padding: '0 16px', height: 48, lineHeight: '48px' }}>
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between'}}> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', height: 48 }}>
<h1 style={{margin: 0}}></h1> <h1 style={{ margin: 0, fontSize: 20 }}></h1>
<div style={{display: 'flex', gap: 8, alignItems: 'center'}}> <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
<Button <Button
type="primary" type="primary"
icon={<SettingOutlined/>} icon={<SettingOutlined />}
onClick={handleRefreshParsedData} onClick={handleRefreshParsedData}
loading={loading} loading={loading}
style={{flex: 1}} style={{ flex: 1, height: 32 }}
></Button> ></Button>
<Button style={{flex: 1}} onClick={handleUploadButtonClick}> <Button style={{ flex: 1, height: 32 }} onClick={handleUploadButtonClick}>
JSON JSON
</Button> </Button>
<input <input
ref={fileInputRef} ref={fileInputRef}
type="file" type="file"
accept="application/json" accept="application/json"
style={{display: 'none'}} style={{ display: 'none' }}
onChange={handleFileUpload} onChange={handleFileUpload}
/> />
{uploadedFileName && ( {uploadedFileName && (
<span style={{marginLeft: 8, color: '#888', fontSize: 12}}>{uploadedFileName}</span> <span style={{ marginLeft: 8, color: '#888', fontSize: 12 }}>{uploadedFileName}</span>
)} )}
</div> </div>
</div> </div>
</Header> </Header>
<Layout> <Layout>
<Sider width={300} style={{background: '#fff'}}> <Sider width={220} style={{ background: '#fff' }}>
<div style={{padding: '20px'}}> <div style={{ padding: '12px' }}>
<Card title="抓包控制" size="small"> <Card title="抓包控制" size="small">
<div style={{marginBottom: 16}}> <div style={{ marginBottom: 12 }}>
<label></label> <label></label>
<Select <Select
style={{width: '100%', marginTop: 8}} style={{ width: '100%', marginTop: 6 }}
value={selectedInterface} value={selectedInterface}
onChange={setSelectedInterface} onChange={setSelectedInterface}
placeholder="选择网络接口" placeholder="选择网络接口"
loading={interfaceLoading} loading={interfaceLoading}
> >
{interfaces.map(iface => ( {interfaces.map((iface) => (
<Select.Option key={iface.name} value={iface.name}> <Select.Option key={iface.name} value={iface.name}>
{iface.addresses} {iface.addresses.join(', ')}
</Select.Option> </Select.Option>
))} ))}
</Select> </Select>
</div> </div>
<div style={{display: 'flex', gap: 8}}> <div style={{ display: 'flex', gap: 8 }}>
<Button <Button
type="primary" type="primary"
icon={<PlayCircleOutlined/>} icon={<PlayCircleOutlined />}
onClick={startCapture} onClick={startCapture}
disabled={isCapturing || !selectedInterface} disabled={isCapturing || !selectedInterface}
loading={loading} loading={loading}
style={{flex: 1}} style={{ flex: 1, height: 32 }}
> >
</Button> </Button>
<Button <Button
danger danger
icon={<StopOutlined/>} icon={<StopOutlined />}
onClick={stopCapture} onClick={stopCapture}
disabled={!isCapturing} disabled={!isCapturing}
loading={loading} loading={loading}
style={{flex: 1}} style={{ flex: 1, height: 32 }}
> >
</Button> </Button>
</div> </div>
<div style={{marginTop: 16}}> <div style={{ marginTop: 12 }}>
<Button <Button
icon={<DownloadOutlined/>} icon={<DownloadOutlined />}
onClick={exportData} onClick={exportData}
disabled={!capturedData.length} disabled={!capturedData.length}
style={{width: '100%'}}> style={{ width: '100%', height: 32 }}>
</Button> </Button>
</div> </div>
</Card> </Card>
<Card title="抓包状态" size="small" style={{marginTop: 16}}> <Card title="抓包状态" size="small" style={{ marginTop: 12 }}>
<div> <div>
<p>: {isCapturing ? '正在抓包...' : '准备就绪'}</p> <p style={{ marginBottom: 4 }}>: {isCapturing ? '正在抓包...' : '准备就绪'}</p>
<p>: {capturedData.length} </p> <p style={{ marginBottom: 4 }}>: {capturedData.length} </p>
{parsedData && ( {parsedData && (
<p>: {parsedData.items.length} </p> <p style={{ marginBottom: 0 }}>: {parsedData.items.length} </p>
)} )}
</div> </div>
</Card> </Card>
</div> </div>
</Sider> </Sider>
<Content style={{padding: '20px'}}> <Content style={{ padding: '16px' }}>
<Spin spinning={loading}> <Spin spinning={loading}>
{parsedData && parsedData.items.length > 0 ? ( {parsedData && parsedData.items.length > 0 ? (
<Card title="装备数据"> <Card title="装备数据">
@@ -436,15 +452,15 @@ function CapturePage() {
dataSource={parsedData.items} dataSource={parsedData.items}
columns={equipmentColumns} columns={equipmentColumns}
rowKey="id" rowKey="id"
pagination={{pageSize: 10}} pagination={{ pageSize: 10 }}
scroll={{x: true}} scroll={{ x: true }}
/> />
</Card> </Card>
) : ( ) : (
<Card title="数据预览"> <Card title="数据预览">
<div style={{textAlign: 'center', padding: '40px'}}> <div style={{ textAlign: 'center', padding: '40px' }}>
<p></p> <p></p>
<p style={{color: '#999', fontSize: '12px'}}> <p style={{ color: '#999', fontSize: '12px' }}>
{parsedData ? '数据为空,请检查数据源或上传文件' : '请开始抓包或上传JSON文件'} {parsedData ? '数据为空,请检查数据源或上传文件' : '请开始抓包或上传JSON文件'}
</p> </p>
</div> </div>
@@ -454,7 +470,7 @@ function CapturePage() {
</Content> </Content>
</Layout> </Layout>
</Layout> </Layout>
) );
} }
export default CapturePage export default CapturePage;