脚本管理支持编辑删除文件

This commit is contained in:
hanhh 2021-08-19 14:18:25 +08:00
parent ff481ef7f3
commit 5e13264393
2 changed files with 176 additions and 4 deletions

View File

@ -70,7 +70,10 @@ export default (app: Router) => {
path += '/';
}
if (config.writePathList.every((x) => !path.startsWith(x))) {
return res.send({ code: 400, data: '文件路径错误,可保存目录/ql/scripts、/ql/config、/ql/jbot、/ql/bak' });
return res.send({
code: 400,
data: '文件路径错误,可保存目录/ql/scripts、/ql/config、/ql/jbot、/ql/bak',
});
}
const filePath = `${path}${filename.replace(/\//g, '')}`;
const bakPath = '/ql/bak';
@ -88,4 +91,52 @@ export default (app: Router) => {
}
},
);
route.put(
'/scripts',
celebrate({
body: Joi.object({
filename: Joi.string().required(),
content: Joi.string().required(),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
let { filename, content } = req.body as {
filename: string;
content: string;
};
const filePath = `${config.scriptPath}${filename}`;
fs.writeFileSync(filePath, content);
return res.send({ code: 200 });
} catch (e) {
logger.error('🔥 error: %o', e);
return next(e);
}
},
);
route.delete(
'/scripts',
celebrate({
body: Joi.object({
filename: Joi.string().required(),
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
let { filename } = req.body as {
filename: string;
};
const filePath = `${config.scriptPath}${filename}`;
fs.unlinkSync(filePath);
res.send({ code: 200 });
} catch (e) {
logger.error('🔥 error: %o', e);
return next(e);
}
},
);
};

View File

@ -1,5 +1,13 @@
import { useState, useEffect, useCallback, Key, useRef } from 'react';
import { TreeSelect, Tree, Input, Button } from 'antd';
import {
TreeSelect,
Tree,
Input,
Button,
Modal,
message,
Typography,
} from 'antd';
import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout';
import Editor from '@monaco-editor/react';
@ -10,6 +18,8 @@ import { Controlled as CodeMirror } from 'react-codemirror2';
import { useCtx, useTheme } from '@/utils/hooks';
import SplitPane from 'react-split-pane';
const { Text } = Typography;
function getFilterData(keyword: string, data: any) {
if (keyword) {
const tree: any = [];
@ -33,7 +43,7 @@ const LangMap: any = {
const Script = () => {
const [title, setTitle] = useState('请选择脚本文件');
const [value, setValue] = useState('请选择脚本文件');
const [select, setSelect] = useState();
const [select, setSelect] = useState<string>();
const [data, setData] = useState<any[]>([]);
const [filterData, setFilterData] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
@ -43,6 +53,9 @@ const Script = () => {
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
const { headerStyle, isPhone } = useCtx();
const { theme } = useTheme();
const [searchValue, setSearchValue] = useState('');
const [isEditing, setIsEditing] = useState(false);
const editorRef = useRef<any>(null);
const getScripts = () => {
setLoading(true);
@ -76,12 +89,102 @@ const Script = () => {
const onSearch = useCallback(
(e) => {
const keyword = e.target.value;
setSearchValue(keyword);
const { tree } = getFilterData(keyword.toLocaleLowerCase(), data);
setFilterData(tree);
},
[data, setFilterData],
);
const editFile = () => {
setIsEditing(true);
};
const saveFile = () => {
Modal.confirm({
title: `确认保存`,
content: (
<>
<Text style={{ wordBreak: 'break-all' }} type="warning">
{select}
</Text>{' '}
</>
),
onOk() {
const content = editorRef.current
? editorRef.current.getValue().replace(/\r\n/g, '\n')
: value;
request
.put(`${config.apiPrefix}scripts`, {
data: {
filename: select,
content,
},
})
.then((_data: any) => {
if (_data.code === 200) {
message.success(`保存成功`);
} else {
message.error(_data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const deleteFile = () => {
Modal.confirm({
title: `确认删除`,
content: (
<>
<Text style={{ wordBreak: 'break-all' }} type="warning">
{select}
</Text>{' '}
</>
),
onOk() {
request
.delete(`${config.apiPrefix}scripts`, {
data: {
filename: select,
},
})
.then((_data: any) => {
if (_data.code === 200) {
message.success(`删除成功`);
let newData = [...data];
const index = newData.findIndex((x) => x.value === select);
newData.splice(index, 1);
setData(newData);
} else {
message.error(_data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
useEffect(() => {
const word = searchValue || '';
const { tree } = getFilterData(word.toLocaleLowerCase(), data);
console.log(word);
console.log(tree);
setFilterData(tree);
setSelect('');
setTitle('请选择脚本文件');
setValue('请选择脚本文件');
}, [data]);
useEffect(() => {
getScripts();
setHeight(treeDom.current.clientHeight);
@ -105,8 +208,23 @@ const Script = () => {
key="value"
onSelect={onSelect}
/>,
<Button type="primary" onClick={deleteFile}>
</Button>,
]
: isEditing
? [
<Button type="primary" onClick={saveFile}>
</Button>,
]
: [
<Button type="primary" onClick={editFile}>
</Button>,
<Button type="primary" onClick={deleteFile}>
</Button>,
<Button
type="primary"
onClick={() => {
@ -145,12 +263,15 @@ const Script = () => {
value={value}
theme={theme}
options={{
readOnly: true,
readOnly: !isEditing,
fontSize: 12,
lineNumbersMinChars: 3,
folding: false,
glyphMargin: false,
}}
onMount={(editor) => {
editorRef.current = editor;
}}
/>
</SplitPane>
)}