UptimePanel.jsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /*
  2. Copyright (C) 2025 QuantumNous
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. For commercial licensing, please contact support@quantumnous.com
  14. */
  15. import React from 'react';
  16. import { Card, Button, Spin, Tabs, TabPane, Tag, Empty } from '@douyinfe/semi-ui';
  17. import { Gauge, RefreshCw } from 'lucide-react';
  18. import { IllustrationConstruction, IllustrationConstructionDark } from '@douyinfe/semi-illustrations';
  19. import ScrollableContainer from '../common/ui/ScrollableContainer';
  20. const UptimePanel = ({
  21. uptimeData,
  22. uptimeLoading,
  23. activeUptimeTab,
  24. setActiveUptimeTab,
  25. loadUptimeData,
  26. uptimeLegendData,
  27. renderMonitorList,
  28. CARD_PROPS,
  29. ILLUSTRATION_SIZE,
  30. t
  31. }) => {
  32. return (
  33. <Card
  34. {...CARD_PROPS}
  35. className="shadow-sm !rounded-2xl lg:col-span-1"
  36. title={
  37. <div className="flex items-center justify-between w-full gap-2">
  38. <div className="flex items-center gap-2">
  39. <Gauge size={16} />
  40. {t('服务可用性')}
  41. </div>
  42. <Button
  43. icon={<RefreshCw size={14} />}
  44. onClick={loadUptimeData}
  45. loading={uptimeLoading}
  46. size="small"
  47. theme="borderless"
  48. type='tertiary'
  49. className="text-gray-500 hover:text-blue-500 hover:bg-blue-50 !rounded-full"
  50. />
  51. </div>
  52. }
  53. bodyStyle={{ padding: 0 }}
  54. >
  55. {/* 内容区域 */}
  56. <div className="relative">
  57. <Spin spinning={uptimeLoading}>
  58. {uptimeData.length > 0 ? (
  59. uptimeData.length === 1 ? (
  60. <ScrollableContainer maxHeight="24rem">
  61. {renderMonitorList(uptimeData[0].monitors)}
  62. </ScrollableContainer>
  63. ) : (
  64. <Tabs
  65. type="card"
  66. collapsible
  67. activeKey={activeUptimeTab}
  68. onChange={setActiveUptimeTab}
  69. size="small"
  70. >
  71. {uptimeData.map((group, groupIdx) => (
  72. <TabPane
  73. tab={
  74. <span className="flex items-center gap-2">
  75. <Gauge size={14} />
  76. {group.categoryName}
  77. <Tag
  78. color={activeUptimeTab === group.categoryName ? 'red' : 'grey'}
  79. size='small'
  80. shape='circle'
  81. >
  82. {group.monitors ? group.monitors.length : 0}
  83. </Tag>
  84. </span>
  85. }
  86. itemKey={group.categoryName}
  87. key={groupIdx}
  88. >
  89. <ScrollableContainer maxHeight="21.5rem">
  90. {renderMonitorList(group.monitors)}
  91. </ScrollableContainer>
  92. </TabPane>
  93. ))}
  94. </Tabs>
  95. )
  96. ) : (
  97. <div className="flex justify-center items-center py-8">
  98. <Empty
  99. image={<IllustrationConstruction style={ILLUSTRATION_SIZE} />}
  100. darkModeImage={<IllustrationConstructionDark style={ILLUSTRATION_SIZE} />}
  101. title={t('暂无监控数据')}
  102. description={t('请联系管理员在系统设置中配置Uptime')}
  103. />
  104. </div>
  105. )}
  106. </Spin>
  107. </div>
  108. {/* 图例 */}
  109. {uptimeData.length > 0 && (
  110. <div className="p-3 bg-gray-50 rounded-b-2xl">
  111. <div className="flex flex-wrap gap-3 text-xs justify-center">
  112. {uptimeLegendData.map((legend, index) => (
  113. <div key={index} className="flex items-center gap-1">
  114. <div
  115. className="w-2 h-2 rounded-full"
  116. style={{ backgroundColor: legend.color }}
  117. />
  118. <span className="text-gray-600">{legend.label}</span>
  119. </div>
  120. ))}
  121. </div>
  122. </div>
  123. )}
  124. </Card>
  125. );
  126. };
  127. export default UptimePanel;