添加openapi模块

This commit is contained in:
hanhh
2021-08-26 19:01:39 +08:00
parent 7739cef7b8
commit 1e58254f4c
12 changed files with 730 additions and 47 deletions
+80
View File
@@ -0,0 +1,80 @@
import React, { useEffect, useState } from 'react';
import { Modal, message, Input, Form, Select } from 'antd';
import { request } from '@/utils/http';
import config from '@/utils/config';
const AppModal = ({
app,
handleCancel,
visible,
}: {
app?: any;
visible: boolean;
handleCancel: (needUpdate?: boolean) => void;
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const handleOk = async (values: any) => {
setLoading(true);
const method = app ? 'put' : 'post';
const payload = { ...values };
if (app) {
payload._id = app._id;
}
const { code, data } = await request[method](`${config.apiPrefix}apps`, {
data: payload,
});
if (code === 200) {
message.success(app ? '更新应用成功' : '添加应用成功');
} else {
message.error(data);
}
setLoading(false);
handleCancel(data);
};
useEffect(() => {
form.resetFields();
}, [app, visible]);
return (
<Modal
title={app ? '编辑应用' : '新建应用'}
visible={visible}
forceRender
onOk={() => {
form
.validateFields()
.then((values) => {
handleOk(values);
})
.catch((info) => {
console.log('Validate Failed:', info);
});
}}
onCancel={() => handleCancel()}
confirmLoading={loading}
>
<Form
form={form}
layout="vertical"
name="form_app_modal"
initialValues={app}
>
<Form.Item name="name" label="名称">
<Input placeholder="请输入应用名称" />
</Form.Item>
<Form.Item name="scopes" label="权限" rules={[{ required: true }]}>
<Select mode="multiple" allowClear style={{ width: '100%' }}>
{config.scopes.map((x) => {
return <Select.Option value={x.value}>{x.name}</Select.Option>;
})}
</Select>
</Form.Item>
</Form>
</Modal>
);
};
export default AppModal;
+224 -9
View File
@@ -1,5 +1,18 @@
import React, { useState, useEffect } from 'react';
import { Button, Input, Form, Radio, Tabs } from 'antd';
import {
Button,
Input,
Form,
Radio,
Tabs,
Table,
Tooltip,
Space,
Tag,
Modal,
message,
Typography,
} from 'antd';
import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout';
import { request } from '@/utils/http';
@@ -10,19 +23,87 @@ import {
setFetchMethod,
} from 'darkreader';
import { history } from 'umi';
import { useCtx } from '@/utils/hooks';
import AppModal from './appModal';
import {
EditOutlined,
DeleteOutlined,
ReloadOutlined,
} from '@ant-design/icons';
const { Text } = Typography;
const optionsWithDisabled = [
{ label: '亮色', value: 'light' },
{ label: '暗色', value: 'dark' },
{ label: '跟随系统', value: 'auto' },
];
const Password = ({ headerStyle, isPhone }: any) => {
const [value, setValue] = useState('');
const Setting = ({ headerStyle, isPhone }: any) => {
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
align: 'center' as const,
},
{
title: 'Client ID',
dataIndex: 'client_id',
key: 'client_id',
align: 'center' as const,
},
{
title: 'Client Secret',
dataIndex: 'client_secret',
key: 'client_secret',
align: 'center' as const,
},
{
title: '权限',
dataIndex: 'scopes',
key: 'scopes',
align: 'center' as const,
render: (text: string, record: any) => {
return record.scopes.map((scope: any) => {
return <Tag key={scope}>{(config.scopesMap as any)[scope]}</Tag>;
});
},
},
{
title: '操作',
key: 'action',
align: 'center' as const,
render: (text: string, record: any, index: number) => {
const isPc = !isPhone;
return (
<Space size="middle" style={{ paddingLeft: 8 }}>
<Tooltip title={isPc ? '编辑' : ''}>
<a onClick={() => editApp(record, index)}>
<EditOutlined />
</a>
</Tooltip>
<Tooltip title={isPc ? '重置secret' : ''}>
<a onClick={() => resetSecret(record, index)}>
<ReloadOutlined />
</a>
</Tooltip>
<Tooltip title={isPc ? '删除' : ''}>
<a onClick={() => deleteApp(record, index)}>
<DeleteOutlined />
</a>
</Tooltip>
</Space>
);
},
},
];
const [loading, setLoading] = useState(true);
const defaultDarken = localStorage.getItem('qinglong_dark_theme') || 'auto';
const [theme, setTheme] = useState(defaultDarken);
const [dataSource, setDataSource] = useState<any[]>([]);
const [isModalVisible, setIsModalVisible] = useState(false);
const [editedApp, setEditedApp] = useState();
const [tabActiveKey, setTabActiveKey] = useState('person');
const handleOk = (values: any) => {
request
@@ -46,12 +127,116 @@ const Password = ({ headerStyle, isPhone }: any) => {
localStorage.setItem('qinglong_dark_theme', e.target.value);
};
const importJob = () => {
request.get(`${config.apiPrefix}crons/import`).then((data: any) => {
console.log(data);
const getApps = () => {
setLoading(true);
request
.get(`${config.apiPrefix}apps`)
.then((data: any) => {
setDataSource(data.data);
})
.finally(() => setLoading(false));
};
const addApp = () => {
setIsModalVisible(true);
};
const editApp = (record: any, index: number) => {
setEditedApp(record);
setIsModalVisible(true);
};
const deleteApp = (record: any, index: number) => {
Modal.confirm({
title: '确认删除',
content: (
<>
{' '}
<Text style={{ wordBreak: 'break-all' }} type="warning">
{record.name}
</Text>{' '}
</>
),
onOk() {
request
.delete(`${config.apiPrefix}apps`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
message.success('删除成功');
const result = [...dataSource];
result.splice(index, 1);
setDataSource(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const resetSecret = (record: any, index: number) => {
Modal.confirm({
title: '确认重置',
content: (
<>
{' '}
<Text style={{ wordBreak: 'break-all' }} type="warning">
{record.name}
</Text>{' '}
Secret吗
<br />
<Text type="secondary">Secret会让当前应用所有token失效</Text>
</>
),
onOk() {
request
.put(`${config.apiPrefix}apps/${record._id}/reset-secret`)
.then((data: any) => {
if (data.code === 200) {
message.success('重置成功');
handleApp(data.data);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const handleCancel = (app?: any) => {
setIsModalVisible(false);
if (app) {
handleApp(app);
}
};
const handleApp = (app: any) => {
const index = dataSource.findIndex((x) => x._id === app._id);
const result = [...dataSource];
if (index === -1) {
result.push(app);
} else {
result.splice(index, 1, {
...app,
});
}
setDataSource(result);
};
const tabChange = (activeKey: string) => {
setTabActiveKey(activeKey);
if (activeKey === 'app') {
getApps();
}
};
useEffect(() => {
setFetchMethod(window.fetch);
if (theme === 'dark') {
@@ -70,8 +255,22 @@ const Password = ({ headerStyle, isPhone }: any) => {
header={{
style: headerStyle,
}}
extra={
tabActiveKey === 'app'
? [
<Button key="2" type="primary" onClick={() => addApp()}>
</Button>,
]
: []
}
>
<Tabs defaultActiveKey="person" size="small" tabPosition="top">
<Tabs
defaultActiveKey="person"
size="small"
tabPosition="top"
onChange={tabChange}
>
<Tabs.TabPane tab="个人设置" key="person">
<Form onFinish={handleOk} layout="vertical">
<Form.Item
@@ -97,6 +296,17 @@ const Password = ({ headerStyle, isPhone }: any) => {
</Button>
</Form>
</Tabs.TabPane>
<Tabs.TabPane tab="应用设置" key="app">
<Table
columns={columns}
pagination={false}
dataSource={dataSource}
rowKey="_id"
size="middle"
scroll={{ x: 768 }}
loading={loading}
/>
</Tabs.TabPane>
<Tabs.TabPane tab="其他设置" key="theme">
<Form layout="vertical">
<Form.Item label="主题设置" name="theme" initialValue={theme}>
@@ -111,8 +321,13 @@ const Password = ({ headerStyle, isPhone }: any) => {
</Form>
</Tabs.TabPane>
</Tabs>
<AppModal
visible={isModalVisible}
handleCancel={handleCancel}
app={editedApp}
/>
</PageContainer>
);
};
export default Password;
export default Setting;
+29
View File
@@ -34,4 +34,33 @@ export default {
],
defaultLanguage: 'en',
},
scopes: [
{
name: '定时任务',
value: 'crons',
},
{
name: '环境变量',
value: 'envs',
},
{
name: '配置文件',
value: 'configs',
},
{
name: '脚本管理',
value: 'scripts',
},
{
name: '任务日志',
value: 'logs',
},
],
scopesMap: {
crons: '定时任务',
envs: '环境变量',
configs: '配置文件',
scripts: '脚本管理',
logs: '任务日志',
},
};