SiderBar.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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: '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. items: chatItems,
  87. icon: <IconComment />,
  88. // className: localStorage.getItem('chat_link')
  89. // ? 'semi-navigation-item-normal'
  90. // : 'tableHiddle',
  91. },
  92. {
  93. text: '令牌',
  94. itemKey: 'token',
  95. to: '/token',
  96. icon: <IconKey />,
  97. },
  98. {
  99. text: '兑换码',
  100. itemKey: 'redemption',
  101. to: '/redemption',
  102. icon: <IconGift />,
  103. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  104. },
  105. {
  106. text: '钱包',
  107. itemKey: 'topup',
  108. to: '/topup',
  109. icon: <IconCreditCard />,
  110. },
  111. {
  112. text: '用户管理',
  113. itemKey: 'user',
  114. to: '/user',
  115. icon: <IconUser />,
  116. className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle',
  117. },
  118. {
  119. text: '日志',
  120. itemKey: 'log',
  121. to: '/log',
  122. icon: <IconHistogram />,
  123. },
  124. {
  125. text: '数据看板',
  126. itemKey: 'detail',
  127. to: '/detail',
  128. icon: <IconCalendarClock />,
  129. className:
  130. localStorage.getItem('enable_data_export') === 'true'
  131. ? 'semi-navigation-item-normal'
  132. : 'tableHiddle',
  133. },
  134. {
  135. text: '绘图',
  136. itemKey: 'midjourney',
  137. to: '/midjourney',
  138. icon: <IconImage />,
  139. className:
  140. localStorage.getItem('enable_drawing') === 'true'
  141. ? 'semi-navigation-item-normal'
  142. : 'tableHiddle',
  143. },
  144. {
  145. text: '异步任务',
  146. itemKey: 'task',
  147. to: '/task',
  148. icon: <IconChecklistStroked />,
  149. className:
  150. localStorage.getItem('enable_task') === 'true'
  151. ? 'semi-navigation-item-normal'
  152. : 'tableHiddle',
  153. },
  154. {
  155. text: '设置',
  156. itemKey: 'setting',
  157. to: '/setting',
  158. icon: <IconSetting />,
  159. },
  160. // {
  161. // text: '关于',
  162. // itemKey: 'about',
  163. // to: '/about',
  164. // icon: <IconAt/>
  165. // }
  166. ],
  167. [
  168. localStorage.getItem('enable_data_export'),
  169. localStorage.getItem('enable_drawing'),
  170. localStorage.getItem('enable_task'),
  171. localStorage.getItem('chat_link'), chatItems,
  172. isAdmin(),
  173. ],
  174. );
  175. const loadStatus = async () => {
  176. const res = await API.get('/api/status');
  177. if (res === undefined) {
  178. return;
  179. }
  180. const { success, data } = res.data;
  181. if (success) {
  182. statusDispatch({ type: 'set', payload: data });
  183. setStatusData(data);
  184. } else {
  185. showError('无法正常连接至服务器!');
  186. }
  187. };
  188. useEffect(() => {
  189. loadStatus().then(() => {
  190. setIsCollapsed(
  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. let chatLink = localStorage.getItem('chat_link');
  200. if (!chatLink) {
  201. let chats = localStorage.getItem('chats');
  202. if (chats) {
  203. // console.log(chats);
  204. try {
  205. chats = JSON.parse(chats);
  206. if (Array.isArray(chats)) {
  207. let chatItems = [];
  208. for (let i = 0; i < chats.length; i++) {
  209. let chat = {};
  210. for (let key in chats[i]) {
  211. chat.text = key;
  212. chat.itemKey = 'chat' + i;
  213. chat.to = '/chat/' + i;
  214. }
  215. // setRouterMap({ ...routerMap, chat: '/chat/' + i })
  216. chatItems.push(chat);
  217. }
  218. setChatItems(chatItems);
  219. }
  220. } catch (e) {
  221. console.error(e);
  222. showError('聊天数据解析失败')
  223. }
  224. }
  225. }
  226. }, []);
  227. return (
  228. <>
  229. <Nav
  230. style={{ maxWidth: 220, height: '100%' }}
  231. defaultIsCollapsed={
  232. localStorage.getItem('default_collapse_sidebar') === 'true'
  233. }
  234. isCollapsed={isCollapsed}
  235. onCollapseChange={(collapsed) => {
  236. setIsCollapsed(collapsed);
  237. }}
  238. selectedKeys={selectedKeys}
  239. renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
  240. let chatLink = localStorage.getItem('chat_link');
  241. if (!chatLink) {
  242. let chats = localStorage.getItem('chats');
  243. if (chats) {
  244. chats = JSON.parse(chats);
  245. if (Array.isArray(chats) && chats.length > 0) {
  246. for (let i = 0; i < chats.length; i++) {
  247. routerMap['chat' + i] = '/chat/' + i;
  248. }
  249. if (chats.length > 1) {
  250. // delete /chat
  251. if (routerMap['chat']) {
  252. delete routerMap['chat'];
  253. }
  254. } else {
  255. // rename /chat to /chat/0
  256. routerMap['chat'] = '/chat/0';
  257. }
  258. }
  259. }
  260. }
  261. return (
  262. <Link
  263. style={{ textDecoration: 'none' }}
  264. to={routerMap[props.itemKey]}
  265. >
  266. {itemElement}
  267. </Link>
  268. );
  269. }}
  270. items={headerButtons}
  271. onSelect={(key) => {
  272. if (key.itemKey.toString().startsWith('chat')) {
  273. styleDispatch({ type: 'SET_INNER_PADDING', payload: true });
  274. } else {
  275. styleDispatch({ type: 'SET_INNER_PADDING', payload: false });
  276. }
  277. setSelectedKeys([key.itemKey]);
  278. }}
  279. footer={
  280. <>
  281. </>
  282. }
  283. >
  284. <Nav.Footer collapseButton={true}></Nav.Footer>
  285. </Nav>
  286. </>
  287. );
  288. };
  289. export default SiderBar;