mirror of
				https://github.com/whyour/qinglong.git
				synced 2025-11-01 01:16:07 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			300 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import intl from 'react-intl-universal';
 | |
| import React, { useState, useEffect, useRef } from 'react';
 | |
| import {
 | |
|   Button,
 | |
|   InputNumber,
 | |
|   Form,
 | |
|   Radio,
 | |
|   message,
 | |
|   Input,
 | |
|   Upload,
 | |
|   Modal,
 | |
|   Select,
 | |
| } from 'antd';
 | |
| import * as DarkReader from '@umijs/ssr-darkreader';
 | |
| import config from '@/utils/config';
 | |
| import { request } from '@/utils/http';
 | |
| import CheckUpdate from './checkUpdate';
 | |
| import { SharedContext } from '@/layouts';
 | |
| import { saveAs } from 'file-saver';
 | |
| import './index.less';
 | |
| import { UploadOutlined } from '@ant-design/icons';
 | |
| import Countdown from 'antd/lib/statistic/Countdown';
 | |
| import useProgress from './progress';
 | |
| import pick from 'lodash/pick';
 | |
| 
 | |
| const dataMap = {
 | |
|   'log-remove-frequency': 'logRemoveFrequency',
 | |
|   'cron-concurrency': 'cronConcurrency',
 | |
| };
 | |
| 
 | |
| const Other = ({
 | |
|   systemInfo,
 | |
|   reloadTheme,
 | |
| }: Pick<SharedContext, 'reloadTheme' | 'systemInfo'>) => {
 | |
|   const defaultTheme = localStorage.getItem('qinglong_dark_theme') || 'auto';
 | |
|   const [systemConfig, setSystemConfig] = useState<{
 | |
|     logRemoveFrequency?: number | null;
 | |
|     cronConcurrency?: number | null;
 | |
|   }>();
 | |
|   const [form] = Form.useForm();
 | |
|   const [exportLoading, setExportLoading] = useState(false);
 | |
|   const showUploadProgress = useProgress(intl.get('上传'));
 | |
|   const showDownloadProgress = useProgress(intl.get('下载'));
 | |
| 
 | |
|   const {
 | |
|     enable: enableDarkMode,
 | |
|     disable: disableDarkMode,
 | |
|     exportGeneratedCSS: collectCSS,
 | |
|     setFetchMethod,
 | |
|     auto: followSystemColorScheme,
 | |
|   } = DarkReader || {};
 | |
| 
 | |
|   const themeChange = (e: any) => {
 | |
|     const _theme = e.target.value;
 | |
|     localStorage.setItem('qinglong_dark_theme', e.target.value);
 | |
|     setFetchMethod(fetch);
 | |
| 
 | |
|     if (_theme === 'dark') {
 | |
|       enableDarkMode({});
 | |
|     } else if (_theme === 'light') {
 | |
|       disableDarkMode();
 | |
|     } else {
 | |
|       followSystemColorScheme({});
 | |
|     }
 | |
|     reloadTheme();
 | |
|   };
 | |
| 
 | |
|   const handleLangChange = (v: string) => {
 | |
|     localStorage.setItem('lang', v);
 | |
|     setTimeout(() => {
 | |
|       window.location.reload();
 | |
|     }, 500);
 | |
|   };
 | |
| 
 | |
|   const getSystemConfig = () => {
 | |
|     request
 | |
|       .get(`${config.apiPrefix}system/config`)
 | |
|       .then(({ code, data }) => {
 | |
|         if (code === 200 && data.info) {
 | |
|           setSystemConfig(data.info);
 | |
|         }
 | |
|       })
 | |
|       .catch((error: any) => {
 | |
|         console.log(error);
 | |
|       });
 | |
|   };
 | |
| 
 | |
|   const updateSystemConfig = (path: keyof typeof dataMap) => {
 | |
|     request
 | |
|       .put(
 | |
|         `${config.apiPrefix}system/config/${path}`,
 | |
|         pick(systemConfig, dataMap[path]),
 | |
|       )
 | |
|       .then(({ code, data }) => {
 | |
|         if (code === 200) {
 | |
|           message.success(intl.get('更新成功'));
 | |
|         }
 | |
|       })
 | |
|       .catch((error: any) => {
 | |
|         console.log(error);
 | |
|       });
 | |
|   };
 | |
| 
 | |
|   const exportData = () => {
 | |
|     setExportLoading(true);
 | |
|     request
 | |
|       .put<Blob>(
 | |
|         `${config.apiPrefix}system/data/export`,
 | |
|         {},
 | |
|         {
 | |
|           responseType: 'blob',
 | |
|           timeout: 86400000,
 | |
|           onDownloadProgress: (e) => {
 | |
|             if (e.progress) {
 | |
|               showDownloadProgress(parseFloat((e.progress * 100).toFixed(1)));
 | |
|             }
 | |
|           },
 | |
|         },
 | |
|       )
 | |
|       .then((res) => {
 | |
|         saveAs(res, 'data.tgz');
 | |
|       })
 | |
|       .catch((error: any) => {
 | |
|         console.log(error);
 | |
|       })
 | |
|       .finally(() => setExportLoading(false));
 | |
|   };
 | |
| 
 | |
|   const showReloadModal = () => {
 | |
|     Modal.confirm({
 | |
|       width: 600,
 | |
|       maskClosable: false,
 | |
|       title: intl.get('确认重启'),
 | |
|       centered: true,
 | |
|       content: (
 | |
|         <>
 | |
|           <div>{intl.get('备份数据上传成功,确认覆盖数据')}</div>
 | |
|           <div>{intl.get('如果恢复失败,可进入容器执行')} ql reload data</div>
 | |
|         </>
 | |
|       ),
 | |
|       okText: intl.get('重启'),
 | |
|       onOk() {
 | |
|         request
 | |
|           .put(`${config.apiPrefix}system/reload`, { type: 'data' })
 | |
|           .then(() => {
 | |
|             message.success({
 | |
|               content: (
 | |
|                 <span>
 | |
|                   {intl.get('系统将在')}
 | |
|                   <Countdown
 | |
|                     className="inline-countdown"
 | |
|                     format="ss"
 | |
|                     value={Date.now() + 1000 * 30}
 | |
|                   />
 | |
|                   {intl.get('秒后自动刷新')}
 | |
|                 </span>
 | |
|               ),
 | |
|               duration: 30,
 | |
|             });
 | |
|             setTimeout(() => {
 | |
|               window.location.reload();
 | |
|             }, 30000);
 | |
|           })
 | |
|           .catch((error: any) => {
 | |
|             console.log(error);
 | |
|           });
 | |
|       },
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   useEffect(() => {
 | |
|     getSystemConfig();
 | |
|   }, []);
 | |
| 
 | |
|   return (
 | |
|     <Form layout="vertical" form={form}>
 | |
|       <Form.Item
 | |
|         label={intl.get('主题')}
 | |
|         name="theme"
 | |
|         initialValue={defaultTheme}
 | |
|       >
 | |
|         <Radio.Group
 | |
|           onChange={themeChange}
 | |
|           value={defaultTheme}
 | |
|           optionType="button"
 | |
|           buttonStyle="solid"
 | |
|         >
 | |
|           <Radio.Button
 | |
|             value="light"
 | |
|             style={{ width: 70, textAlign: 'center' }}
 | |
|           >
 | |
|             {intl.get('亮色')}
 | |
|           </Radio.Button>
 | |
|           <Radio.Button value="dark" style={{ width: 66, textAlign: 'center' }}>
 | |
|             {intl.get('暗色')}
 | |
|           </Radio.Button>
 | |
|           <Radio.Button
 | |
|             value="auto"
 | |
|             style={{ width: 129, textAlign: 'center' }}
 | |
|           >
 | |
|             {intl.get('跟随系统')}
 | |
|           </Radio.Button>
 | |
|         </Radio.Group>
 | |
|       </Form.Item>
 | |
|       <Form.Item
 | |
|         label={intl.get('日志删除频率')}
 | |
|         name="frequency"
 | |
|         tooltip={intl.get('每x天自动删除x天以前的日志')}
 | |
|       >
 | |
|         <Input.Group compact>
 | |
|           <InputNumber
 | |
|             addonBefore={intl.get('每')}
 | |
|             addonAfter={intl.get('天')}
 | |
|             style={{ width: 180 }}
 | |
|             min={0}
 | |
|             value={systemConfig?.logRemoveFrequency}
 | |
|             onChange={(value) => {
 | |
|               setSystemConfig({ ...systemConfig, logRemoveFrequency: value });
 | |
|             }}
 | |
|           />
 | |
|           <Button
 | |
|             type="primary"
 | |
|             onClick={() => {
 | |
|               updateSystemConfig('log-remove-frequency');
 | |
|             }}
 | |
|             style={{ width: 84 }}
 | |
|           >
 | |
|             {intl.get('确认')}
 | |
|           </Button>
 | |
|         </Input.Group>
 | |
|       </Form.Item>
 | |
|       <Form.Item label={intl.get('定时任务并发数')} name="frequency">
 | |
|         <Input.Group compact>
 | |
|           <InputNumber
 | |
|             style={{ width: 180 }}
 | |
|             min={1}
 | |
|             value={systemConfig?.cronConcurrency}
 | |
|             onChange={(value) => {
 | |
|               setSystemConfig({ ...systemConfig, cronConcurrency: value });
 | |
|             }}
 | |
|           />
 | |
|           <Button
 | |
|             type="primary"
 | |
|             onClick={() => {
 | |
|               updateSystemConfig('cron-concurrency');
 | |
|             }}
 | |
|             style={{ width: 84 }}
 | |
|           >
 | |
|             {intl.get('确认')}
 | |
|           </Button>
 | |
|         </Input.Group>
 | |
|       </Form.Item>
 | |
|       <Form.Item label={intl.get('语言')} name="lang">
 | |
|         <Select
 | |
|           defaultValue={localStorage.getItem('lang') || ''}
 | |
|           style={{ width: 264 }}
 | |
|           onChange={handleLangChange}
 | |
|           options={[
 | |
|             { value: '', label: intl.get('跟随系统') },
 | |
|             { value: 'zh', label: '简体中文' },
 | |
|             { value: 'en', label: 'English' },
 | |
|           ]}
 | |
|         />
 | |
|       </Form.Item>
 | |
|       <Form.Item label={intl.get('数据备份还原')} name="frequency">
 | |
|         <Button type="primary" onClick={exportData} loading={exportLoading}>
 | |
|           {exportLoading ? intl.get('生成数据中...') : intl.get('备份')}
 | |
|         </Button>
 | |
|         <Upload
 | |
|           method="put"
 | |
|           showUploadList={false}
 | |
|           maxCount={1}
 | |
|           action={`${config.apiPrefix}system/data/import`}
 | |
|           onChange={(e) => {
 | |
|             if (e.event?.percent) {
 | |
|               showUploadProgress(parseFloat(e.event?.percent.toFixed(1)));
 | |
|               if (e.event?.percent === 100) {
 | |
|                 showReloadModal();
 | |
|               }
 | |
|             }
 | |
|           }}
 | |
|           name="data"
 | |
|           headers={{
 | |
|             Authorization: `Bearer ${localStorage.getItem(config.authKey)}`,
 | |
|           }}
 | |
|         >
 | |
|           <Button icon={<UploadOutlined />} style={{ marginLeft: 8 }}>
 | |
|             {intl.get('还原数据')}
 | |
|           </Button>
 | |
|         </Upload>
 | |
|       </Form.Item>
 | |
|       <Form.Item label={intl.get('检查更新')} name="update">
 | |
|         <CheckUpdate systemInfo={systemInfo} />
 | |
|       </Form.Item>
 | |
|     </Form>
 | |
|   );
 | |
| };
 | |
| 
 | |
| export default Other;
 | 
