SiderBar.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. import React, { useContext, useEffect, useMemo, useState } from 'react';
  2. import { Link, useNavigate } from 'react-router-dom';
  3. import { UserContext } from '../context/User';
  4. import { StatusContext } from '../context/Status';
  5. import {
  6. API,
  7. getLogo,
  8. getSystemName,
  9. isAdmin,
  10. isMobile,
  11. showError,
  12. } from '../helpers';
  13. import '../index.css';
  14. import {
  15. IconCalendarClock, IconChecklistStroked,
  16. IconComment,
  17. IconCreditCard,
  18. IconGift, IconHelpCircle,
  19. IconHistogram,
  20. IconHome,
  21. IconImage,
  22. IconKey,
  23. IconLayers,
  24. IconPriceTag,
  25. IconSetting,
  26. IconUser
  27. } from '@douyinfe/semi-icons';
  28. import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
  29. import { setStatusData } from '../helpers/data.js';
  30. import { stringToColor } from '../helpers/render.js';
  31. import { useSetTheme, useTheme } from '../context/Theme/index.js';
  32. // HeaderBar Buttons
  33. const SiderBar = () => {
  34. const [userState, userDispatch] = useContext(UserContext);
  35. const [statusState, statusDispatch] = useContext(StatusContext);
  36. const defaultIsCollapsed =
  37. isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true';
  38. let navigate = useNavigate();
  39. const [selectedKeys, setSelectedKeys] = useState(['home']);
  40. const systemName = getSystemName();
  41. const logo = getLogo();
  42. const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
  43. const theme = useTheme();
  44. const setTheme = useSetTheme();
  45. const routerMap = {
  46. home: '/',
  47. channel: '/channel',
  48. token: '/token',
  49. redemption: '/redemption',
  50. topup: '/topup',
  51. user: '/user',
  52. log: '/log',
  53. midjourney: '/midjourney',
  54. setting: '/setting',
  55. about: '/about',
  56. chat: '/chat',
  57. detail: '/detail',
  58. pricing: '/pricing',
  59. task: '/task',
  60. };
  61. const headerButtons = useMemo(
  62. () => [
  63. // {
  64. // text: '首页',
  65. // itemKey: 'home',
  66. // to: '/',
  67. // icon: <IconHome />,
  68. // },
  69. {
  70. text: '模型价格',
  71. itemKey: 'pricing',
  72. to: '/pricing',
  73. icon: <IconPriceTag />,
  74. },
  75. {
  76. text: '渠道',
  77. itemKey: 'channel',
  78. to: '/channel',
  79. icon: <IconLayers />,
  80. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  81. },
  82. {
  83. text: '聊天',
  84. itemKey: 'chat',
  85. to: '/chat',
  86. icon: <IconComment />,
  87. className: localStorage.getItem('chat_link')
  88. ? 'semi-navigation-item-normal'
  89. : 'tableHiddle',
  90. },
  91. {
  92. text: '令牌',
  93. itemKey: 'token',
  94. to: '/token',
  95. icon: <IconKey />,
  96. },
  97. {
  98. text: '兑换码',
  99. itemKey: 'redemption',
  100. to: '/redemption',
  101. icon: <IconGift />,
  102. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  103. },
  104. {
  105. text: '钱包',
  106. itemKey: 'topup',
  107. to: '/topup',
  108. icon: <IconCreditCard />,
  109. },
  110. {
  111. text: '用户管理',
  112. itemKey: 'user',
  113. to: '/user',
  114. icon: <IconUser />,
  115. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  116. },
  117. {
  118. text: '日志',
  119. itemKey: 'log',
  120. to: '/log',
  121. icon: <IconHistogram />,
  122. },
  123. {
  124. text: '数据看板',
  125. itemKey: 'detail',
  126. to: '/detail',
  127. icon: <IconCalendarClock />,
  128. className:
  129. localStorage.getItem('enable_data_export') === 'true'
  130. ? 'semi-navigation-item-normal'
  131. : 'tableHiddle',
  132. },
  133. {
  134. text: '绘图',
  135. itemKey: 'midjourney',
  136. to: '/midjourney',
  137. icon: <IconImage />,
  138. className:
  139. localStorage.getItem('enable_drawing') === 'true'
  140. ? 'semi-navigation-item-normal'
  141. : 'tableHiddle',
  142. },
  143. {
  144. text: '异步任务',
  145. itemKey: 'task',
  146. to: '/task',
  147. icon: <IconChecklistStroked />,
  148. className:
  149. localStorage.getItem('enable_task') === 'true'
  150. ? 'semi-navigation-item-normal'
  151. : 'tableHiddle',
  152. },
  153. {
  154. text: '设置',
  155. itemKey: 'setting',
  156. to: '/setting',
  157. icon: <IconSetting />,
  158. },
  159. // {
  160. // text: '关于',
  161. // itemKey: 'about',
  162. // to: '/about',
  163. // icon: <IconAt/>
  164. // }
  165. ],
  166. [
  167. localStorage.getItem('enable_data_export'),
  168. localStorage.getItem('enable_drawing'),
  169. localStorage.getItem('enable_task'),
  170. localStorage.getItem('chat_link'),
  171. isAdmin(),
  172. ],
  173. );
  174. const loadStatus = async () => {
  175. const res = await API.get('/api/status');
  176. if (res === undefined) {
  177. return;
  178. }
  179. const { success, data } = res.data;
  180. if (success) {
  181. statusDispatch({ type: 'set', payload: data });
  182. setStatusData(data);
  183. } else {
  184. showError('无法正常连接至服务器!');
  185. }
  186. };
  187. useEffect(() => {
  188. loadStatus().then(() => {
  189. setIsCollapsed(
  190. isMobile() ||
  191. localStorage.getItem('default_collapse_sidebar') === 'true',
  192. );
  193. });
  194. let localKey = window.location.pathname.split('/')[1];
  195. if (localKey === '') {
  196. localKey = 'home';
  197. }
  198. setSelectedKeys([localKey]);
  199. }, []);
  200. return (
  201. <>
  202. <Nav
  203. style={{ maxWidth: 220, height: '100%' }}
  204. defaultIsCollapsed={
  205. isMobile() ||
  206. localStorage.getItem('default_collapse_sidebar') === 'true'
  207. }
  208. isCollapsed={isCollapsed}
  209. onCollapseChange={(collapsed) => {
  210. setIsCollapsed(collapsed);
  211. }}
  212. selectedKeys={selectedKeys}
  213. renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
  214. return (
  215. <Link
  216. style={{ textDecoration: 'none' }}
  217. to={routerMap[props.itemKey]}
  218. >
  219. {itemElement}
  220. </Link>
  221. );
  222. }}
  223. items={headerButtons}
  224. onSelect={(key) => {
  225. setSelectedKeys([key.itemKey]);
  226. }}
  227. // header={{
  228. // logo: (
  229. // <img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
  230. // ),
  231. // text: systemName,
  232. // }}
  233. // footer={{
  234. // text: '© 2021 NekoAPI',
  235. // }}
  236. footer={
  237. <>
  238. {isMobile() && (
  239. <Switch
  240. checkedText='🌞'
  241. size={'small'}
  242. checked={theme === 'dark'}
  243. uncheckedText='🌙'
  244. onChange={(checked) => {
  245. setTheme(checked);
  246. }}
  247. />
  248. )}
  249. </>
  250. }
  251. >
  252. <Nav.Footer collapseButton={true}></Nav.Footer>
  253. </Nav>
  254. </>
  255. );
  256. };
  257. export default SiderBar;