LogsTable.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import React, { useEffect, useState } from 'react';
  2. import { Button, Label, Pagination, Select, Table } from 'semantic-ui-react';
  3. import { API, isAdmin, showError, timestamp2string } from '../helpers';
  4. import { ITEMS_PER_PAGE } from '../constants';
  5. function renderTimestamp(timestamp) {
  6. return (
  7. <>
  8. {timestamp2string(timestamp)}
  9. </>
  10. );
  11. }
  12. const MODE_OPTIONS = [
  13. { key: 'all', text: '全部用户', value: 'all' },
  14. { key: 'self', text: '当前用户', value: 'self' },
  15. ];
  16. const LOG_OPTIONS = [
  17. { key: '0', text: '全部', value: 0 },
  18. { key: '1', text: '充值', value: 1 },
  19. { key: '2', text: '消费', value: 2 },
  20. { key: '3', text: '管理', value: 3 },
  21. { key: '4', text: '系统', value: 4 }
  22. ];
  23. function renderType(type) {
  24. switch (type) {
  25. case 1:
  26. return <Label basic color='green'> 充值 </Label>;
  27. case 2:
  28. return <Label basic color='olive'> 消费 </Label>;
  29. case 3:
  30. return <Label basic color='orange'> 管理 </Label>;
  31. case 4:
  32. return <Label basic color='purple'> 系统 </Label>;
  33. default:
  34. return <Label basic color='black'> 未知 </Label>;
  35. }
  36. }
  37. const LogsTable = () => {
  38. const [logs, setLogs] = useState([]);
  39. const [loading, setLoading] = useState(true);
  40. const [activePage, setActivePage] = useState(1);
  41. const [searchKeyword, setSearchKeyword] = useState('');
  42. const [searching, setSearching] = useState(false);
  43. const [logType, setLogType] = useState(0);
  44. const [mode, setMode] = useState('self'); // all, self
  45. const showModePanel = isAdmin();
  46. const loadLogs = async (startIdx) => {
  47. let url = `/api/log/self/?p=${startIdx}&type=${logType}`;
  48. if (mode === 'all') {
  49. url = `/api/log/?p=${startIdx}&type=${logType}`;
  50. }
  51. const res = await API.get(url);
  52. const { success, message, data } = res.data;
  53. if (success) {
  54. if (startIdx === 0) {
  55. setLogs(data);
  56. } else {
  57. let newLogs = logs;
  58. newLogs.push(...data);
  59. setLogs(newLogs);
  60. }
  61. } else {
  62. showError(message);
  63. }
  64. setLoading(false);
  65. };
  66. const onPaginationChange = (e, { activePage }) => {
  67. (async () => {
  68. if (activePage === Math.ceil(logs.length / ITEMS_PER_PAGE) + 1) {
  69. // In this case we have to load more data and then append them.
  70. await loadLogs(activePage - 1);
  71. }
  72. setActivePage(activePage);
  73. })();
  74. };
  75. const refresh = async () => {
  76. setLoading(true);
  77. await loadLogs(0);
  78. };
  79. useEffect(() => {
  80. loadLogs(0)
  81. .then()
  82. .catch((reason) => {
  83. showError(reason);
  84. });
  85. }, []);
  86. useEffect(() => {
  87. refresh().then();
  88. }, [mode, logType]);
  89. const searchLogs = async () => {
  90. if (searchKeyword === '') {
  91. // if keyword is blank, load files instead.
  92. await loadLogs(0);
  93. setActivePage(1);
  94. return;
  95. }
  96. setSearching(true);
  97. const res = await API.get(`/api/log/self/search?keyword=${searchKeyword}`);
  98. const { success, message, data } = res.data;
  99. if (success) {
  100. setLogs(data);
  101. setActivePage(1);
  102. } else {
  103. showError(message);
  104. }
  105. setSearching(false);
  106. };
  107. const handleKeywordChange = async (e, { value }) => {
  108. setSearchKeyword(value.trim());
  109. };
  110. const sortLog = (key) => {
  111. if (logs.length === 0) return;
  112. setLoading(true);
  113. let sortedLogs = [...logs];
  114. sortedLogs.sort((a, b) => {
  115. return ('' + a[key]).localeCompare(b[key]);
  116. });
  117. if (sortedLogs[0].id === logs[0].id) {
  118. sortedLogs.reverse();
  119. }
  120. setLogs(sortedLogs);
  121. setLoading(false);
  122. };
  123. return (
  124. <>
  125. <Table basic>
  126. <Table.Header>
  127. <Table.Row>
  128. <Table.HeaderCell
  129. style={{ cursor: 'pointer' }}
  130. onClick={() => {
  131. sortLog('created_time');
  132. }}
  133. width={3}
  134. >
  135. 时间
  136. </Table.HeaderCell>
  137. {
  138. showModePanel && (
  139. <Table.HeaderCell
  140. style={{ cursor: 'pointer' }}
  141. onClick={() => {
  142. sortLog('user_id');
  143. }}
  144. width={1}
  145. >
  146. 用户
  147. </Table.HeaderCell>
  148. )
  149. }
  150. <Table.HeaderCell
  151. style={{ cursor: 'pointer' }}
  152. onClick={() => {
  153. sortLog('type');
  154. }}
  155. width={2}
  156. >
  157. 类型
  158. </Table.HeaderCell>
  159. <Table.HeaderCell
  160. style={{ cursor: 'pointer' }}
  161. onClick={() => {
  162. sortLog('content');
  163. }}
  164. width={showModePanel ? 10 : 11}
  165. >
  166. 详情
  167. </Table.HeaderCell>
  168. </Table.Row>
  169. </Table.Header>
  170. <Table.Body>
  171. {logs
  172. .slice(
  173. (activePage - 1) * ITEMS_PER_PAGE,
  174. activePage * ITEMS_PER_PAGE
  175. )
  176. .map((log, idx) => {
  177. if (log.deleted) return <></>;
  178. return (
  179. <Table.Row key={log.created_at}>
  180. <Table.Cell>{renderTimestamp(log.created_at)}</Table.Cell>
  181. {
  182. showModePanel && (
  183. <Table.Cell><Label>{log.user_id}</Label></Table.Cell>
  184. )
  185. }
  186. <Table.Cell>{renderType(log.type)}</Table.Cell>
  187. <Table.Cell>{log.content}</Table.Cell>
  188. </Table.Row>
  189. );
  190. })}
  191. </Table.Body>
  192. <Table.Footer>
  193. <Table.Row>
  194. <Table.HeaderCell colSpan={showModePanel ? '5' : '4'}>
  195. {
  196. showModePanel && (
  197. <Select
  198. placeholder='选择模式'
  199. options={MODE_OPTIONS}
  200. style={{ marginRight: '8px' }}
  201. name='mode'
  202. value={mode}
  203. onChange={(e, { name, value }) => {
  204. setMode(value);
  205. }}
  206. />
  207. )
  208. }
  209. <Select
  210. placeholder='选择明细分类'
  211. options={LOG_OPTIONS}
  212. style={{ marginRight: '8px' }}
  213. name='logType'
  214. value={logType}
  215. onChange={(e, { name, value }) => {
  216. setLogType(value);
  217. }}
  218. />
  219. <Button size='small' onClick={refresh} loading={loading}>刷新</Button>
  220. <Pagination
  221. floated='right'
  222. activePage={activePage}
  223. onPageChange={onPaginationChange}
  224. size='small'
  225. siblingRange={1}
  226. totalPages={
  227. Math.ceil(logs.length / ITEMS_PER_PAGE) +
  228. (logs.length % ITEMS_PER_PAGE === 0 ? 1 : 0)
  229. }
  230. />
  231. </Table.HeaderCell>
  232. </Table.Row>
  233. </Table.Footer>
  234. </Table>
  235. </>
  236. );
  237. };
  238. export default LogsTable;