mirror of
https://github.com/whyour/qinglong.git
synced 2026-07-17 01:14:50 +08:00
初始化项目
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { request } from '@/utils/http';
|
||||
|
||||
const Crontab = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getConfig = () => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}config/shareCode`).then((data) => {
|
||||
setValue(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const updateConfig = () => {
|
||||
request
|
||||
.post(`${config.apiPrefix}save`, {
|
||||
data: { content: value, name: 'diy.sh' },
|
||||
})
|
||||
.then((data) => {
|
||||
notification.success({
|
||||
message: data.msg,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="互助码"
|
||||
loading={loading}
|
||||
extra={[
|
||||
<Button key="1" type="primary" onClick={updateConfig}>
|
||||
保存
|
||||
</Button>,
|
||||
]}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode: 'shell',
|
||||
theme: 'dracula',
|
||||
readOnly: 'nocursor',
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crontab;
|
||||
@@ -0,0 +1,148 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { request } from '@/utils/http';
|
||||
import QRCode from 'qrcode.react';
|
||||
|
||||
const Config = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getConfig = () => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
||||
setValue(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const updateConfig = () => {
|
||||
request
|
||||
.post(`${config.apiPrefix}save`, {
|
||||
data: { content: value, name: 'config.sh' },
|
||||
})
|
||||
.then((data) => {
|
||||
notification.success({
|
||||
message: data.msg,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function sleep(time: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
const showQrCode = () => {
|
||||
request.get(`${config.apiPrefix}qrcode`).then(async (data) => {
|
||||
const modal = Modal.info({
|
||||
title: '二维码',
|
||||
content: (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginLeft: -38,
|
||||
}}
|
||||
>
|
||||
<QRCode
|
||||
style={{
|
||||
width: 200,
|
||||
height: 200,
|
||||
marginBottom: 10,
|
||||
marginTop: 20,
|
||||
}}
|
||||
value={data.qrcode}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
getCookie(modal);
|
||||
});
|
||||
};
|
||||
|
||||
const getCookie = async (modal: { destroy: () => void }) => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const result = await request.get(`${config.apiPrefix}cookie`);
|
||||
console.log(i, result);
|
||||
if (result && result.cookie) {
|
||||
notification.success({
|
||||
message: 'Cookie获取成功',
|
||||
});
|
||||
modal.destroy();
|
||||
Modal.success({
|
||||
title: '获取Cookie成功',
|
||||
content: <div>{result.cookie}</div>,
|
||||
});
|
||||
break;
|
||||
}
|
||||
await sleep(2000);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="config.sh"
|
||||
loading={loading}
|
||||
extra={[
|
||||
<Button key="1" type="primary" onClick={updateConfig}>
|
||||
保存
|
||||
</Button>,
|
||||
<Button key="2" type="primary" onClick={showQrCode}>
|
||||
扫码获取Cookie
|
||||
</Button>,
|
||||
]}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode: 'shell',
|
||||
theme: 'dracula',
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Config;
|
||||
@@ -0,0 +1,190 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal, Table, Tag, Space } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { request } from '@/utils/http';
|
||||
import QRCode from 'qrcode.react';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'pin',
|
||||
key: 'pin',
|
||||
},
|
||||
{
|
||||
title: '昵称',
|
||||
dataIndex: 'nickname',
|
||||
key: 'nickname',
|
||||
},
|
||||
{
|
||||
title: '值',
|
||||
dataIndex: 'cookie',
|
||||
key: 'cookie',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
dataIndex: 'status',
|
||||
render: (text: string, record: any) => (
|
||||
<Tag color="success">success</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text: string, record: any) => (
|
||||
<Space size="middle">
|
||||
<a>Invite {record.name}</a>
|
||||
<a>Delete</a>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
address: 'New York No. 1 Lake Park',
|
||||
tags: ['nice', 'developer'],
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Jim Green',
|
||||
age: 42,
|
||||
address: 'London No. 1 Lake Park',
|
||||
tags: ['loser'],
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
address: 'Sidney No. 1 Lake Park',
|
||||
tags: ['cool', 'teacher'],
|
||||
},
|
||||
];
|
||||
|
||||
const Config = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getConfig = () => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
||||
setValue(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const updateConfig = () => {
|
||||
request
|
||||
.post(`${config.apiPrefix}save`, {
|
||||
data: { content: value, name: 'config.sh' },
|
||||
})
|
||||
.then((data) => {
|
||||
notification.success({
|
||||
message: data.msg,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function sleep(time: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
const showQrCode = () => {
|
||||
request.get(`${config.apiPrefix}qrcode`).then(async (data) => {
|
||||
const modal = Modal.info({
|
||||
title: '二维码',
|
||||
content: (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginLeft: -38,
|
||||
}}
|
||||
>
|
||||
<QRCode
|
||||
style={{
|
||||
width: 200,
|
||||
height: 200,
|
||||
marginBottom: 10,
|
||||
marginTop: 20,
|
||||
}}
|
||||
value={data.qrcode}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
getCookie(modal);
|
||||
});
|
||||
};
|
||||
|
||||
const getCookie = async (modal: { destroy: () => void }) => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const result = await request.get(`${config.apiPrefix}cookie`);
|
||||
console.log(i, result);
|
||||
if (result && result.cookie) {
|
||||
notification.success({
|
||||
message: 'Cookie获取成功',
|
||||
});
|
||||
modal.destroy();
|
||||
Modal.success({
|
||||
title: '获取Cookie成功',
|
||||
content: <div>{result.cookie}</div>,
|
||||
});
|
||||
break;
|
||||
}
|
||||
await sleep(2000);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="Cookie管理"
|
||||
loading={loading}
|
||||
extra={[
|
||||
<Button key="2" type="primary" onClick={showQrCode}>
|
||||
扫码获取Cookie
|
||||
</Button>,
|
||||
]}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<Table columns={columns} pagination={{hideOnSinglePage: true}} dataSource={data} />
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Config;
|
||||
@@ -0,0 +1,92 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { request } from '@/utils/http';
|
||||
|
||||
const Crontab = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getConfig = () => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}config/crontab`).then((data) => {
|
||||
setValue(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const updateConfig = () => {
|
||||
request
|
||||
.post(`${config.apiPrefix}save`, {
|
||||
data: { content: value, name: 'crontab.list' },
|
||||
})
|
||||
.then((data) => {
|
||||
notification.success({
|
||||
message: data.msg,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="crontab.list"
|
||||
loading={loading}
|
||||
extra={[
|
||||
<Button key="1" type="primary" onClick={updateConfig}>
|
||||
保存
|
||||
</Button>,
|
||||
]}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode: 'shell',
|
||||
theme: 'dracula',
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crontab;
|
||||
@@ -0,0 +1,12 @@
|
||||
.d2h-files-diff {
|
||||
height: calc(100vh - 130px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.d2h-code-side-linenumber {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.d2h-code-side-line {
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { request } from '@/utils/http';
|
||||
import ReactDiffViewer from 'react-diff-viewer';
|
||||
import './index.less';
|
||||
|
||||
const Crontab = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [sample, setSample] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getConfig = () => {
|
||||
request.get(`${config.apiPrefix}config/config`).then((data) => {
|
||||
setValue(data);
|
||||
});
|
||||
};
|
||||
|
||||
const getSample = () => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}config/sample`).then((data) => {
|
||||
setSample(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
getSample();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="对比工具"
|
||||
loading={loading}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<ReactDiffViewer
|
||||
styles={{ diffRemoved: {
|
||||
overflowX: 'auto',
|
||||
maxWidth: 300,
|
||||
},
|
||||
diffAdded: {
|
||||
overflowX: 'auto',
|
||||
maxWidth: 300,
|
||||
},line: {
|
||||
wordBreak: 'break-word',
|
||||
}, }}
|
||||
oldValue={value}
|
||||
newValue={sample}
|
||||
splitView={true}
|
||||
leftTitle="config.sh"
|
||||
rightTitle="config.sh.sample"
|
||||
disableWordDiff={true}
|
||||
/>
|
||||
{/* <CodeDiff
|
||||
style={{ height: 'calc(100vh - 72px)', overflowY: 'auto' }}
|
||||
outputFormat="side-by-side"
|
||||
oldStr={value}
|
||||
newStr={sample}
|
||||
/> */}
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crontab;
|
||||
@@ -0,0 +1,92 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { request } from '@/utils/http';
|
||||
|
||||
const Crontab = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getConfig = () => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}config/diy`).then((data) => {
|
||||
setValue(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const updateConfig = () => {
|
||||
request
|
||||
.post(`${config.apiPrefix}save`, {
|
||||
data: { content: value, name: 'diy.sh' },
|
||||
})
|
||||
.then((data) => {
|
||||
notification.success({
|
||||
message: data.msg,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="diy.sh"
|
||||
loading={loading}
|
||||
extra={[
|
||||
<Button key="1" type="primary" onClick={updateConfig}>
|
||||
保存
|
||||
</Button>,
|
||||
]}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode: 'shell',
|
||||
theme: 'dracula',
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crontab;
|
||||
@@ -0,0 +1,112 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Modal, TreeSelect } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { request } from '@/utils/http';
|
||||
const Log = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [title, setTitle] = useState('log');
|
||||
const [value, setValue] = useState('请选择日志文件');
|
||||
const [select, setSelect] = useState();
|
||||
const [data, setData] = useState();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const getConfig = () => {
|
||||
request.get(`${config.apiPrefix}logs`).then((data) => {
|
||||
setData(formatData(data.dirs) as any);
|
||||
});
|
||||
};
|
||||
|
||||
const formatData = (tree: any[]) => {
|
||||
return tree.map(x => {
|
||||
x.title = x.dirName;
|
||||
x.value = x.dirName;
|
||||
x.disabled = true;
|
||||
x.children = x.files.map((y: string) => ({ title: y, key: y, value: y, parent: x.dirName }));
|
||||
return x;
|
||||
})
|
||||
}
|
||||
|
||||
const getLog = (node: any) => {
|
||||
setLoading(true);
|
||||
request.get(`${config.apiPrefix}logs/${node.parent}/${node.value}`).then((data) => {
|
||||
setValue(data);
|
||||
}).finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const onSelect = (value: any, node: any) => {
|
||||
setSelect(value);
|
||||
setTitle(node.parent);
|
||||
getLog(node);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
getConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title={title}
|
||||
loading={loading}
|
||||
extra={[
|
||||
<TreeSelect
|
||||
style={{ width: 280 }}
|
||||
value={select}
|
||||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||
treeData={data}
|
||||
placeholder="请选择日志文件"
|
||||
showSearch
|
||||
key="title"
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
]}
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
matchBrackets: true,
|
||||
mode: 'shell',
|
||||
theme: 'dracula',
|
||||
readOnly: 'nocursor',
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setValue(value);
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Log;
|
||||
@@ -0,0 +1,58 @@
|
||||
.form {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
margin: -160px 0 0 -160px;
|
||||
width: 320px;
|
||||
height: 320px;
|
||||
padding: 36px;
|
||||
box-shadow: 0 0 100px rgba(0, 0, 0, 0.08);
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
color: rgb(204, 204, 204);
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
vertical-align: text-bottom;
|
||||
font-size: 16px;
|
||||
text-transform: uppercase;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
// color: @primary-color;
|
||||
// .text-gradient();
|
||||
}
|
||||
}
|
||||
|
||||
.ant-spin-container,
|
||||
.ant-spin-nested-loading {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import React, { Fragment, useEffect } from 'react';
|
||||
import { Button, Row, Input, Form, notification } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { history } from 'umi';
|
||||
import styles from './index.less';
|
||||
import { request } from '@/utils/http';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const Login = () => {
|
||||
const handleOk = (values: any) => {
|
||||
request
|
||||
.post(`${config.apiPrefix}auth`, {
|
||||
data: {
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.err == 0) {
|
||||
localStorage.setItem(config.authKey, 'true');
|
||||
history.push('/cookie');
|
||||
} else {
|
||||
notification.open({
|
||||
message: data.msg,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const isAuth = localStorage.getItem(config.authKey);
|
||||
if (isAuth) {
|
||||
history.push('/cookie');
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={styles.form}>
|
||||
<div className={styles.logo}>
|
||||
<span>{config.siteName}</span>
|
||||
</div>
|
||||
<Form onFinish={handleOk}>
|
||||
<FormItem
|
||||
name="username"
|
||||
rules={[{ required: true, message: '请输入用户名' }]}
|
||||
hasFeedback
|
||||
>
|
||||
<Input placeholder="用户名" autoFocus/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="password"
|
||||
rules={[{ required: true, message: '请输入密码' }]}
|
||||
hasFeedback
|
||||
>
|
||||
<Input type="password" placeholder="密码" />
|
||||
</FormItem>
|
||||
<Row>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Sign in
|
||||
</Button>
|
||||
</Row>
|
||||
</Form>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
@@ -0,0 +1,84 @@
|
||||
import React, { PureComponent, Fragment, useState, useEffect } from 'react';
|
||||
import { Button, notification, Input, Form } from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||
import { request } from '@/utils/http';
|
||||
|
||||
const Password = () => {
|
||||
const [width, setWdith] = useState('100%');
|
||||
const [marginLeft, setMarginLeft] = useState(0);
|
||||
const [marginTop, setMarginTop] = useState(-72);
|
||||
const [value, setValue] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const handleOk = (values: any) => {
|
||||
request
|
||||
.post(`${config.apiPrefix}auth?t=${Date.now()}`, {
|
||||
data: {
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.err == 0) {
|
||||
localStorage.setItem(config.authKey, 'true');
|
||||
} else {
|
||||
notification.open({
|
||||
message: data.msg,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body.clientWidth < 768) {
|
||||
setWdith('auto');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(0);
|
||||
} else {
|
||||
setWdith('100%');
|
||||
setMarginLeft(0);
|
||||
setMarginTop(-72);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="code-mirror-wrapper"
|
||||
title="修改密码"
|
||||
header={{
|
||||
style: {
|
||||
padding: '4px 16px 4px 15px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 20,
|
||||
marginTop,
|
||||
width,
|
||||
marginLeft,
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<Form onFinish={handleOk} style={{ padding: 20, background: '#fff', height: 'calc(100vh - 96px)' }}>
|
||||
<Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]} hasFeedback style={{width:300}}>
|
||||
<Input placeholder="用户名" autoFocus/>
|
||||
</Form.Item>
|
||||
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]} hasFeedback style={{width:300}}>
|
||||
<Input type="password" placeholder="密码" />
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
保存
|
||||
</Button>
|
||||
</Form>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Password;
|
||||
Reference in New Issue
Block a user