mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-10 11:40:01 +08:00
@@ -376,9 +376,9 @@ const remoteApi = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
queryConsumerGroupList: async (skipSysGroup = false) => {
|
queryConsumerGroupList: async (skipSysGroup, address) => {
|
||||||
try {
|
try {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/groupList.query?skipSysGroup=${skipSysGroup}`));
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/groupList.query?skipSysGroup=${skipSysGroup}&address=${address}`));
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -278,6 +278,12 @@ export const translations = {
|
|||||||
"ENTER_IP_HINT": "请输入 IP 地址,按回车键添加,支持 IPv4、IPv6 和 CIDR",
|
"ENTER_IP_HINT": "请输入 IP 地址,按回车键添加,支持 IPv4、IPv6 和 CIDR",
|
||||||
"PLEASE_ENTER_DECISION": "请输入决策!",
|
"PLEASE_ENTER_DECISION": "请输入决策!",
|
||||||
"MENU": "菜单",
|
"MENU": "菜单",
|
||||||
|
"SELECT_PROXY": "选择代理",
|
||||||
|
"ENABLE_PROXY": "启用代理",
|
||||||
|
"PROXY_DISABLED": "代理禁用",
|
||||||
|
"PROXY_ENABLED": "代理启用",
|
||||||
|
"BROKER_OVERVIEW": "Broker概览",
|
||||||
|
"TOTAL_MSG_RECEIVED_TODAY": "今天接收的总消息数",
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
"DEFAULT": "Default",
|
"DEFAULT": "Default",
|
||||||
@@ -534,6 +540,13 @@ export const translations = {
|
|||||||
"ENTER_IP_HINT": "Please enter IP address, press Enter to add. Supports IPv4, IPv6, and CIDR.",
|
"ENTER_IP_HINT": "Please enter IP address, press Enter to add. Supports IPv4, IPv6, and CIDR.",
|
||||||
"PLEASE_ENTER_DECISION": "Please enter decision!",
|
"PLEASE_ENTER_DECISION": "Please enter decision!",
|
||||||
"MENU": "Menu",
|
"MENU": "Menu",
|
||||||
|
"SELECT_PROXY": "Select Proxy",
|
||||||
|
"ENABLE_PROXY": "Enable Proxy",
|
||||||
|
"PROXY_DISABLED": "Proxy Disabled",
|
||||||
|
"PROXY_ENABLED": "Proxy Enabled",
|
||||||
|
"BROKER_OVERVIEW": "Broker Overview",
|
||||||
|
"TOTAL_MSG_RECEIVED_TODAY": "Total messages received today",
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useCallback, useEffect, useState} from 'react';
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
import {Button, Checkbox, Input, message, notification, Spin, Table} from 'antd';
|
import {Button, Checkbox, Input, message, notification, Select, Spin, Switch, Table} from 'antd';
|
||||||
import {useLanguage} from '../../i18n/LanguageContext';
|
import {useLanguage} from '../../i18n/LanguageContext';
|
||||||
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
import {remoteApi} from '../../api/remoteApi/remoteApi';
|
||||||
import ClientInfoModal from "../../components/consumer/ClientInfoModal";
|
import ClientInfoModal from "../../components/consumer/ClientInfoModal";
|
||||||
@@ -46,6 +46,27 @@ const ConsumerGroupList = () => {
|
|||||||
const [messageApi, msgContextHolder] = message.useMessage();
|
const [messageApi, msgContextHolder] = message.useMessage();
|
||||||
const [notificationApi, notificationContextHolder] = notification.useNotification();
|
const [notificationApi, notificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
|
const [proxyEnabled, setProxyEnabled] = useState(() => {
|
||||||
|
try {
|
||||||
|
const storedValue = localStorage.getItem('proxyEnabled');
|
||||||
|
return storedValue ? JSON.parse(storedValue) : false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to read proxyEnabled from localStorage:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [selectedProxy, setSelectedProxy] = useState(() => {
|
||||||
|
try {
|
||||||
|
const storedValue = localStorage.getItem('selectedProxy');
|
||||||
|
return storedValue || undefined;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to read selectedProxy from localStorage:", error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [proxyOptions ,setProxyOptions]= useState([]);
|
||||||
const [paginationConf, setPaginationConf] = useState({
|
const [paginationConf, setPaginationConf] = useState({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -60,7 +81,12 @@ const ConsumerGroupList = () => {
|
|||||||
const loadConsumerGroups = useCallback(async (currentPage) => {
|
const loadConsumerGroups = useCallback(async (currentPage) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await remoteApi.queryConsumerGroupList(false);
|
var response;
|
||||||
|
if(!proxyEnabled){
|
||||||
|
response = await remoteApi.queryConsumerGroupList(false);
|
||||||
|
}else{
|
||||||
|
response = await remoteApi.queryConsumerGroupList(false, selectedProxy);
|
||||||
|
}
|
||||||
if (response.status === 0) {
|
if (response.status === 0) {
|
||||||
setAllConsumerGroupList(response.data);
|
setAllConsumerGroupList(response.data);
|
||||||
if (currentPage != null) {
|
if (currentPage != null) {
|
||||||
@@ -87,7 +113,6 @@ const ConsumerGroupList = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const filterList = useCallback((currentPage, data) => {
|
const filterList = useCallback((currentPage, data) => {
|
||||||
// 排序处理
|
|
||||||
let sortedData = [...data];
|
let sortedData = [...data];
|
||||||
if (sortConfig.sortKey) {
|
if (sortConfig.sortKey) {
|
||||||
sortedData.sort((a, b) => {
|
sortedData.sort((a, b) => {
|
||||||
@@ -153,6 +178,48 @@ const ConsumerGroupList = () => {
|
|||||||
filterList(paginationConf.current, sortedList);
|
filterList(paginationConf.current, sortedList);
|
||||||
}, [sortConfig, allConsumerGroupList, paginationConf.current]);
|
}, [sortConfig, allConsumerGroupList, paginationConf.current]);
|
||||||
|
|
||||||
|
const fetchProxyList = useCallback(async () => {
|
||||||
|
remoteApi.queryProxyHomePage((resp) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (resp.status === 0) {
|
||||||
|
const {proxyAddrList, currentProxyAddr} = resp.data;
|
||||||
|
const options = proxyAddrList.map(proxyAddress => ({
|
||||||
|
label: proxyAddress,
|
||||||
|
value: proxyAddress,
|
||||||
|
}));
|
||||||
|
setProxyOptions(options || []);
|
||||||
|
setSelectedProxy(prevSelectedProxy => {
|
||||||
|
if (prevSelectedProxy) {
|
||||||
|
return prevSelectedProxy;
|
||||||
|
}
|
||||||
|
if (options.length > 0) {
|
||||||
|
return options[0].value;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notificationApi.error({message: resp.errMsg || t.FETCH_PROXY_LIST_FAILED, duration: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem('proxyEnabled', JSON.stringify(proxyEnabled));
|
||||||
|
}, [proxyEnabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedProxy) {
|
||||||
|
localStorage.setItem('selectedProxy', selectedProxy);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem('selectedProxy');
|
||||||
|
}
|
||||||
|
}, [selectedProxy]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchProxyList();
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadConsumerGroups();
|
loadConsumerGroups();
|
||||||
}, [loadConsumerGroups]);
|
}, [loadConsumerGroups]);
|
||||||
@@ -389,16 +456,18 @@ const ConsumerGroupList = () => {
|
|||||||
<>
|
<>
|
||||||
{msgContextHolder}
|
{msgContextHolder}
|
||||||
{notificationContextHolder}
|
{notificationContextHolder}
|
||||||
<div style={{padding: '20px'}}>
|
<div style={{ padding: '20px' }}>
|
||||||
<Spin spinning={loading} tip={t.LOADING}>
|
<Spin spinning={loading} tip={t.LOADING}>
|
||||||
<div style={{marginBottom: '20px'}}>
|
<div style={{ marginBottom: '20px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<div style={{display: 'flex', alignItems: 'center', gap: '15px'}}>
|
{/* 左侧:筛选和操作按钮 */}
|
||||||
<div style={{display: 'flex', alignItems: 'center'}}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '15px', flexWrap: 'wrap' }}>
|
||||||
<label style={{marginRight: '8px'}}>{t.SUBSCRIPTION_GROUP}:</label>
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<label style={{ marginRight: '8px', whiteSpace: 'nowrap' }}>{t.SUBSCRIPTION_GROUP}:</label>
|
||||||
<Input
|
<Input
|
||||||
style={{width: '200px'}}
|
style={{ width: '200px' }}
|
||||||
value={filterStr}
|
value={filterStr}
|
||||||
onChange={(e) => handleFilterInputChange(e.target.value)}
|
onChange={(e) => handleFilterInputChange(e.target.value)}
|
||||||
|
placeholder="输入订阅组名称"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Checkbox checked={filterNormal}
|
<Checkbox checked={filterNormal}
|
||||||
@@ -423,12 +492,35 @@ const ConsumerGroupList = () => {
|
|||||||
<Button type="primary" onClick={handleRefreshConsumerData}>
|
<Button type="primary" onClick={handleRefreshConsumerData}>
|
||||||
{t.REFRESH}
|
{t.REFRESH}
|
||||||
</Button>
|
</Button>
|
||||||
{/*<Switch*/}
|
</div>
|
||||||
{/* checked={intervalProcessSwitch}*/}
|
|
||||||
{/* onChange={(checked) => setIntervalProcessSwitch(checked)}*/}
|
{/* 右侧:代理选项 */}
|
||||||
{/* checkedChildren={t.AUTO_REFRESH}*/}
|
<div style={{ display: 'flex', alignItems: 'center', gap: '15px' }}>
|
||||||
{/* unCheckedChildren={t.AUTO_REFRESH}*/}
|
<label style={{ marginRight: '8px', whiteSpace: 'nowrap' }}>{t.SELECT_PROXY}:</label>
|
||||||
{/*/>*/}
|
<Select
|
||||||
|
style={{ width: '220px' }}
|
||||||
|
placeholder={t.SELECT_PROXY}
|
||||||
|
onChange={(value) => setSelectedProxy(value)}
|
||||||
|
value={selectedProxy}
|
||||||
|
options={proxyOptions}
|
||||||
|
disabled={!proxyEnabled}
|
||||||
|
allowClear
|
||||||
|
/>
|
||||||
|
<label style={{ marginRight: '8px', whiteSpace: 'nowrap' }}>{t.ENABLE_PROXY}:</label>
|
||||||
|
<Switch
|
||||||
|
checked={proxyEnabled}
|
||||||
|
onChange={(checked) => {
|
||||||
|
setProxyEnabled(checked);
|
||||||
|
if (!checked) {
|
||||||
|
setSelectedProxy(undefined);
|
||||||
|
messageApi.info(t.PROXY_DISABLED);
|
||||||
|
} else {
|
||||||
|
messageApi.info(t.PROXY_ENABLED);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
checkedChildren={t.ENABLED}
|
||||||
|
unCheckedChildren={t.DISABLED}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -443,6 +535,7 @@ const ConsumerGroupList = () => {
|
|||||||
/>
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
|
|
||||||
|
{/* 模态框组件保持不变 */}
|
||||||
<ClientInfoModal
|
<ClientInfoModal
|
||||||
visible={showClientInfo}
|
visible={showClientInfo}
|
||||||
group={selectedGroup}
|
group={selectedGroup}
|
||||||
|
@@ -250,17 +250,18 @@ const DashboardPage = () => {
|
|||||||
const brokerAddrTable = resp.data.clusterInfo.brokerAddrTable; // Corrected to brokerAddrTable
|
const brokerAddrTable = resp.data.clusterInfo.brokerAddrTable; // Corrected to brokerAddrTable
|
||||||
const brokerDetail = resp.data.brokerServer;
|
const brokerDetail = resp.data.brokerServer;
|
||||||
const clusterMap = tools.generateBrokerMap(brokerDetail, clusterAddrTable, brokerAddrTable);
|
const clusterMap = tools.generateBrokerMap(brokerDetail, clusterAddrTable, brokerAddrTable);
|
||||||
|
console.log(brokerAddrTable)
|
||||||
let brokerArray = [];
|
let brokerArray = [];
|
||||||
Object.values(clusterMap).forEach(brokersInCluster => {
|
Object.values(clusterMap).forEach(brokersInCluster => {
|
||||||
brokerArray = brokerArray.concat(brokersInCluster);
|
brokerArray = brokerArray.concat(brokersInCluster);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update broker table data
|
const newData = brokerArray.map(broker => ({
|
||||||
setBrokerTableData(brokerArray.map(broker => ({
|
|
||||||
...broker,
|
...broker,
|
||||||
key: broker.brokerName // Ant Design Table needs a unique key
|
key: broker.brokerName,
|
||||||
})));
|
}));
|
||||||
|
console.log("即将设置的数据:", newData); // 先打印
|
||||||
|
setBrokerTableData(newData); // 再设置状态
|
||||||
|
|
||||||
brokerArray.sort((firstBroker, lastBroker) => {
|
brokerArray.sort((firstBroker, lastBroker) => {
|
||||||
const firstTotalMsg = parseFloat(firstBroker.msgGetTotalTodayNow || 0);
|
const firstTotalMsg = parseFloat(firstBroker.msgGetTotalTodayNow || 0);
|
||||||
@@ -347,7 +348,7 @@ const DashboardPage = () => {
|
|||||||
|
|
||||||
const brokerColumns = [
|
const brokerColumns = [
|
||||||
{title: t.BROKER_NAME, dataIndex: 'brokerName', key: 'brokerName'},
|
{title: t.BROKER_NAME, dataIndex: 'brokerName', key: 'brokerName'},
|
||||||
{title: t.BROKER_ADDR, dataIndex: 'brokerAddress', key: 'brokerAddress'},
|
{title: t.BROKER_ADDR, dataIndex: 'address', key: 'address'},
|
||||||
{
|
{
|
||||||
title: t.TOTAL_MSG_RECEIVED_TODAY,
|
title: t.TOTAL_MSG_RECEIVED_TODAY,
|
||||||
dataIndex: 'msgGetTotalTodayNow',
|
dataIndex: 'msgGetTotalTodayNow',
|
||||||
|
@@ -179,7 +179,6 @@ const DlqMessageQueryPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// console.log("根据Message ID查询DLQ消息:", { msgId: messageId, consumerGroup: selectedConsumerGroup });
|
|
||||||
try {
|
try {
|
||||||
const resp = await remoteApi.viewMessage(messageId, DLQ_GROUP_TOPIC_PREFIX + selectedConsumerGroup);
|
const resp = await remoteApi.viewMessage(messageId, DLQ_GROUP_TOPIC_PREFIX + selectedConsumerGroup);
|
||||||
if (resp.status === 0) {
|
if (resp.status === 0) {
|
||||||
@@ -323,7 +322,6 @@ const DlqMessageQueryPage = () => {
|
|||||||
msgId: message.properties.ORIGIN_MESSAGE_ID,
|
msgId: message.properties.ORIGIN_MESSAGE_ID,
|
||||||
consumerGroup: selectedConsumerGroup,
|
consumerGroup: selectedConsumerGroup,
|
||||||
}));
|
}));
|
||||||
// console.log(`批量重发DLQ消息到 ${selectedConsumerGroup}:`, messagesToResend);
|
|
||||||
try {
|
try {
|
||||||
const resp = await remoteApi.batchResendDlqMessage(messagesToResend);
|
const resp = await remoteApi.batchResendDlqMessage(messagesToResend);
|
||||||
if (resp.status === 0) {
|
if (resp.status === 0) {
|
||||||
@@ -355,7 +353,6 @@ const DlqMessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.BATCH_RESEND_FAILED,
|
description: t.BATCH_RESEND_FAILED,
|
||||||
});
|
});
|
||||||
console.error("批量重发失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
@@ -146,7 +146,6 @@ const MessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.QUERY_FAILED,
|
description: t.QUERY_FAILED,
|
||||||
});
|
});
|
||||||
console.error("查询失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -182,7 +181,6 @@ const MessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.QUERY_FAILED,
|
description: t.QUERY_FAILED,
|
||||||
});
|
});
|
||||||
console.error("查询失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -241,7 +239,6 @@ const MessageQueryPage = () => {
|
|||||||
message: t.ERROR,
|
message: t.ERROR,
|
||||||
description: t.RESEND_FAILED,
|
description: t.RESEND_FAILED,
|
||||||
});
|
});
|
||||||
console.error("重发失败:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
// Optionally, you might want to refresh the message detail after resend
|
// Optionally, you might want to refresh the message detail after resend
|
||||||
@@ -455,7 +452,6 @@ const MessageQueryPage = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
{/* Message ID 查询结果通常直接弹窗显示,这里不需要表格 */}
|
|
||||||
</div>
|
</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
Reference in New Issue
Block a user