新增刷新按钮

This commit is contained in:
三丙
2025-09-27 19:01:50 +08:00
parent a1e0a09320
commit 2a2fd21bdb
20 changed files with 226 additions and 80 deletions

View File

@@ -156,7 +156,7 @@ public class RpcController extends BaseController {
/** /**
* 处理离线卡余额更新指令 * 处理离线卡余额更新指令
*/ */
private void handleOfflineCardBalanceUpdate(JsonNode parameter) { private void handleOfflineCardBalanceUpdate(JsonNode parameter) throws Exception {
OfflineCardBalanceUpdateRequest request = JacksonUtil.fromJson(parameter, OfflineCardBalanceUpdateRequest.class); OfflineCardBalanceUpdateRequest request = JacksonUtil.fromJson(parameter, OfflineCardBalanceUpdateRequest.class);
pileProtocolService.offlineCardBalanceUpdateRequest(request); pileProtocolService.offlineCardBalanceUpdateRequest(request);
} }

View File

@@ -54,7 +54,7 @@ public class LvnengV340HeartbeatULCmd extends LvnengUplinkCmdExe {
//5预留 //5预留
byteBuf.skipBytes(16); byteBuf.skipBytes(16);
// 会话添加充电桩编码
tcpSession.addPileCode(pileCode); tcpSession.addPileCode(pileCode);
// 注册前置会话 // 注册前置会话

View File

@@ -219,7 +219,7 @@ public class LvnengV340RealTimeDataULCmd extends LvnengUplinkCmdExe {
//46 预留 1 //46 预留 1
byteBuf.skipBytes(1); byteBuf.skipBytes(1);
// 会话添加充电桩编码
tcpSession.addPileCode(pileCode); tcpSession.addPileCode(pileCode);
// 注册前置会话 // 注册前置会话

View File

@@ -140,6 +140,12 @@ public class YunKuaiChongV150RealTimeDataULCmd extends YunKuaiChongUplinkCmdExe
.addAllFaultMessages(faults) .addAllFaultMessages(faults)
.setAdditionalInfo(additionalInfo.toString()); .setAdditionalInfo(additionalInfo.toString());
// 会话添加充电桩编码
tcpSession.addPileCode(pileCode);
// 注册前置会话
ctx.getProtocolSessionRegistryProvider().register(tcpSession);
// 转发到后端 // 转发到后端
UplinkQueueMessage gunRunStatusMessage = uplinkMessageBuilder(pileCode, tcpSession, yunKuaiChongUplinkMessage) UplinkQueueMessage gunRunStatusMessage = uplinkMessageBuilder(pileCode, tcpSession, yunKuaiChongUplinkMessage)
.setGunRunStatusProto(gunRunStatusProtoBuilder) .setGunRunStatusProto(gunRunStatusProtoBuilder)

View File

@@ -7,7 +7,7 @@
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import {useNavigate, useParams, useSearchParams} from 'react-router-dom'; import {useNavigate, useParams, useSearchParams} from 'react-router-dom';
import {Alert, Breadcrumb, Button, Card, Descriptions, Divider, message, Space, Spin, Typography} from 'antd'; import {Alert, Breadcrumb, Button, Card, Descriptions, Divider, message, Space, Spin, Typography} from 'antd';
import {ArrowLeftOutlined, BugOutlined, HomeOutlined, PlayCircleOutlined} from '@ant-design/icons'; import {ArrowLeftOutlined, BugOutlined, CopyOutlined, HomeOutlined, PlayCircleOutlined} from '@ant-design/icons';
import {Gun} from '../types'; import {Gun} from '../types';
import * as gunService from '../services/gunService'; import * as gunService from '../services/gunService';
import {api, getErrorMessage} from '../services/api'; import {api, getErrorMessage} from '../services/api';
@@ -91,6 +91,47 @@ const GunDebug: React.FC = () => {
navigate(returnUrl); navigate(returnUrl);
}; };
// 获取完整的请求头信息类似Swagger
const getCompleteHeaders = () => {
const token = localStorage.getItem('token');
const headers: Record<string, string> = {
'Accept': 'application/json;charset=UTF-8',
'Content-Type': 'application/json;charset=UTF-8',
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
return headers;
};
// 生成curl命令类似Swagger UI
const generateCurlCommand = (url: string, method: string, headers: Record<string, string>, requestBody: any) => {
let curlCommand = `curl -X ${method} "${url}"`;
// 添加请求头
Object.entries(headers).forEach(([key, value]) => {
curlCommand += ` \\\n -H "${key}: ${value}"`;
});
// 添加请求体(如果有)
if (requestBody && method !== 'GET') {
curlCommand += ` \\\n -d '${JSON.stringify(requestBody)}'`;
}
return curlCommand;
};
// 复制curl命令到剪贴板
const copyCurlCommand = (curlCommand: string) => {
navigator.clipboard.writeText(curlCommand).then(() => {
message.success('cURL命令已复制到剪贴板');
}).catch(() => {
message.error('复制失败,请手动复制');
});
};
// 执行充电枪状态查询调试 // 执行充电枪状态查询调试
const handleDebugGunStatus = async () => { const handleDebugGunStatus = async () => {
if (!gun) return; if (!gun) return;
@@ -98,16 +139,16 @@ const GunDebug: React.FC = () => {
// 清除充电桩调试结果,只显示充电枪调试结果 // 清除充电桩调试结果,只显示充电枪调试结果
setPileDebugResult(null); setPileDebugResult(null);
setDebugLoading(true); setDebugLoading(true);
try {
const headers = {
'Content-Type': 'application/json',
};
const fullUrl = `${api.defaults.baseURL}/api/guns/status/${gun.gunCode}`;
const headers = getCompleteHeaders();
try {
// 直接调用现有的正确API接口 // 直接调用现有的正确API接口
const response = await api.get(`/api/guns/status/${gun.gunCode}`); const response = await api.get(`/api/guns/status/${gun.gunCode}`);
setDebugResult({ setDebugResult({
url: `/api/guns/status/${gun.gunCode}`, url: fullUrl,
method: 'GET', method: 'GET',
headers, headers,
requestBody: null, requestBody: null,
@@ -123,9 +164,9 @@ const GunDebug: React.FC = () => {
} }
} catch (error: any) { } catch (error: any) {
const errorResult = { const errorResult = {
url: `/api/guns/status/${gun.gunCode}`, url: fullUrl,
method: 'GET', method: 'GET',
headers: {'Content-Type': 'application/json'}, headers,
requestBody: null, requestBody: null,
response: {success: false, message: getErrorMessage(error)}, response: {success: false, message: getErrorMessage(error)},
timestamp: new Date().toLocaleString(), timestamp: new Date().toLocaleString(),
@@ -149,16 +190,16 @@ const GunDebug: React.FC = () => {
// 清除充电枪调试结果,只显示充电桩调试结果 // 清除充电枪调试结果,只显示充电桩调试结果
setDebugResult(null); setDebugResult(null);
setPileDebugLoading(true); setPileDebugLoading(true);
try {
const headers = {
'Content-Type': 'application/json',
};
const fullUrl = `${api.defaults.baseURL}/api/piles/status/${gun.pileCode}`;
const headers = getCompleteHeaders();
try {
// 直接调用现有的正确API接口 // 直接调用现有的正确API接口
const response = await api.get(`/api/piles/status/${gun.pileCode}`); const response = await api.get(`/api/piles/status/${gun.pileCode}`);
setPileDebugResult({ setPileDebugResult({
url: `/api/piles/status/${gun.pileCode}`, url: fullUrl,
method: 'GET', method: 'GET',
headers, headers,
requestBody: null, requestBody: null,
@@ -174,9 +215,9 @@ const GunDebug: React.FC = () => {
} }
} catch (error: any) { } catch (error: any) {
const errorResult = { const errorResult = {
url: `/api/piles/status/${gun.pileCode}`, url: fullUrl,
method: 'GET', method: 'GET',
headers: {'Content-Type': 'application/json'}, headers,
requestBody: null, requestBody: null,
response: {success: false, message: getErrorMessage(error)}, response: {success: false, message: getErrorMessage(error)},
timestamp: new Date().toLocaleString(), timestamp: new Date().toLocaleString(),
@@ -302,6 +343,30 @@ const GunDebug: React.FC = () => {
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Divider orientation="left">
cURL
<Button
type="link"
size="small"
icon={<CopyOutlined/>}
onClick={() => copyCurlCommand(generateCurlCommand(debugResult.url, debugResult.method, debugResult.headers, debugResult.requestBody))}
style={{marginLeft: 8}}
>
</Button>
</Divider>
<pre style={{
background: '#1f1f1f',
color: '#f8f8f2',
padding: 12,
borderRadius: 4,
fontSize: 12,
overflow: 'auto',
fontFamily: 'Monaco, Menlo, "Ubuntu Mono", monospace'
}}>
{generateCurlCommand(debugResult.url, debugResult.method, debugResult.headers, debugResult.requestBody)}
</pre>
<Divider orientation="left"> (Headers)</Divider> <Divider orientation="left"> (Headers)</Divider>
<pre style={{ <pre style={{
background: '#f5f5f5', background: '#f5f5f5',
@@ -321,7 +386,7 @@ const GunDebug: React.FC = () => {
fontSize: 12, fontSize: 12,
overflow: 'auto' overflow: 'auto'
}}> }}>
{JSON.stringify(debugResult.requestBody, null, 2)} {debugResult.requestBody ? JSON.stringify(debugResult.requestBody, null, 2) : 'null'}
</pre> </pre>
<Divider orientation="left"> (Response)</Divider> <Divider orientation="left"> (Response)</Divider>
@@ -361,6 +426,30 @@ const GunDebug: React.FC = () => {
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Divider orientation="left">
cURL
<Button
type="link"
size="small"
icon={<CopyOutlined/>}
onClick={() => copyCurlCommand(generateCurlCommand(pileDebugResult.url, pileDebugResult.method, pileDebugResult.headers, pileDebugResult.requestBody))}
style={{marginLeft: 8}}
>
</Button>
</Divider>
<pre style={{
background: '#1f1f1f',
color: '#f8f8f2',
padding: 12,
borderRadius: 4,
fontSize: 12,
overflow: 'auto',
fontFamily: 'Monaco, Menlo, "Ubuntu Mono", monospace'
}}>
{generateCurlCommand(pileDebugResult.url, pileDebugResult.method, pileDebugResult.headers, pileDebugResult.requestBody)}
</pre>
<Divider orientation="left"> (Headers)</Divider> <Divider orientation="left"> (Headers)</Divider>
<pre style={{ <pre style={{
background: '#f5f5f5', background: '#f5f5f5',
@@ -380,7 +469,7 @@ const GunDebug: React.FC = () => {
fontSize: 12, fontSize: 12,
overflow: 'auto' overflow: 'auto'
}}> }}>
{JSON.stringify(pileDebugResult.requestBody, null, 2)} {pileDebugResult.requestBody ? JSON.stringify(pileDebugResult.requestBody, null, 2) : 'null'}
</pre> </pre>
<Divider orientation="left"> (Response)</Divider> <Divider orientation="left"> (Response)</Divider>

View File

@@ -597,6 +597,13 @@ const GunManagement: React.FC = () => {
updateSearchParams(newParams); updateSearchParams(newParams);
}; };
// 刷新数据
const handleRefresh = () => {
// 使用当前的搜索参数重新加载数据
updateSearchParams({...searchParams});
setSelectedRowKeys([]);
};
// 显示新建模态框 // 显示新建模态框
const showCreateModal = () => { const showCreateModal = () => {
setIsEdit(false); setIsEdit(false);
@@ -942,20 +949,30 @@ const GunManagement: React.FC = () => {
<Card <Card
title="充电枪列表" title="充电枪列表"
extra={ extra={
<Space size="small">
<Button
icon={<ReloadOutlined/>}
type="text"
size="small"
style={{padding: '4px 8px'}}
title="刷新数据"
onClick={handleRefresh}
/>
<Dropdown <Dropdown
menu={columnSelectorMenu} menu={columnSelectorMenu}
placement="bottomRight" placement="bottomRight"
trigger={['click']} trigger={['click']}
overlayStyle={{ minWidth: 180 }} overlayStyle={{minWidth: 180}}
> >
<Button <Button
icon={<TableOutlined />} icon={<TableOutlined/>}
type="text" type="text"
size="small" size="small"
style={{ padding: '4px 8px' }} style={{padding: '4px 8px'}}
title="自定义列" title="自定义列"
/> />
</Dropdown> </Dropdown>
</Space>
} }
> >
<Table <Table

View File

@@ -23,7 +23,7 @@ import {
Tag, Tag,
Typography Typography
} from 'antd'; } from 'antd';
import {DeleteOutlined, PlusOutlined, TableOutlined} from '@ant-design/icons'; import {DeleteOutlined, PlusOutlined, ReloadOutlined, TableOutlined} from '@ant-design/icons';
import type {ColumnsType, TableProps} from 'antd/es/table'; import type {ColumnsType, TableProps} from 'antd/es/table';
import {pileService} from '../services/pileService'; import {pileService} from '../services/pileService';
import * as stationService from '../services/stationService'; import * as stationService from '../services/stationService';
@@ -585,6 +585,13 @@ const PileManagement: React.FC = () => {
setSearchParams(newParams); setSearchParams(newParams);
}; };
// 刷新数据
const handleRefresh = () => {
// 使用当前的搜索参数重新加载数据
setSearchParams({...searchParams});
setSelectedRowKeys([]);
};
// 显示新建Modal // 显示新建Modal
const showCreateModal = async () => { const showCreateModal = async () => {
form.resetFields(); form.resetFields();
@@ -969,20 +976,30 @@ const PileManagement: React.FC = () => {
<Card <Card
title="充电桩列表" title="充电桩列表"
extra={ extra={
<Space size="small">
<Button
icon={<ReloadOutlined/>}
type="text"
size="small"
style={{padding: '4px 8px'}}
title="刷新数据"
onClick={handleRefresh}
/>
<Dropdown <Dropdown
menu={columnSelectorMenu} menu={columnSelectorMenu}
placement="bottomRight" placement="bottomRight"
trigger={['click']} trigger={['click']}
overlayStyle={{ minWidth: 180 }} overlayStyle={{minWidth: 180}}
> >
<Button <Button
icon={<TableOutlined />} icon={<TableOutlined/>}
type="text" type="text"
size="small" size="small"
style={{ padding: '4px 8px' }} style={{padding: '4px 8px'}}
title="自定义列" title="自定义列"
/> />
</Dropdown> </Dropdown>
</Space>
} }
> >
<Table <Table

View File

@@ -505,6 +505,13 @@ const StationManagement: React.FC = () => {
setSearchParams(newParams); setSearchParams(newParams);
}; };
// 刷新数据
const handleRefresh = () => {
// 使用当前的搜索参数重新加载数据
setSearchParams({...searchParams});
setSelectedRowKeys([]);
};
// 显示创建模态框 // 显示创建模态框
const showCreateModal = () => { const showCreateModal = () => {
setIsEdit(false); setIsEdit(false);
@@ -929,20 +936,30 @@ const StationManagement: React.FC = () => {
<Card <Card
title="充电站列表" title="充电站列表"
extra={ extra={
<Space size="small">
<Button
icon={<ReloadOutlined/>}
type="text"
size="small"
style={{padding: '4px 8px'}}
title="刷新数据"
onClick={handleRefresh}
/>
<Dropdown <Dropdown
menu={columnSelectorMenu} menu={columnSelectorMenu}
placement="bottomRight" placement="bottomRight"
trigger={['click']} trigger={['click']}
overlayStyle={{ minWidth: 180 }} overlayStyle={{minWidth: 180}}
> >
<Button <Button
icon={<TableOutlined />} icon={<TableOutlined/>}
type="text" type="text"
size="small" size="small"
style={{ padding: '4px 8px' }} style={{padding: '4px 8px'}}
title="自定义列" title="自定义列"
/> />
</Dropdown> </Dropdown>
</Space>
} }
> >
<Table <Table