wnm168 commited on
Commit
c8bbbf0
·
verified ·
1 Parent(s): dbd6207

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +935 -18
index.html CHANGED
@@ -1,19 +1,936 @@
1
- <!doctype html>
 
2
  <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
3
  <html>
4
+
5
+ <head>
6
+ <meta charset="UTF-8" />
7
+ <title>Task</title>
8
+ <link rel="stylesheet" type="text/css" href="https://www.unpkg.com/[email protected]/dist/css/bootstrap.min.css" />
9
+ <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet" />
10
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/css/fonts.min.css" rel="stylesheet" />
11
+ </head>
12
+
13
+ <body>
14
+ <div id="root"></div>
15
+ <a id="back-to-top" href="#" class="btn btn-success btn-lg back-to-top" role="button"><i
16
+ class="mdi mdi-arrow-up"></i></a>
17
+ <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
18
+ <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
19
+ <script src="https://www.unpkg.com/[email protected]/dist/jquery.min.js"></script>
20
+ <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>
21
+ <script src="https://www.unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
22
+ <script src="https://unpkg.com/[email protected]/dist/react-bootstrap.min.js"></script>
23
+ <script src="https://unpkg.com/[email protected]/dist/redux.min.js"></script>
24
+ <script src="https://unpkg.com/[email protected]/umd/react-router-dom.min.js"></script>
25
+ <script src="https://unpkg.com/[email protected]/babel.min.js"></script>
26
+ <script src="https://unpkg.com/[email protected]/runtime.js"></script>
27
+ <script src="https://cdn.bootcdn.net/ajax/libs/babel-polyfill/7.12.1/polyfill.min.js"></script>
28
+ <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.7.2/axios.min.js"></script>
29
+ <script src="layer/layer.js"></script>
30
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mitt.umd.min.js"></script>
31
+
32
+ <style>
33
+ .bi {
34
+ display: inline-block;
35
+ width: 1rem;
36
+ height: 1rem;
37
+ }
38
+
39
+ /*
40
+ * Sidebar
41
+ */
42
+ @media (min-width: 768px) {
43
+ .sidebar {
44
+ width: 100%;
45
+ }
46
+
47
+ .sidebar .offcanvas-lg {
48
+ position: -webkit-sticky;
49
+ position: sticky;
50
+ top: 48px;
51
+ }
52
+
53
+ .navbar-search {
54
+ display: block;
55
+ }
56
+ }
57
+
58
+ .sidebar .nav-link {
59
+ font-size: 0.875rem;
60
+ font-weight: 500;
61
+ }
62
+
63
+ .sidebar .nav-link.active {
64
+ color: #2470dc;
65
+ }
66
+
67
+ .sidebar-heading {
68
+ font-size: 0.75rem;
69
+ }
70
+
71
+ /*
72
+ * Navbar
73
+ */
74
+ .navbar {
75
+ background-color: teal;
76
+ }
77
+
78
+ .navbar-brand {
79
+ padding-top: 0.75rem;
80
+ padding-bottom: 0.75rem;
81
+ /* background-color: rgba(0, 0, 0, .25);
82
+ box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); */
83
+ }
84
+
85
+ .navbar .form-control {
86
+ padding: 0.75rem 1rem;
87
+ }
88
+
89
+ .bd-placeholder-img {
90
+ font-size: 1.125rem;
91
+ text-anchor: middle;
92
+ -webkit-user-select: none;
93
+ -moz-user-select: none;
94
+ user-select: none;
95
+ }
96
+
97
+ @media (min-width: 768px) {
98
+ .bd-placeholder-img-lg {
99
+ font-size: 3.5rem;
100
+ }
101
+ }
102
+
103
+ .b-example-divider {
104
+ width: 100%;
105
+ height: 3rem;
106
+ background-color: rgba(0, 0, 0, 0.1);
107
+ border: solid rgba(0, 0, 0, 0.15);
108
+ border-width: 1px 0;
109
+ box-shadow: inset 0 0.5em 1.5em rgba(0, 0, 0, 0.1),
110
+ inset 0 0.125em 0.5em rgba(0, 0, 0, 0.15);
111
+ }
112
+
113
+ .b-example-vr {
114
+ flex-shrink: 0;
115
+ width: 1.5rem;
116
+ height: 100vh;
117
+ }
118
+
119
+ .bi {
120
+ vertical-align: -0.125em;
121
+ fill: currentColor;
122
+ }
123
+
124
+ .nav-scroller {
125
+ position: relative;
126
+ z-index: 2;
127
+ height: 2.75rem;
128
+ overflow-y: hidden;
129
+ }
130
+
131
+ .nav-scroller .nav {
132
+ display: flex;
133
+ flex-wrap: nowrap;
134
+ padding-bottom: 1rem;
135
+ margin-top: -1px;
136
+ overflow-x: auto;
137
+ text-align: center;
138
+ white-space: nowrap;
139
+ -webkit-overflow-scrolling: touch;
140
+ }
141
+
142
+ .btn-bd-primary {
143
+ --bd-violet-bg: #712cf9;
144
+ --bd-violet-rgb: 112.520718, 44.062154, 249.437846;
145
+
146
+ --bs-btn-font-weight: 600;
147
+ --bs-btn-color: var(--bs-white);
148
+ --bs-btn-bg: var(--bd-violet-bg);
149
+ --bs-btn-border-color: var(--bd-violet-bg);
150
+ --bs-btn-hover-color: var(--bs-white);
151
+ --bs-btn-hover-bg: #6528e0;
152
+ --bs-btn-hover-border-color: #6528e0;
153
+ --bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
154
+ --bs-btn-active-color: var(--bs-btn-hover-color);
155
+ --bs-btn-active-bg: #5a23c8;
156
+ --bs-btn-active-border-color: #5a23c8;
157
+ }
158
+
159
+ .bd-mode-toggle {
160
+ z-index: 1500;
161
+ }
162
+
163
+ .bd-mode-toggle .dropdown-menu .active .bi {
164
+ display: block !important;
165
+ }
166
+
167
+ .back-to-top {
168
+ position: fixed;
169
+ bottom: 25px;
170
+ right: 25px;
171
+ display: none;
172
+ }
173
+
174
+ .leftsidebar {
175
+ height: 100%;
176
+ box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1);
177
+ }
178
+
179
+ @media (min-width: 768px) {
180
+ .leftsidebar {
181
+ min-width: 15%;
182
+ }
183
+ }
184
+
185
+ @media (max-width: 768px) {
186
+ .leftsidebar {
187
+ max-width: 50%;
188
+ }
189
+ }
190
+
191
+ .bg-teal {
192
+ background-color: teal;
193
+ }
194
+ </style>
195
+
196
+ <script type="text/babel" data-presets="react" data-type="module">
197
+ //事件监听开始 通过修改localstorage实现跨页面事件监听
198
+ const emitter = mitt();
199
+ // 监听 localStorage 变化
200
+ window.addEventListener("storage", (event) => {
201
+ if (event.key === "event") {
202
+ const { type, data } = JSON.parse(event.newValue);
203
+ emitter.emit(type, data);
204
+ }
205
+ });
206
+ // 封装 emit 方法
207
+ const emitEvent = (type, data) => {
208
+ // 触发本地事件
209
+ emitter.emit(type, data);
210
+ const randomString = Math.random()
211
+ .toString(36)
212
+ .substring(2, 10); // 生成一个随机字符串确保event每次的值不一样,如果一样会不触发事件
213
+ const identity = `${Date.now()}-${randomString}`;
214
+ // 存储到 localStorage,以便其他页面能够接收到
215
+ localStorage.setItem(
216
+ "event",
217
+ JSON.stringify({ type, data, identity })
218
+ );
219
+ };
220
+
221
+ // 封装 on 方法
222
+ const onEvent = (type, callback) => {
223
+ emitter.on(type, callback);
224
+ };
225
+
226
+ // 封装 off 方法
227
+ const offEvent = (type, callback) => {
228
+ emitter.off(type, callback);
229
+ };
230
+ //事件监听结束
231
+
232
+
233
+ const { createStore, combineReducers } = Redux;
234
+ // 从 localStorage 加载初始状态
235
+ const loadStateFromLocalStorage = () => {
236
+ try {
237
+ const serializedState = localStorage.getItem('settings');
238
+ if (serializedState === null) {
239
+ return {}; // 默认值
240
+ }
241
+ return JSON.parse(serializedState);
242
+ } catch (e) {
243
+ console.error("Could not load state from localStorage:", e);
244
+ return {}; // 默认值
245
+ }
246
+ };
247
+ // 保存状态到 localStorage
248
+ const saveStateToLocalStorage = (state) => {
249
+ try {
250
+ const serializedState = JSON.stringify(state);
251
+ localStorage.setItem('settings', serializedState);
252
+ } catch (e) {
253
+ console.error("Could not save state to localStorage:", e);
254
+ }
255
+ };
256
+
257
+ // 定义初始状态
258
+ const initialSettingsState = loadStateFromLocalStorage();
259
+
260
+ // 创建 settings Reducer
261
+ function settingsReducer(state = initialSettingsState, action) {
262
+ switch (action.type) {
263
+ case 'SAVE_SETTING':
264
+ return { ...state, ...action.payload };
265
+ default:
266
+ return state;
267
+ }
268
+ }
269
+
270
+ // 合并 Reducer(如果有多个)
271
+ const rootReducer = combineReducers({
272
+ settings: settingsReducer,
273
+ });
274
+
275
+ // 创建 Redux Store
276
+ const STORE = createStore(rootReducer);
277
+
278
+ // 订阅 Store 的变化,并将状态保存到 localStorage
279
+ STORE.subscribe(() => {
280
+ saveStateToLocalStorage(STORE.getState().settings);
281
+ });
282
+
283
+
284
+ const bytesToSize = (bytes) => {
285
+ if (bytes === 0) return '0 B';
286
+ var k = 1024;
287
+ sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
288
+ i = Math.floor(Math.log(bytes) / Math.log(k));
289
+ return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];
290
+ };
291
+ const formatDate = (date) => {
292
+ var d = new Date(date);
293
+ var year = d.getFullYear();
294
+ var month = d.getMonth() + 1;
295
+ var day = d.getDate() < 10 ? '0' + d.getDate() : '' + d.getDate();
296
+ var hour = d.getHours();
297
+ var minutes = d.getMinutes();
298
+ var seconds = d.getSeconds();
299
+ return year + '-' + month + '-' + day + ' ' + hour + ':' + minutes + ':' + seconds;
300
+ };
301
+
302
+
303
+ const { useState, useEffect, useRef } = React;
304
+ const { HashRouter, Route, Link, Switch, useLocation, useParams } =
305
+ ReactRouterDOM;
306
+ const {
307
+ Alert,
308
+ Badge,
309
+ Button,
310
+ ButtonGroup,
311
+ ButtonToolbar,
312
+ Collapse,
313
+ Col,
314
+ Container,
315
+ Form,
316
+ Image,
317
+ InputGroup,
318
+ ListGroup,
319
+ Modal,
320
+ Nav,
321
+ Navbar,
322
+ NavDropdown,
323
+ Offcanvas,
324
+ Pagination,
325
+ Row,
326
+ Table,
327
+ } = ReactBootstrap;
328
+ //注意修改js文件后需要直接访问js以更新浏览器缓存
329
+
330
+ // 表格组件
331
+ const DataTable = ({ data, columns }) => {
332
+ return (
333
+ <Table responsive bordered>
334
+ <thead>
335
+ <tr className="text-center">
336
+ {columns.map((column, index) => (
337
+ <th key={index}>{column.title}</th>
338
+ ))}
339
+ </tr>
340
+ </thead>
341
+ <tbody>
342
+ {data.map((row, rowIndex) => (
343
+ <tr key={rowIndex} className="text-center">
344
+ {columns.map((column, colIndex) => (
345
+ <td key={colIndex}>
346
+ {/* 调用渲染方法,如果没有定义,则直接显示数据 */}
347
+ {column.render
348
+ ? column.render(row)
349
+ : row[column.dataIndex]}
350
+ </td>
351
+ ))}
352
+ </tr>
353
+ ))}
354
+ </tbody>
355
+ </Table>
356
+ );
357
+ };
358
+ //分页组件
359
+ const Paginate = (props) => {
360
+ const page = props.page;
361
+ const pageCount = Math.ceil(
362
+ props.totalCount / props.itemsPerPage
363
+ );
364
+
365
+ const SelectItems = () => {
366
+ const pageNumbers = Array.from(
367
+ { length: pageCount },
368
+ (_, i) => i + 1
369
+ );
370
+ return (
371
+ <select
372
+ className="form-select me-2"
373
+ style={{ width: "auto" }}
374
+ onChange={(e) => {
375
+ props.onClick(parseInt(e.target.value));
376
+ }}
377
+ >
378
+ {pageNumbers.map((number) => {
379
+ const selected = number === page ? true : false;
380
+ return (
381
+ <option
382
+ key={number}
383
+ value={number}
384
+ selected={selected}
385
+ >
386
+ {number}
387
+ </option>
388
+ );
389
+ })}
390
+ </select>
391
+ );
392
+ };
393
+ return (
394
+ <div className="d-flex justify-content-center align-items-baseline">
395
+ <SelectItems />
396
+ <span className="text-info me-2">
397
+ {page}/{pageCount}
398
+ </span>
399
+ <Pagination>
400
+ {pageCount > 1 && page > 1 && (
401
+ <Pagination.First
402
+ onClick={() => {
403
+ props.onClick(1);
404
+ }}
405
+ />
406
+ )}
407
+ {pageCount > 1 && page > 1 && (
408
+ <Pagination.Prev
409
+ onClick={() => {
410
+ props.onClick(page - 1);
411
+ }}
412
+ />
413
+ )}
414
+ {pageCount > 1 && page < pageCount && (
415
+ <Pagination.Next
416
+ onClick={() => {
417
+ props.onClick(page + 1);
418
+ }}
419
+ />
420
+ )}
421
+ {pageCount > 1 && page < pageCount && (
422
+ <Pagination.Last
423
+ onClick={() => {
424
+ props.onClick(pageCount);
425
+ }}
426
+ />
427
+ )}
428
+ </Pagination>
429
+ </div>
430
+ );
431
+ };
432
+ //图标组件
433
+ const Icon = (props) => {
434
+ return (
435
+ <span
436
+ onClick={props.onClick}
437
+ className={`mdi mdi-${props.icon} fs-${props.size} ${props.className}`}
438
+ ></span>
439
+ );
440
+ };
441
+ //按钮图标组件
442
+ const IconButton = (props) => {
443
+ return (
444
+ <Button
445
+ variant="success"
446
+ onClick={props.onClick}
447
+ className={props.className}
448
+ >
449
+ <span
450
+ className={`mdi mdi-${props.icon} fs-${props.iconSize} ${props.iconClassName}`}
451
+ ></span>
452
+ {props.text}
453
+ </Button>
454
+ );
455
+ };
456
+ //设置框
457
+ const SettingModal = (props) => {
458
+ const settings = [
459
+ { "alist": [{ "label": "Alist地址", "key": "alist_host", "show": true }, { "label": "Alist令牌", "key": "alist_token", "show": false }] },
460
+ { "github": [{ "label": "Actions地址", "key": "github_host", "show": true }, { "label": "Github令牌", "key": "github_token", "show": false }] }
461
+ ]
462
+ const [setting, setSetting] = useState({});
463
+ // useEffect(() => {
464
+ // localStorage.setItem('settings', JSON.stringify(setting));
465
+ // }, [setting]);
466
+
467
+ const loadSetting = () => {
468
+ const storedSettings = STORE.getState().settings;
469
+ if (storedSettings) {
470
+ setSetting(storedSettings);
471
+ }
472
+ }
473
+ const saveSetting = () => {
474
+ STORE.dispatch({ type: 'SAVE_SETTING', payload: setting })
475
+ //localStorage.setItem('settings', JSON.stringify(setting));
476
+ }
477
+ return (
478
+ <Modal show={props.show} onHide={props.onHide} onShow={loadSetting}>
479
+ <Modal.Header closeButton onHide={props.onHide}>
480
+ <Modal.Title>设置</Modal.Title>
481
+ </Modal.Header>
482
+ <Modal.Body>
483
+ <Form>
484
+ <ListGroup>
485
+ {settings.map((value, index) => {
486
+ const key = Object.keys(value)[0];
487
+ const items = value[key];
488
+ return (<ListGroup.Item>
489
+ {items.map((setting_item) => {
490
+ return (
491
+ <Form.Group as={Row} className="mb-3">
492
+ <Form.Label column sm="3">
493
+ {setting_item.label}
494
+ </Form.Label>
495
+ <Col sm="9">
496
+ <Form.Control type={setting_item.show ? "input" : "password"} value={setting[setting_item.key]} name={setting_item.key} placeholder={setting_item.label} onChange={(e) => { setSetting({ ...setting, [setting_item.key]: e.target.value }) }} />
497
+ </Col>
498
+ </Form.Group>
499
+ )
500
+ })}
501
+ </ListGroup.Item>)
502
+ })}
503
+ </ListGroup>
504
+ </Form>
505
+ </Modal.Body>
506
+ <Modal.Footer className="justify-content-between">
507
+ <Button
508
+ variant="secondary"
509
+ onClick={() => {
510
+ props.onHide();
511
+ }}
512
+ >
513
+ 关闭
514
+ </Button>
515
+ <Button
516
+ variant="primary"
517
+ onClick={() => {
518
+ saveSetting();
519
+ props.onHide();
520
+ //props.onSave();
521
+ }}
522
+ >
523
+ 保存
524
+ </Button>
525
+ </Modal.Footer>
526
+ </Modal>
527
+ );
528
+ };
529
+
530
+ //axios封装开始
531
+ const useAxios = () => {
532
+ const [response, setResponse] = useState(null);
533
+ const [error, setError] = useState("");
534
+ const [loading, setLoading] = useState(false);
535
+
536
+ // Create an Axios instance
537
+ const axiosInstance = axios.create({});
538
+
539
+ // Set up request and response interceptors
540
+ axiosInstance.interceptors.request.use(
541
+ (config) => {
542
+ // Log or modify request here
543
+ //console.log("Sending request to:", config.url);
544
+ return config;
545
+ },
546
+ (error) => {
547
+ // Handle request error here
548
+ return Promise.reject(error);
549
+ }
550
+ );
551
+
552
+ axiosInstance.interceptors.response.use(
553
+ (response) => {
554
+ // Log or modify response here
555
+ //console.log("Received response from:", response.config.url);
556
+ return response;
557
+ },
558
+ (error) => {
559
+ // Handle response error here
560
+ return Promise.reject(error);
561
+ }
562
+ );
563
+
564
+ useEffect(() => {
565
+ const source = axios.CancelToken.source();
566
+ return () => {
567
+ // Cancel the request when the component unmounts
568
+ source.cancel(
569
+ "组件被卸载: 请求取消."
570
+ );
571
+ };
572
+ }, []);
573
+
574
+ // Making the API call with cancellation support
575
+ const fetchData = async ({ url, method, data, headers }) => {
576
+ setLoading(true);
577
+ try {
578
+ const result = await axiosInstance({
579
+ url,
580
+ method,
581
+ headers: headers ? headers : {},
582
+ data:
583
+ method.toLowerCase() === "get"
584
+ ? undefined
585
+ : data,
586
+ params:
587
+ method.toLowerCase() === "get"
588
+ ? data
589
+ : undefined,
590
+ cancelToken: axios.CancelToken.source().token,
591
+ });
592
+ setResponse(result.data);
593
+ } catch (error) {
594
+ if (axios.isCancel(error)) {
595
+ console.log("Request cancelled", error.message);
596
+ } else {
597
+ setError(
598
+ error.response
599
+ ? error.response.data
600
+ : error.message
601
+ );
602
+ }
603
+ } finally {
604
+ setLoading(false);
605
+ }
606
+ };
607
+ return [response, error, loading, fetchData];
608
+ };
609
+ //axios封闭结束
610
+
611
+ //API定义开始
612
+ const getFiles = () => {
613
+ const [response, error, loading, fetchData] = useAxios();
614
+
615
+ const fetchDataByPage = async (setting, query) => {
616
+ var host = setting.alist_host;
617
+ if (!host.endsWith("/")) {
618
+ host = host + '/'
619
+ }
620
+ fetchData({
621
+ url: host + 'api/fs/list',
622
+ method: "POST",
623
+ data: query,
624
+ headers: {
625
+ 'Authorization': setting.alist_token,
626
+ 'Content-Type': 'application/json'
627
+ },
628
+ });
629
+ };
630
+ return [response, error, loading, fetchDataByPage];
631
+ };
632
+ //API定义结束
633
+
634
+ const Layout = ({ children }) => {
635
+ useEffect(() => {
636
+ // 组件挂载时执行的代码(相当于 componentDidMount)
637
+ }, []); // 空数组表示只在挂载和卸载时执行
638
+
639
+ const [showSideBar, setShowSideBar] = useState(false);
640
+ const handleSidebarClose = () => setShowSideBar(false);
641
+ const handleSidebarShow = () => setShowSideBar(true);
642
+ const toggleSidebarShow = () => {
643
+ setShowSideBar(!showSideBar);
644
+ };
645
+
646
+ const [setting, setSetting] = useState(false);
647
+
648
+ return (
649
+ <div className="pb-5">
650
+ <header className="sticky-top">
651
+ <Navbar expand="md">
652
+ <Container fluid>
653
+ <div>
654
+ <Navbar.Toggle
655
+ className="shadow-none border-0"
656
+ onClick={handleSidebarShow}
657
+ children={
658
+ <Icon
659
+ icon="menu"
660
+ size="3"
661
+ className="text-white"
662
+ />
663
+ }
664
+ />
665
+ <Navbar.Brand
666
+ as={Link}
667
+ to="/"
668
+ className="text-white"
669
+ >
670
+ 离线管理
671
+ </Navbar.Brand>
672
+ </div>
673
+ <div className="d-flex">
674
+ <Button
675
+ style={{
676
+ backgroundColor: "transparent",
677
+ }}
678
+ className="nav-link btn"
679
+ onClick={() => {
680
+ setSetting(true)
681
+ }}
682
+ children={
683
+ <Icon
684
+ icon="dots-vertical"
685
+ size="3"
686
+ className="text-white"
687
+ />
688
+ }
689
+ ></Button>
690
+ <SettingModal
691
+ show={setting}
692
+ onHide={() => {
693
+ setSetting(false);
694
+ }}
695
+ />
696
+ </div>
697
+ </Container>
698
+ </Navbar>
699
+ </header>
700
+ <Container fluid>
701
+ <Row style={{ minHeight: "100vh" }}>
702
+ <Col
703
+ md="2"
704
+ lg="2"
705
+ xl="2"
706
+ className="ps-0 d-none d-md-block"
707
+ >
708
+ <Offcanvas
709
+ className="leftsidebar h-100 bg-light"
710
+ show={showSideBar}
711
+ onHide={handleSidebarClose}
712
+ placement="start"
713
+ responsive="md"
714
+ >
715
+ <Offcanvas.Header
716
+ className="py-2 border-bottom"
717
+ closeButton
718
+ >
719
+ <Offcanvas.Title>
720
+ 离线任务
721
+ </Offcanvas.Title>
722
+ </Offcanvas.Header>
723
+ <Offcanvas.Body className="p-0">
724
+ <Container fluid className="p-0">
725
+ <Nav
726
+ activeKey="1"
727
+ className="flex-column"
728
+ >
729
+ <Nav.Link
730
+ as={Link}
731
+ className="nav-link text-dark"
732
+ to="/"
733
+ onClick={
734
+ handleSidebarClose
735
+ }
736
+ >
737
+ <Icon
738
+ icon="plus"
739
+ size="6"
740
+ className="me-2"
741
+ />
742
+ 离线管理
743
+ </Nav.Link>
744
+ </Nav>
745
+ </Container>
746
+ </Offcanvas.Body>
747
+ </Offcanvas>
748
+ </Col>
749
+
750
+ <Col xs="12" sm="12" md="10" lg="10" xl="10">
751
+ <main>
752
+ <Container fluid className="pt-2 px-0">
753
+ {children}
754
+ </Container>
755
+ </main>
756
+ </Col>
757
+ </Row>
758
+ </Container>
759
+ </div>
760
+ );
761
+ };
762
+ const Home = () => {
763
+ const location = useLocation();
764
+ const { id } = useParams();
765
+ return (
766
+ <div>
767
+ <div className="d-flex justify-content-between align-items-center p-2 border-bottom bg-light">
768
+ <label className="fs-3">Home</label>
769
+ <ButtonToolbar
770
+ aria-label="文件列表"
771
+ className="bg-teal rounded"
772
+ >
773
+ <ButtonGroup className="bg-teal">
774
+ <IconButton
775
+ onClick={() => {
776
+ alert("test")
777
+ }}
778
+ text="刷新"
779
+ className="bg-teal border-0"
780
+ icon="reload"
781
+ iconClassName="me-1 text-white"
782
+ iconSize="6"
783
+ />
784
+ <IconButton
785
+ onClick={() => {
786
+ alert("hello");
787
+ }}
788
+ text="删除"
789
+ className="bg-teal border-0"
790
+ icon="delete-outline"
791
+ iconClassName="me-1 text-white"
792
+ iconSize="6"
793
+ />
794
+ </ButtonGroup>
795
+ </ButtonToolbar>
796
+ </div>
797
+ <Container fluid className="p-2"></Container>
798
+ </div>
799
+ );
800
+ };
801
+
802
+ App = () => {
803
+ const [open, setOpen] = useState(false);
804
+ const [reload, setReload] = useState(false);
805
+ const [response, error, loading, fetchDataByPage] = getFiles();
806
+ const { folder } = useParams();
807
+ const location = useLocation();
808
+ const [path, setPath] = useState(location.pathname);
809
+ const [page, setPage] = useState(1);
810
+ const [query, setQuery] = useState({ "path": path, "password": "", "page": page, "per_page": 0, "refresh": true });
811
+ const setting = STORE.getState().settings;
812
+ const columns = [
813
+ { title: "文件名称", dataIndex: "name" },
814
+ { title: "大小", dataIndex: "size", render: (row) => (bytesToSize(row.size)) },
815
+ { title: "日期", dataIndex: "created", render: (row) => (formatDate(row.created)) },
816
+ {
817
+ title: "操作",
818
+ dataIndex: "name",
819
+ render: (row) => (
820
+ row.is_dir ? <Nav.Link
821
+ as={Link}
822
+ className="nav-link text-dark"
823
+ to={path + row.name + '/'}
824
+ target="_blank"
825
+ >
826
+ <Icon
827
+ icon="open-in-new"
828
+ size="6"
829
+ className="me-2"
830
+ />
831
+ </Nav.Link> :
832
+ <Icon
833
+ icon="download-outline"
834
+ size="6"
835
+ className="me-2"
836
+ onClick={() => {
837
+ alert(row.name);
838
+ }}
839
+ />
840
+ ),
841
+ },
842
+ ];
843
+
844
+ useEffect(() => {
845
+ if (!setting.alist_token || setting.alist_token.length < 5) {
846
+ layer.alert("请先正确配置Alsit的令牌", { icon: 5 });
847
+ return
848
+ }
849
+ fetchDataByPage(setting, query);
850
+ return () => { }
851
+ }, [reload, query]);
852
+
853
+
854
+ const forceUpdate = () => {
855
+ setReload((pre) => !pre);
856
+ };
857
+
858
+ return (
859
+ <div>
860
+ {error && (
861
+ <div className="text-center text-danger">
862
+ {error}
863
+ </div>
864
+ )}
865
+ {loading && (
866
+ <div className="text-center text-success">
867
+ 正在努力加载中......
868
+ </div>
869
+ )}
870
+ <div className="d-flex justify-content-between align-items-center p-2 border-bottom bg-light">
871
+ <label className="fs-3">文件列表</label>
872
+ <ButtonToolbar
873
+ aria-label="功能区"
874
+ className="bg-teal rounded"
875
+ >
876
+ <ButtonGroup className="bg-teal">
877
+ <IconButton
878
+ onClick={() => {
879
+ emitEvent("test", { a: 'b' })
880
+ }}
881
+ text="刷新"
882
+ className="bg-teal border-0"
883
+ icon="reload"
884
+ iconClassName="me-1 text-white"
885
+ iconSize="6"
886
+ />
887
+ </ButtonGroup>
888
+ </ButtonToolbar>
889
+ </div>
890
+ <Container fluid className="p-2">
891
+ {response && (
892
+ <DataTable data={response.data.content ? response.data.content : []} columns={columns} />
893
+ )}
894
+ </Container>
895
+ </div>
896
+ );
897
+ };
898
+
899
+ const container = document.getElementById("root");
900
+ const root = ReactDOM.createRoot(container);
901
+ root.render(
902
+ <HashRouter>
903
+ <Route path="/:path?">
904
+ <Layout>
905
+ <Switch>
906
+ <Route path="/" exact component={App} />
907
+ <Route path="/:folder?" component={App} />
908
+ </Switch>
909
+ </Layout>
910
+ </Route>
911
+ </HashRouter>
912
+ );
913
+
914
+ $(document).ready(function () {
915
+ $(window).scroll(function () {
916
+ if ($(this).scrollTop() > 50) {
917
+ $("#back-to-top").fadeIn();
918
+ } else {
919
+ $("#back-to-top").fadeOut();
920
+ }
921
+ });
922
+ // scroll body to 0px on click
923
+ $("#back-to-top").click(function () {
924
+ $("body,html").animate(
925
+ {
926
+ scrollTop: 0,
927
+ },
928
+ 400
929
+ );
930
+ return false;
931
+ });
932
+ });
933
+ </script>
934
+ </body>
935
+
936
+ </html>