mirror of
https://gitee.com/san-bing/JChargePointProtocol
synced 2026-05-05 02:19:56 +08:00
添加查询充电枪状态接口
This commit is contained in:
@@ -17,6 +17,7 @@ import Dashboard from './components/Dashboard';
|
||||
import StationManagement from './components/StationManagement';
|
||||
import PileManagement from './components/PileManagement';
|
||||
import GunManagement from './components/GunManagement';
|
||||
import GunDebug from './components/GunDebug';
|
||||
import NotFoundRedirect from './components/NotFoundRedirect';
|
||||
import './App.css';
|
||||
|
||||
@@ -71,6 +72,13 @@ const App: React.FC = () => {
|
||||
</Layout>
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="/page/guns/:gunCode/debug" element={
|
||||
<ProtectedRoute>
|
||||
<Layout>
|
||||
<GunDebug/>
|
||||
</Layout>
|
||||
</ProtectedRoute>
|
||||
}/>
|
||||
|
||||
{/* 智能404重定向 - 根据登录状态决定重定向目标 */}
|
||||
<Route path="*" element={<NotFoundRedirect />} />
|
||||
|
||||
404
jcpp-web-ui/src/components/GunDebug.tsx
Normal file
404
jcpp-web-ui/src/components/GunDebug.tsx
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
|
||||
* 微信:mohan_88888
|
||||
* 抖音:程序员三丙
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {useNavigate, useParams, useSearchParams} from 'react-router-dom';
|
||||
import {Alert, Breadcrumb, Button, Card, Descriptions, Divider, message, Space, Spin, Typography} from 'antd';
|
||||
import {ArrowLeftOutlined, BugOutlined, HomeOutlined, PlayCircleOutlined} from '@ant-design/icons';
|
||||
import {Gun} from '../types';
|
||||
import * as gunService from '../services/gunService';
|
||||
import {api, getErrorMessage} from '../services/api';
|
||||
|
||||
const {Title, Text} = Typography;
|
||||
|
||||
interface DebugResult {
|
||||
url: string;
|
||||
method: string;
|
||||
headers: Record<string, string>;
|
||||
requestBody: any;
|
||||
response: any;
|
||||
timestamp: string;
|
||||
status: 'success' | 'error';
|
||||
}
|
||||
|
||||
const GunDebug: React.FC = () => {
|
||||
const {gunCode} = useParams<{ gunCode: string }>();
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [gun, setGun] = useState<Gun | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [debugLoading, setDebugLoading] = useState(false);
|
||||
const [debugResult, setDebugResult] = useState<DebugResult | null>(null);
|
||||
const [pileDebugLoading, setPileDebugLoading] = useState(false);
|
||||
const [pileDebugResult, setPileDebugResult] = useState<DebugResult | null>(null);
|
||||
|
||||
// 获取返回URL,如果没有则使用默认的充电枪管理页面
|
||||
const returnUrl = searchParams.get('returnUrl') || '/page/guns';
|
||||
|
||||
// 面包屑配置 - 按照官方文档标准写法
|
||||
const breadcrumbItems = [
|
||||
{
|
||||
title: (
|
||||
<span>
|
||||
<HomeOutlined/>
|
||||
<span style={{marginLeft: 8}}>首页</span>
|
||||
</span>
|
||||
),
|
||||
onClick: () => navigate('/page/dashboard'),
|
||||
},
|
||||
{
|
||||
title: '充电枪管理',
|
||||
onClick: () => navigate(returnUrl),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<span>
|
||||
<BugOutlined/>
|
||||
<span style={{marginLeft: 8}}>充电枪调试</span>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// 加载充电枪信息
|
||||
useEffect(() => {
|
||||
const loadGunInfo = async () => {
|
||||
if (!gunCode) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const gun = await gunService.getGunByCode(gunCode);
|
||||
setGun(gun);
|
||||
} catch (error: any) {
|
||||
console.error('加载充电枪信息失败:', error);
|
||||
const errorMessage = getErrorMessage(error);
|
||||
message.error(`加载充电枪信息失败: ${errorMessage}`);
|
||||
navigate('/page/guns');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadGunInfo();
|
||||
}, [gunCode, navigate]);
|
||||
|
||||
// 返回充电枪列表,保持原有的查询参数
|
||||
const handleBack = () => {
|
||||
navigate(returnUrl);
|
||||
};
|
||||
|
||||
// 执行充电枪状态查询调试
|
||||
const handleDebugGunStatus = async () => {
|
||||
if (!gun) return;
|
||||
|
||||
// 清除充电桩调试结果,只显示充电枪调试结果
|
||||
setPileDebugResult(null);
|
||||
setDebugLoading(true);
|
||||
try {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
// 直接调用现有的正确API接口
|
||||
const response = await api.get(`/api/guns/status/${gun.gunCode}`);
|
||||
|
||||
setDebugResult({
|
||||
url: `/api/guns/status/${gun.gunCode}`,
|
||||
method: 'GET',
|
||||
headers,
|
||||
requestBody: null,
|
||||
response: response.data,
|
||||
timestamp: new Date().toLocaleString(),
|
||||
status: response.data.success ? 'success' : 'error'
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
message.success('调试执行成功');
|
||||
} else {
|
||||
message.error('调试执行失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
const errorResult = {
|
||||
url: `/api/guns/status/${gun.gunCode}`,
|
||||
method: 'GET',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
requestBody: null,
|
||||
response: {success: false, message: getErrorMessage(error)},
|
||||
timestamp: new Date().toLocaleString(),
|
||||
status: 'error' as const
|
||||
};
|
||||
|
||||
setDebugResult(errorResult);
|
||||
message.error('调试执行失败');
|
||||
} finally {
|
||||
setDebugLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 执行充电桩状态查询调试
|
||||
const handleDebugPileStatus = async () => {
|
||||
if (!gun || !gun.pileCode) {
|
||||
message.error('充电桩编码不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除充电枪调试结果,只显示充电桩调试结果
|
||||
setDebugResult(null);
|
||||
setPileDebugLoading(true);
|
||||
try {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
// 直接调用现有的正确API接口
|
||||
const response = await api.get(`/api/piles/status/${gun.pileCode}`);
|
||||
|
||||
setPileDebugResult({
|
||||
url: `/api/piles/status/${gun.pileCode}`,
|
||||
method: 'GET',
|
||||
headers,
|
||||
requestBody: null,
|
||||
response: response.data,
|
||||
timestamp: new Date().toLocaleString(),
|
||||
status: response.data.success ? 'success' : 'error'
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
message.success('调试执行成功');
|
||||
} else {
|
||||
message.error('调试执行失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
const errorResult = {
|
||||
url: `/api/piles/status/${gun.pileCode}`,
|
||||
method: 'GET',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
requestBody: null,
|
||||
response: {success: false, message: getErrorMessage(error)},
|
||||
timestamp: new Date().toLocaleString(),
|
||||
status: 'error' as const
|
||||
};
|
||||
|
||||
setPileDebugResult(errorResult);
|
||||
message.error('调试执行失败');
|
||||
} finally {
|
||||
setPileDebugLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{padding: 24, textAlign: 'center'}}>
|
||||
<Spin size="large"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!gun) {
|
||||
return (
|
||||
<div style={{padding: 24}}>
|
||||
<Alert
|
||||
message="充电枪不存在"
|
||||
description="未找到指定的充电枪信息"
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{padding: 24}}>
|
||||
{/* 面包屑导航 */}
|
||||
<Breadcrumb
|
||||
items={breadcrumbItems}
|
||||
style={{marginBottom: 16}}
|
||||
/>
|
||||
|
||||
{/* 页面标题和返回按钮 */}
|
||||
<div style={{marginBottom: 24, display: 'flex', alignItems: 'center', justifyContent: 'space-between'}}>
|
||||
<Title level={3} style={{margin: 0}}>
|
||||
<BugOutlined style={{marginRight: 8}}/>
|
||||
充电枪调试 - {gun.gunName}
|
||||
</Title>
|
||||
<Button
|
||||
icon={<ArrowLeftOutlined/>}
|
||||
onClick={handleBack}
|
||||
>
|
||||
返回列表
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 充电枪基本信息 */}
|
||||
<Card title="充电枪基本信息" style={{marginBottom: 24}}>
|
||||
<Descriptions column={2} bordered>
|
||||
<Descriptions.Item label="充电枪名称">{gun.gunName}</Descriptions.Item>
|
||||
<Descriptions.Item label="充电枪编码">{gun.gunCode}</Descriptions.Item>
|
||||
<Descriptions.Item label="充电枪编号">{gun.gunNo}</Descriptions.Item>
|
||||
<Descriptions.Item label="所属充电桩">{gun.pileName}</Descriptions.Item>
|
||||
<Descriptions.Item label="充电桩编码">{gun.pileCode}</Descriptions.Item>
|
||||
<Descriptions.Item label="所属充电站">{gun.stationName}</Descriptions.Item>
|
||||
<Descriptions.Item label="创建时间">
|
||||
{gun.createdTime ? new Date(gun.createdTime).toLocaleString() : '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="更新时间">
|
||||
{gun.updatedTime ? new Date(gun.updatedTime).toLocaleString() : '-'}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
{/* 调试操作区域 */}
|
||||
<Card title="调试操作" style={{marginBottom: 24}}>
|
||||
<Space direction="vertical" style={{width: '100%'}}>
|
||||
<div>
|
||||
<Text strong>接口调试</Text>
|
||||
<div style={{marginTop: 8}}>
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlayCircleOutlined/>}
|
||||
loading={debugLoading}
|
||||
onClick={handleDebugGunStatus}
|
||||
>
|
||||
查询充电枪状态
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlayCircleOutlined/>}
|
||||
loading={pileDebugLoading}
|
||||
onClick={handleDebugPileStatus}
|
||||
>
|
||||
查询充电桩状态
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
{/* 充电枪调试结果展示 */}
|
||||
{debugResult && (
|
||||
<Card title="充电枪状态调试结果">
|
||||
<Space direction="vertical" style={{width: '100%'}}>
|
||||
<Alert
|
||||
message={debugResult.status === 'success' ? '调试成功' : '调试失败'}
|
||||
type={debugResult.status === 'success' ? 'success' : 'error'}
|
||||
showIcon
|
||||
/>
|
||||
|
||||
<Descriptions column={1} bordered size="small">
|
||||
<Descriptions.Item label="请求URL">
|
||||
<Text code>{debugResult.url}</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="请求方法">
|
||||
<Text code>{debugResult.method}</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="请求时间">
|
||||
{debugResult.timestamp}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<Divider orientation="left">请求头 (Headers)</Divider>
|
||||
<pre style={{
|
||||
background: '#f5f5f5',
|
||||
padding: 12,
|
||||
borderRadius: 4,
|
||||
fontSize: 12,
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
{JSON.stringify(debugResult.headers, null, 2)}
|
||||
</pre>
|
||||
|
||||
<Divider orientation="left">请求体 (Request Body)</Divider>
|
||||
<pre style={{
|
||||
background: '#f5f5f5',
|
||||
padding: 12,
|
||||
borderRadius: 4,
|
||||
fontSize: 12,
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
{JSON.stringify(debugResult.requestBody, null, 2)}
|
||||
</pre>
|
||||
|
||||
<Divider orientation="left">响应结果 (Response)</Divider>
|
||||
<pre style={{
|
||||
background: debugResult.status === 'success' ? '#f6ffed' : '#fff2f0',
|
||||
padding: 12,
|
||||
borderRadius: 4,
|
||||
fontSize: 12,
|
||||
overflow: 'auto',
|
||||
border: `1px solid ${debugResult.status === 'success' ? '#b7eb8f' : '#ffccc7'}`
|
||||
}}>
|
||||
{JSON.stringify(debugResult.response, null, 2)}
|
||||
</pre>
|
||||
</Space>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 充电桩调试结果展示 */}
|
||||
{pileDebugResult && (
|
||||
<Card title="充电桩状态调试结果" style={{marginTop: 16}}>
|
||||
<Space direction="vertical" style={{width: '100%'}}>
|
||||
<Alert
|
||||
message={pileDebugResult.status === 'success' ? '调试成功' : '调试失败'}
|
||||
type={pileDebugResult.status === 'success' ? 'success' : 'error'}
|
||||
showIcon
|
||||
/>
|
||||
|
||||
<Descriptions column={1} bordered size="small">
|
||||
<Descriptions.Item label="请求URL">
|
||||
<Text code>{pileDebugResult.url}</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="请求方法">
|
||||
<Text code>{pileDebugResult.method}</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="请求时间">
|
||||
{pileDebugResult.timestamp}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<Divider orientation="left">请求头 (Headers)</Divider>
|
||||
<pre style={{
|
||||
background: '#f5f5f5',
|
||||
padding: 12,
|
||||
borderRadius: 4,
|
||||
fontSize: 12,
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
{JSON.stringify(pileDebugResult.headers, null, 2)}
|
||||
</pre>
|
||||
|
||||
<Divider orientation="left">请求体 (Request Body)</Divider>
|
||||
<pre style={{
|
||||
background: '#f5f5f5',
|
||||
padding: 12,
|
||||
borderRadius: 4,
|
||||
fontSize: 12,
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
{JSON.stringify(pileDebugResult.requestBody, null, 2)}
|
||||
</pre>
|
||||
|
||||
<Divider orientation="left">响应结果 (Response)</Divider>
|
||||
<pre style={{
|
||||
background: pileDebugResult.status === 'success' ? '#f6ffed' : '#fff2f0',
|
||||
padding: 12,
|
||||
borderRadius: 4,
|
||||
fontSize: 12,
|
||||
overflow: 'auto',
|
||||
border: `1px solid ${pileDebugResult.status === 'success' ? '#b7eb8f' : '#ffccc7'}`
|
||||
}}>
|
||||
{JSON.stringify(pileDebugResult.response, null, 2)}
|
||||
</pre>
|
||||
</Space>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GunDebug;
|
||||
@@ -5,6 +5,7 @@
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
import React, {useEffect, useMemo, useState} from 'react';
|
||||
import {useLocation, useNavigate, useSearchParams} from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -22,7 +23,14 @@ import {
|
||||
Tag,
|
||||
Typography
|
||||
} from 'antd';
|
||||
import {DeleteOutlined, PlusOutlined, ReloadOutlined, SearchOutlined, TableOutlined} from '@ant-design/icons';
|
||||
import {
|
||||
BugOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
ReloadOutlined,
|
||||
SearchOutlined,
|
||||
TableOutlined
|
||||
} from '@ant-design/icons';
|
||||
import type {ColumnsType, TableProps} from 'antd/es/table';
|
||||
import {formatTimestamp, generateGunCode, showMessage} from '../utils';
|
||||
import {getErrorMessage} from '../services/api';
|
||||
@@ -34,6 +42,9 @@ import type {Gun, GunCreateRequest, GunUpdateRequest, PileOption, StationOption}
|
||||
const { confirm } = Modal;
|
||||
|
||||
const GunManagement: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [urlSearchParams, setUrlSearchParams] = useSearchParams();
|
||||
const [dataSource, setDataSource] = useState<Gun[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchForm] = Form.useForm();
|
||||
@@ -55,6 +66,29 @@ const GunManagement: React.FC = () => {
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
});
|
||||
|
||||
// 从URL参数初始化搜索参数
|
||||
const initSearchParams = (): {
|
||||
page: number;
|
||||
size: number;
|
||||
gunName?: string;
|
||||
gunCode?: string;
|
||||
gunNo?: string;
|
||||
stationId?: string;
|
||||
sortField?: string;
|
||||
sortOrder?: string;
|
||||
} => {
|
||||
return {
|
||||
page: parseInt(urlSearchParams.get('page') || '1'),
|
||||
size: parseInt(urlSearchParams.get('size') || '10'),
|
||||
gunName: urlSearchParams.get('gunName') || undefined,
|
||||
gunCode: urlSearchParams.get('gunCode') || undefined,
|
||||
gunNo: urlSearchParams.get('gunNo') || undefined,
|
||||
stationId: urlSearchParams.get('stationId') || undefined,
|
||||
sortField: urlSearchParams.get('sortField') || undefined,
|
||||
sortOrder: urlSearchParams.get('sortOrder') || undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const [searchParams, setSearchParams] = useState<{
|
||||
page: number;
|
||||
size: number;
|
||||
@@ -236,8 +270,13 @@ const GunManagement: React.FC = () => {
|
||||
<Button type="link" size="small" onClick={() => handleEdit(record)}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button type="link" size="small" onClick={() => handleView(record)}>
|
||||
查看
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<BugOutlined/>}
|
||||
onClick={() => handleDebug(record)}
|
||||
>
|
||||
调试
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="确认删除充电枪"
|
||||
@@ -429,11 +468,22 @@ const GunManagement: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 监听搜索参数变化
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchParams]);
|
||||
// 更新搜索参数的函数,同时更新URL
|
||||
const updateSearchParams = (newParams: any) => {
|
||||
setSearchParams(newParams);
|
||||
|
||||
// 更新URL参数
|
||||
const urlParams = new URLSearchParams();
|
||||
Object.entries(newParams).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
urlParams.set(key, String(value));
|
||||
}
|
||||
});
|
||||
setUrlSearchParams(urlParams);
|
||||
};
|
||||
|
||||
// 标记是否已经初始化URL参数
|
||||
const [urlParamsInitialized, setUrlParamsInitialized] = useState(false);
|
||||
|
||||
// 初始化加载充电站选项和充电桩选项
|
||||
useEffect(() => {
|
||||
@@ -441,6 +491,72 @@ const GunManagement: React.FC = () => {
|
||||
loadPileOptions();
|
||||
}, []);
|
||||
|
||||
// 组件挂载后立即从URL参数初始化搜索参数
|
||||
useEffect(() => {
|
||||
const urlParams = initSearchParams();
|
||||
// 只有当URL参数与当前searchParams不同时才更新
|
||||
const hasUrlParams = urlParams.gunName || urlParams.gunCode || urlParams.gunNo ||
|
||||
urlParams.stationId || urlParams.sortField || urlParams.sortOrder ||
|
||||
urlParams.page !== 1 || urlParams.size !== 10;
|
||||
|
||||
if (hasUrlParams) {
|
||||
console.log('从URL初始化搜索参数:', urlParams);
|
||||
setSearchParams(urlParams);
|
||||
}
|
||||
setUrlParamsInitialized(true);
|
||||
}, [urlSearchParams]); // 依赖urlSearchParams,确保URL变化时重新初始化
|
||||
|
||||
// 监听搜索参数变化,但只有在URL参数初始化完成后才加载数据
|
||||
useEffect(() => {
|
||||
if (urlParamsInitialized) {
|
||||
loadData();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchParams, urlParamsInitialized]);
|
||||
|
||||
// 初始化表单值(从URL参数)
|
||||
useEffect(() => {
|
||||
const initialValues = {
|
||||
gunName: searchParams.gunName || '',
|
||||
gunCode: searchParams.gunCode || '',
|
||||
gunNo: searchParams.gunNo || '',
|
||||
stationId: searchParams.stationId || '',
|
||||
};
|
||||
searchForm.setFieldsValue(initialValues);
|
||||
}, [searchForm, searchParams.gunName, searchParams.gunCode, searchParams.gunNo, searchParams.stationId]);
|
||||
|
||||
// 初始化时如果URL有搜索参数,需要触发一次数据加载
|
||||
useEffect(() => {
|
||||
// 检查是否有搜索条件(除了page和size之外的参数)
|
||||
const hasSearchConditions = searchParams.gunName || searchParams.gunCode ||
|
||||
searchParams.gunNo || searchParams.stationId;
|
||||
|
||||
if (hasSearchConditions) {
|
||||
// 如果有搜索条件,确保数据会被重新加载
|
||||
// 这里不需要手动调用loadData,因为searchParams的变化会触发useEffect中的loadData
|
||||
console.log('检测到URL搜索参数,将自动加载数据:', searchParams);
|
||||
}
|
||||
}, []); // 只在组件初始化时执行一次
|
||||
|
||||
// 处理从充电桩管理页面传来的搜索参数
|
||||
useEffect(() => {
|
||||
const state = location.state as { searchPileCode?: string } | null;
|
||||
if (state?.searchPileCode) {
|
||||
// 设置搜索表单的值
|
||||
searchForm.setFieldValue('gunCode', state.searchPileCode);
|
||||
|
||||
// 更新搜索参数并触发搜索
|
||||
updateSearchParams({
|
||||
...searchParams,
|
||||
gunCode: state.searchPileCode,
|
||||
page: 1 // 重置到第一页
|
||||
});
|
||||
|
||||
// 清除location.state,避免重复处理
|
||||
window.history.replaceState({}, document.title);
|
||||
}
|
||||
}, [location.state]);
|
||||
|
||||
// 处理表格变化
|
||||
const handleTableChange: TableProps<Gun>['onChange'] = (pag, filters, sorter) => {
|
||||
let newParams = {
|
||||
@@ -458,7 +574,7 @@ const GunManagement: React.FC = () => {
|
||||
delete newParams.sortOrder;
|
||||
}
|
||||
|
||||
setSearchParams(newParams);
|
||||
updateSearchParams(newParams);
|
||||
};
|
||||
|
||||
// 搜索处理
|
||||
@@ -468,7 +584,7 @@ const GunManagement: React.FC = () => {
|
||||
size: pagination.pageSize,
|
||||
...values
|
||||
};
|
||||
setSearchParams(newParams);
|
||||
updateSearchParams(newParams);
|
||||
};
|
||||
|
||||
// 重置搜索
|
||||
@@ -478,7 +594,7 @@ const GunManagement: React.FC = () => {
|
||||
page: 1,
|
||||
size: pagination.pageSize
|
||||
};
|
||||
setSearchParams(newParams);
|
||||
updateSearchParams(newParams);
|
||||
};
|
||||
|
||||
// 显示新建模态框
|
||||
@@ -500,9 +616,18 @@ const GunManagement: React.FC = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 处理查看
|
||||
const handleView = (record: Gun) => {
|
||||
showMessage.info('查看功能待实现');
|
||||
// 处理调试 - 跳转到调试页面,携带当前查询参数
|
||||
const handleDebug = (record: Gun) => {
|
||||
// 直接从URL中获取当前的查询参数,确保获取到最新的参数
|
||||
const currentUrlParams = new URLSearchParams(window.location.search);
|
||||
const queryString = currentUrlParams.toString();
|
||||
const returnUrl = queryString ? `/page/guns?${queryString}` : '/page/guns';
|
||||
|
||||
console.log('调试跳转 - 当前URL参数:', queryString);
|
||||
console.log('调试跳转 - 返回URL:', returnUrl);
|
||||
|
||||
// 将returnUrl作为URL参数传递
|
||||
navigate(`/page/guns/${record.gunCode}/debug?returnUrl=${encodeURIComponent(returnUrl)}`);
|
||||
};
|
||||
|
||||
// 生成充电枪编码
|
||||
@@ -971,6 +1096,7 @@ const GunManagement: React.FC = () => {
|
||||
</Row>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* 付费课程知识星球:https://t.zsxq.com/aKtXo
|
||||
*/
|
||||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {useNavigate} from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -44,6 +45,8 @@ const { confirm } = Modal;
|
||||
|
||||
|
||||
const PileManagement: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 状态管理
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<Pile[]>([]);
|
||||
@@ -95,6 +98,7 @@ const PileManagement: React.FC = () => {
|
||||
{ key: 'manufacturer', title: '制造商', defaultVisible: false },
|
||||
{ key: 'type', title: '类型', defaultVisible: false },
|
||||
{ key: 'status', title: '状态', defaultVisible: true },
|
||||
{key: 'gunCount', title: '充电枪数量', defaultVisible: true},
|
||||
{ key: 'connectedAt', title: '连接时间', defaultVisible: true },
|
||||
{ key: 'disconnectedAt', title: '断线时间', defaultVisible: true },
|
||||
{ key: 'lastActiveTime', title: '最后活跃时间', defaultVisible: true },
|
||||
@@ -200,6 +204,27 @@ const PileManagement: React.FC = () => {
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '充电枪数量',
|
||||
dataIndex: 'gunCount',
|
||||
key: 'gunCount',
|
||||
width: 100,
|
||||
sorter: true,
|
||||
render: (gunCount: number, record: Pile) => (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
onClick={() => handleGunCountClick(record.pileCode)}
|
||||
style={{
|
||||
padding: 0,
|
||||
height: 'auto',
|
||||
color: gunCount > 0 ? '#1890ff' : '#999'
|
||||
}}
|
||||
>
|
||||
{gunCount || 0}
|
||||
</Button>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '连接时间',
|
||||
dataIndex: 'connectedAt',
|
||||
key: 'connectedAt',
|
||||
@@ -594,6 +619,16 @@ const PileManagement: React.FC = () => {
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理充电枪数量点击
|
||||
const handleGunCountClick = (pileCode: string) => {
|
||||
// 跳转到充电枪管理页面,并设置搜索条件
|
||||
navigate('/page/guns', {
|
||||
state: {
|
||||
searchPileCode: pileCode
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 生成充电桩编码
|
||||
const handleGeneratePileCode = () => {
|
||||
|
||||
@@ -31,3 +31,8 @@ export const getGun = async (id: string): Promise<Gun> => {
|
||||
return response.data.data;
|
||||
};
|
||||
|
||||
export const getGunByCode = async (gunCode: string): Promise<Gun> => {
|
||||
const response = await api.get(`/api/guns/code/${gunCode}`);
|
||||
return response.data.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ export interface Pile {
|
||||
connectedAt?: number;
|
||||
disconnectedAt?: number;
|
||||
lastActiveTime?: number;
|
||||
gunCount?: number;
|
||||
createdTime: number;
|
||||
updatedTime?: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user