mirror of
https://github.com/whyour/qinglong.git
synced 2026-07-17 17:54:32 +08:00
修复antd兼容性,日志详情自动滚动
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { Button, Result, Typography } from 'antd';
|
||||
|
||||
const { Link } = Typography;
|
||||
|
||||
const NotFound: React.FC = () => (
|
||||
<Result
|
||||
status="404"
|
||||
title="404"
|
||||
extra={
|
||||
<Button type="primary">
|
||||
<Link href="/">返回首页</Link>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
export default NotFound;
|
||||
+42
-45
@@ -14,6 +14,7 @@ import {
|
||||
Popover,
|
||||
Tabs,
|
||||
TablePaginationConfig,
|
||||
MenuProps,
|
||||
} from 'antd';
|
||||
import {
|
||||
ClockCircleOutlined,
|
||||
@@ -684,15 +685,13 @@ const Crontab = () => {
|
||||
arrow={{ pointAtCenter: true }}
|
||||
placement="bottomRight"
|
||||
trigger={['click']}
|
||||
overlay={
|
||||
<Menu
|
||||
items={getMenuItems(record)}
|
||||
onClick={({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
action(key, record, index);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
menu={{
|
||||
items: getMenuItems(record),
|
||||
onClick: ({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
action(key, record, index);
|
||||
},
|
||||
}}
|
||||
>
|
||||
<a onClick={(e) => e.stopPropagation()}>
|
||||
<EllipsisOutlined />
|
||||
@@ -889,41 +888,39 @@ const Crontab = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const menu = (
|
||||
<Menu
|
||||
onClick={({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
viewAction(key);
|
||||
}}
|
||||
items={[
|
||||
...[...enabledCronViews].slice(4).map((x) => ({
|
||||
label: (
|
||||
<Space style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span>{x.name}</span>
|
||||
{viewConf?.id === x.id && (
|
||||
<CheckOutlined style={{ color: '#1890ff' }} />
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
key: x.id,
|
||||
icon: <UnorderedListOutlined />,
|
||||
})),
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
label: '新建视图',
|
||||
key: 'new',
|
||||
icon: <PlusOutlined />,
|
||||
},
|
||||
{
|
||||
label: '视图管理',
|
||||
key: 'manage',
|
||||
icon: <SettingOutlined />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
const menu: MenuProps = {
|
||||
onClick: ({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
viewAction(key);
|
||||
},
|
||||
items: [
|
||||
...[...enabledCronViews].slice(4).map((x) => ({
|
||||
label: (
|
||||
<Space style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span>{x.name}</span>
|
||||
{viewConf?.id === x.id && (
|
||||
<CheckOutlined style={{ color: '#1890ff' }} />
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
key: x.id,
|
||||
icon: <UnorderedListOutlined />,
|
||||
})),
|
||||
{
|
||||
type: 'divider' as 'group',
|
||||
},
|
||||
{
|
||||
label: '新建视图',
|
||||
key: 'new',
|
||||
icon: <PlusOutlined />,
|
||||
},
|
||||
{
|
||||
label: '视图管理',
|
||||
key: 'manage',
|
||||
icon: <SettingOutlined />,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const getCronViews = () => {
|
||||
setLoading(true);
|
||||
@@ -975,7 +972,7 @@ const Crontab = () => {
|
||||
className={`crontab-view ${moreMenuActive ? 'more-active' : ''}`}
|
||||
tabBarExtraContent={
|
||||
<Dropdown
|
||||
overlay={menu}
|
||||
menu={menu}
|
||||
trigger={['click']}
|
||||
overlayStyle={{ minWidth: 200 }}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Modal, message, Input, Form, Statistic, Button } from 'antd';
|
||||
import { request } from '@/utils/http';
|
||||
import config from '@/utils/config';
|
||||
@@ -34,7 +34,6 @@ const CronLogModal = ({
|
||||
const [loading, setLoading] = useState<any>(true);
|
||||
const [executing, setExecuting] = useState<any>(true);
|
||||
const [isPhone, setIsPhone] = useState(false);
|
||||
const [theme, setTheme] = useState<string>('');
|
||||
|
||||
const getCronLog = (isFirst?: boolean) => {
|
||||
if (isFirst) {
|
||||
@@ -49,10 +48,14 @@ const CronLogModal = ({
|
||||
) {
|
||||
const log = data as string;
|
||||
setValue(log || '暂无日志');
|
||||
setExecuting(
|
||||
log && !logEnded(log) && !log.includes('重启面板'),
|
||||
);
|
||||
if (log && !logEnded(log) && !log.includes('重启面板')) {
|
||||
const hasNext = log && !logEnded(log) && !log.includes('重启面板');
|
||||
setExecuting(hasNext);
|
||||
setTimeout(() => {
|
||||
document
|
||||
.querySelector('#log-flag')!
|
||||
.scrollIntoView({ behavior: 'smooth' });
|
||||
});
|
||||
if (hasNext) {
|
||||
setTimeout(() => {
|
||||
getCronLog();
|
||||
}, 2000);
|
||||
@@ -155,6 +158,7 @@ const CronLogModal = ({
|
||||
{value}
|
||||
</pre>
|
||||
)}
|
||||
<div id="log-flag"></div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
+42
-42
@@ -11,6 +11,7 @@ import {
|
||||
Dropdown,
|
||||
Menu,
|
||||
Empty,
|
||||
MenuProps,
|
||||
} from 'antd';
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
@@ -66,7 +67,8 @@ const Script = () => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const editorRef = useRef<any>(null);
|
||||
const [isAddFileModalVisible, setIsAddFileModalVisible] = useState(false);
|
||||
const [isRenameFileModalVisible, setIsRenameFileModalVisible] = useState(false);
|
||||
const [isRenameFileModalVisible, setIsRenameFileModalVisible] =
|
||||
useState(false);
|
||||
const [currentNode, setCurrentNode] = useState<any>();
|
||||
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
|
||||
|
||||
@@ -293,12 +295,12 @@ const Script = () => {
|
||||
|
||||
const renameFile = () => {
|
||||
setIsRenameFileModalVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRenameFileCancel = () => {
|
||||
setIsRenameFileModalVisible(false);
|
||||
getScripts(false);
|
||||
}
|
||||
};
|
||||
|
||||
const addFile = () => {
|
||||
setIsAddFileModalVisible(true);
|
||||
@@ -402,46 +404,44 @@ const Script = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const menu = isEditing ? (
|
||||
<Menu
|
||||
items={[
|
||||
{ label: '保存', key: 'save', icon: <PlusOutlined /> },
|
||||
{ label: '退出编辑', key: 'exit', icon: <EditOutlined /> },
|
||||
]}
|
||||
onClick={({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
action(key);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Menu
|
||||
items={[
|
||||
{ label: '新建', key: 'add', icon: <PlusOutlined /> },
|
||||
{
|
||||
label: '编辑',
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
disabled: !select,
|
||||
const menu: MenuProps = isEditing
|
||||
? {
|
||||
items: [
|
||||
{ label: '保存', key: 'save', icon: <PlusOutlined /> },
|
||||
{ label: '退出编辑', key: 'exit', icon: <EditOutlined /> },
|
||||
],
|
||||
onClick: ({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
action(key);
|
||||
},
|
||||
{
|
||||
label: '重命名',
|
||||
key: 'rename',
|
||||
icon: <IconFont type="ql-icon-rename" />,
|
||||
disabled: !select,
|
||||
}
|
||||
: {
|
||||
items: [
|
||||
{ label: '新建', key: 'add', icon: <PlusOutlined /> },
|
||||
{
|
||||
label: '编辑',
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
disabled: !select,
|
||||
},
|
||||
{
|
||||
label: '重命名',
|
||||
key: 'rename',
|
||||
icon: <IconFont type="ql-icon-rename" />,
|
||||
disabled: !select,
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
disabled: !select,
|
||||
},
|
||||
],
|
||||
onClick: ({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
menuAction(key);
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
disabled: !select,
|
||||
},
|
||||
]}
|
||||
onClick={({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
menuAction(key);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
@@ -464,7 +464,7 @@ const Script = () => {
|
||||
allowClear
|
||||
onSelect={onSelect}
|
||||
/>,
|
||||
<Dropdown overlay={menu} trigger={['click']}>
|
||||
<Dropdown menu={menu} trigger={['click']}>
|
||||
<Button type="primary" icon={<EllipsisOutlined />} />
|
||||
</Dropdown>,
|
||||
]
|
||||
|
||||
+6
-105
@@ -17,7 +17,6 @@ import {
|
||||
import config from '@/utils/config';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { request } from '@/utils/http';
|
||||
import * as DarkReader from '@umijs/ssr-darkreader';
|
||||
import AppModal from './appModal';
|
||||
import {
|
||||
EditOutlined,
|
||||
@@ -27,18 +26,13 @@ import {
|
||||
import SecuritySettings from './security';
|
||||
import LoginLog from './loginLog';
|
||||
import NotificationSetting from './notification';
|
||||
import CheckUpdate from './checkUpdate';
|
||||
import Other from './other';
|
||||
import About from './about';
|
||||
import { useOutletContext } from '@umijs/max';
|
||||
import { SharedContext } from '@/layouts';
|
||||
import './index.less';
|
||||
|
||||
const { Text } = Typography;
|
||||
const optionsWithDisabled = [
|
||||
{ label: '亮色', value: 'light' },
|
||||
{ label: '暗色', value: 'dark' },
|
||||
{ label: '跟随系统', value: 'auto' },
|
||||
];
|
||||
|
||||
const Setting = () => {
|
||||
const {
|
||||
@@ -121,37 +115,12 @@ const Setting = () => {
|
||||
];
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const defaultTheme = localStorage.getItem('qinglong_dark_theme') || 'auto';
|
||||
const [dataSource, setDataSource] = useState<any[]>([]);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [editedApp, setEditedApp] = useState<any>();
|
||||
const [tabActiveKey, setTabActiveKey] = useState('security');
|
||||
const [loginLogData, setLoginLogData] = useState<any[]>([]);
|
||||
const [notificationInfo, setNotificationInfo] = useState<any>();
|
||||
const [logRemoveFrequency, setLogRemoveFrequency] = useState<number>();
|
||||
const [form] = Form.useForm();
|
||||
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 getApps = () => {
|
||||
setLoading(true);
|
||||
@@ -276,8 +245,6 @@ const Setting = () => {
|
||||
getLoginLog();
|
||||
} else if (activeKey === 'notification') {
|
||||
getNotification();
|
||||
} else if (activeKey === 'other') {
|
||||
getLogRemoveFrequency();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -294,37 +261,6 @@ const Setting = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const getLogRemoveFrequency = () => {
|
||||
request
|
||||
.get(`${config.apiPrefix}system/log/remove`)
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200 && data.info) {
|
||||
const { frequency } = data.info;
|
||||
setLogRemoveFrequency(frequency);
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const updateRemoveLogFrequency = () => {
|
||||
setTimeout(() => {
|
||||
request
|
||||
.put(`${config.apiPrefix}system/log/remove`, {
|
||||
data: { frequency: logRemoveFrequency },
|
||||
})
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200) {
|
||||
message.success('更新成功');
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
className="ql-container-wrapper ql-container-wrapper-has-tab ql-setting-container"
|
||||
@@ -382,46 +318,11 @@ const Setting = () => {
|
||||
key: 'other',
|
||||
label: '其他设置',
|
||||
children: (
|
||||
<Form layout="vertical" form={form}>
|
||||
<Form.Item
|
||||
label="主题设置"
|
||||
name="theme"
|
||||
initialValue={defaultTheme}
|
||||
>
|
||||
<Radio.Group
|
||||
options={optionsWithDisabled}
|
||||
onChange={themeChange}
|
||||
value={defaultTheme}
|
||||
optionType="button"
|
||||
buttonStyle="solid"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="日志删除频率"
|
||||
name="frequency"
|
||||
tooltip="每x天自动删除x天以前的日志"
|
||||
>
|
||||
<Input.Group compact>
|
||||
<InputNumber
|
||||
addonBefore="每"
|
||||
addonAfter="天"
|
||||
style={{ width: 150 }}
|
||||
min={0}
|
||||
value={logRemoveFrequency}
|
||||
onChange={(value) => setLogRemoveFrequency(value)}
|
||||
/>
|
||||
<Button type="primary" onClick={updateRemoveLogFrequency}>
|
||||
确认
|
||||
</Button>
|
||||
</Input.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="检查更新" name="update">
|
||||
<CheckUpdate
|
||||
systemInfo={systemInfo}
|
||||
socketMessage={socketMessage}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<Other
|
||||
reloadTheme={reloadTheme}
|
||||
socketMessage={socketMessage}
|
||||
systemInfo={systemInfo}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, InputNumber, Form, Radio, message, Input } 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 './index.less';
|
||||
|
||||
const optionsWithDisabled = [
|
||||
{ label: '亮色', value: 'light' },
|
||||
{ label: '暗色', value: 'dark' },
|
||||
{ label: '跟随系统', value: 'auto' },
|
||||
];
|
||||
|
||||
const Other = ({
|
||||
systemInfo,
|
||||
socketMessage,
|
||||
reloadTheme,
|
||||
}: Pick<SharedContext, 'socketMessage' | 'reloadTheme' | 'systemInfo'>) => {
|
||||
const defaultTheme = localStorage.getItem('qinglong_dark_theme') || 'auto';
|
||||
const [logRemoveFrequency, setLogRemoveFrequency] = useState<number | null>();
|
||||
const [form] = Form.useForm();
|
||||
|
||||
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 getLogRemoveFrequency = () => {
|
||||
request
|
||||
.get(`${config.apiPrefix}system/log/remove`)
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200 && data.info) {
|
||||
const { frequency } = data.info;
|
||||
setLogRemoveFrequency(frequency);
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const updateRemoveLogFrequency = () => {
|
||||
setTimeout(() => {
|
||||
request
|
||||
.put(`${config.apiPrefix}system/log/remove`, {
|
||||
data: { frequency: logRemoveFrequency },
|
||||
})
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200) {
|
||||
message.success('更新成功');
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getLogRemoveFrequency();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Form layout="vertical" form={form}>
|
||||
<Form.Item label="主题设置" name="theme" initialValue={defaultTheme}>
|
||||
<Radio.Group
|
||||
options={optionsWithDisabled}
|
||||
onChange={themeChange}
|
||||
value={defaultTheme}
|
||||
optionType="button"
|
||||
buttonStyle="solid"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="日志删除频率"
|
||||
name="frequency"
|
||||
tooltip="每x天自动删除x天以前的日志"
|
||||
>
|
||||
<Input.Group compact>
|
||||
<InputNumber
|
||||
addonBefore="每"
|
||||
addonAfter="天"
|
||||
style={{ width: 150 }}
|
||||
min={0}
|
||||
value={logRemoveFrequency}
|
||||
onChange={(value) => setLogRemoveFrequency(value)}
|
||||
/>
|
||||
<Button type="primary" onClick={updateRemoveLogFrequency}>
|
||||
确认
|
||||
</Button>
|
||||
</Input.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="检查更新" name="update">
|
||||
<CheckUpdate systemInfo={systemInfo} socketMessage={socketMessage} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default Other;
|
||||
@@ -427,28 +427,26 @@ const Subscription = () => {
|
||||
arrow={{ pointAtCenter: true }}
|
||||
placement="bottomRight"
|
||||
trigger={['click']}
|
||||
overlay={
|
||||
<Menu
|
||||
items={[
|
||||
{ label: '编辑', key: 'edit', icon: <EditOutlined /> },
|
||||
{
|
||||
label: record.is_disabled === 1 ? '启用' : '禁用',
|
||||
key: 'enableOrDisable',
|
||||
icon:
|
||||
record.is_disabled === 1 ? (
|
||||
<CheckCircleOutlined />
|
||||
) : (
|
||||
<StopOutlined />
|
||||
),
|
||||
},
|
||||
{ label: '删除', key: 'delete', icon: <DeleteOutlined /> },
|
||||
]}
|
||||
onClick={({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
action(key, record, index);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
menu={{
|
||||
items: [
|
||||
{ label: '编辑', key: 'edit', icon: <EditOutlined /> },
|
||||
{
|
||||
label: record.is_disabled === 1 ? '启用' : '禁用',
|
||||
key: 'enableOrDisable',
|
||||
icon:
|
||||
record.is_disabled === 1 ? (
|
||||
<CheckCircleOutlined />
|
||||
) : (
|
||||
<StopOutlined />
|
||||
),
|
||||
},
|
||||
{ label: '删除', key: 'delete', icon: <DeleteOutlined /> },
|
||||
],
|
||||
onClick: ({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
action(key, record, index);
|
||||
},
|
||||
}}
|
||||
>
|
||||
<a onClick={(e) => e.stopPropagation()}>
|
||||
<EllipsisOutlined />
|
||||
|
||||
Reference in New Issue
Block a user