SiderBar.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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, IconCommentStroked,
  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. import { StyleContext } from '../context/Style/index.js';
  33. // HeaderBar Buttons
  34. const SiderBar = () => {
  35. const [styleState, styleDispatch] = useContext(StyleContext);
  36. const [statusState, statusDispatch] = useContext(StatusContext);
  37. const defaultIsCollapsed =
  38. localStorage.getItem('default_collapse_sidebar') === 'true';
  39. const [selectedKeys, setSelectedKeys] = useState(['home']);
  40. const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
  41. const [chatItems, setChatItems] = useState([]);
  42. const theme = useTheme();
  43. const setTheme = useSetTheme();
  44. const routerMap = {
  45. home: '/',
  46. channel: '/channel',
  47. token: '/token',
  48. redemption: '/redemption',
  49. topup: '/topup',
  50. user: '/user',
  51. log: '/log',
  52. midjourney: '/midjourney',
  53. setting: '/setting',
  54. about: '/about',
  55. chat: '/chat',
  56. detail: '/detail',
  57. pricing: '/pricing',
  58. task: '/task',
  59. playground: '/playground',
  60. };
  61. const headerButtons = useMemo(
  62. () => [
  63. {
  64. text: 'Playground',
  65. itemKey: 'playground',
  66. to: '/playground',
  67. icon: <IconCommentStroked />,
  68. },
  69. {
  70. text: '渠道',
  71. itemKey: 'channel',
  72. to: '/channel',
  73. icon: <IconLayers />,
  74. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  75. },
  76. {
  77. text: '聊天',
  78. itemKey: 'chat',
  79. // to: '/chat',
  80. items: chatItems,
  81. icon: <IconComment />,
  82. // className: localStorage.getItem('chat_link')
  83. // ? 'semi-navigation-item-normal'
  84. // : 'tableHiddle',
  85. },
  86. {
  87. text: '令牌',
  88. itemKey: 'token',
  89. to: '/token',
  90. icon: <IconKey />,
  91. },
  92. {
  93. text: '数据看板',
  94. itemKey: 'detail',
  95. to: '/detail',
  96. icon: <IconCalendarClock />,
  97. className:
  98. localStorage.getItem('enable_data_export') === 'true'
  99. ? 'semi-navigation-item-normal'
  100. : 'tableHiddle',
  101. },
  102. {
  103. text: '兑换码',
  104. itemKey: 'redemption',
  105. to: '/redemption',
  106. icon: <IconGift />,
  107. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  108. },
  109. {
  110. text: '钱包',
  111. itemKey: 'topup',
  112. to: '/topup',
  113. icon: <IconCreditCard />,
  114. },
  115. {
  116. text: '用户管理',
  117. itemKey: 'user',
  118. to: '/user',
  119. icon: <IconUser />,
  120. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  121. },
  122. {
  123. text: '日志',
  124. itemKey: 'log',
  125. to: '/log',
  126. icon: <IconHistogram />,
  127. },
  128. {
  129. text: '绘图',
  130. itemKey: 'midjourney',
  131. to: '/midjourney',
  132. icon: <IconImage />,
  133. className:
  134. localStorage.getItem('enable_drawing') === 'true'
  135. ? 'semi-navigation-item-normal'
  136. : 'tableHiddle',
  137. },
  138. {
  139. text: '异步任务',
  140. itemKey: 'task',
  141. to: '/task',
  142. icon: <IconChecklistStroked />,
  143. className:
  144. localStorage.getItem('enable_task') === 'true'
  145. ? 'semi-navigation-item-normal'
  146. : 'tableHiddle',
  147. },
  148. {
  149. text: '设置',
  150. itemKey: 'setting',
  151. to: '/setting',
  152. icon: <IconSetting />,
  153. },
  154. // {
  155. // text: '关于',
  156. // itemKey: 'about',
  157. // to: '/about',
  158. // icon: <IconAt/>
  159. // }
  160. ],
  161. [
  162. localStorage.getItem('enable_data_export'),
  163. localStorage.getItem('enable_drawing'),
  164. localStorage.getItem('enable_task'),
  165. localStorage.getItem('chat_link'), chatItems,
  166. isAdmin(),
  167. ],
  168. );
  169. const loadStatus = async () => {
  170. const res = await API.get('/api/status');
  171. if (res === undefined) {
  172. return;
  173. }
  174. const { success, data } = res.data;
  175. if (success) {
  176. statusDispatch({ type: 'set', payload: data });
  177. setStatusData(data);
  178. } else {
  179. showError('无法正常连接至服务器!');
  180. }
  181. };
  182. useEffect(() => {
  183. loadStatus().then(() => {
  184. setIsCollapsed(
  185. localStorage.getItem('default_collapse_sidebar') === 'true',
  186. );
  187. });
  188. let localKey = window.location.pathname.split('/')[1];
  189. if (localKey === '') {
  190. localKey = 'home';
  191. }
  192. setSelectedKeys([localKey]);
  193. let chatLink = localStorage.getItem('chat_link');
  194. if (!chatLink) {
  195. let chats = localStorage.getItem('chats');
  196. if (chats) {
  197. // console.log(chats);
  198. try {
  199. chats = JSON.parse(chats);
  200. if (Array.isArray(chats)) {
  201. let chatItems = [];
  202. for (let i = 0; i < chats.length; i++) {
  203. let chat = {};
  204. for (let key in chats[i]) {
  205. chat.text = key;
  206. chat.itemKey = 'chat' + i;
  207. chat.to = '/chat/' + i;
  208. }
  209. // setRouterMap({ ...routerMap, chat: '/chat/' + i })
  210. chatItems.push(chat);
  211. }
  212. setChatItems(chatItems);
  213. }
  214. } catch (e) {
  215. console.error(e);
  216. showError('聊天数据解析失败')
  217. }
  218. }
  219. }
  220. }, []);
  221. return (
  222. <>
  223. <Nav
  224. style={{ maxWidth: 220, height: '100%' }}
  225. defaultIsCollapsed={
  226. localStorage.getItem('default_collapse_sidebar') === 'true'
  227. }
  228. isCollapsed={isCollapsed}
  229. onCollapseChange={(collapsed) => {
  230. setIsCollapsed(collapsed);
  231. }}
  232. selectedKeys={selectedKeys}
  233. renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
  234. let chatLink = localStorage.getItem('chat_link');
  235. if (!chatLink) {
  236. let chats = localStorage.getItem('chats');
  237. if (chats) {
  238. chats = JSON.parse(chats);
  239. if (Array.isArray(chats) && chats.length > 0) {
  240. for (let i = 0; i < chats.length; i++) {
  241. routerMap['chat' + i] = '/chat/' + i;
  242. }
  243. if (chats.length > 1) {
  244. // delete /chat
  245. if (routerMap['chat']) {
  246. delete routerMap['chat'];
  247. }
  248. } else {
  249. // rename /chat to /chat/0
  250. routerMap['chat'] = '/chat/0';
  251. }
  252. }
  253. }
  254. }
  255. return (
  256. <Link
  257. style={{ textDecoration: 'none' }}
  258. to={routerMap[props.itemKey]}
  259. >
  260. {itemElement}
  261. </Link>
  262. );
  263. }}
  264. items={headerButtons}
  265. onSelect={(key) => {
  266. if (key.itemKey.toString().startsWith('chat')) {
  267. styleDispatch({ type: 'SET_INNER_PADDING', payload: true });
  268. } else {
  269. styleDispatch({ type: 'SET_INNER_PADDING', payload: false });
  270. }
  271. setSelectedKeys([key.itemKey]);
  272. }}
  273. footer={
  274. <>
  275. </>
  276. }
  277. >
  278. <Nav.Footer collapseButton={true}></Nav.Footer>
  279. </Nav>
  280. </>
  281. );
  282. };
  283. export default SiderBar;