前端添加代码编辑器主题 缩略图
This commit is contained in:
parent
6eb66b4c18
commit
7b556668d2
@ -29,3 +29,11 @@ export function saveFileContent(data: Api.File.SaveFileRequest) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchInitProject(data: Api.File.InitProjectRequest) {
|
||||||
|
return request<Api.File.FileContent>({
|
||||||
|
url: '/file/init/project',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -8,18 +8,16 @@ export function runPythonCommand(data: Api.Python.SaveFileRequest) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pythonCommand3(data: Api.Python.SaveFileRequest) {
|
export function pythonCommand3() {
|
||||||
return request<boolean>({
|
return request<boolean>({
|
||||||
url: '/python/stop',
|
url: '/python/stop',
|
||||||
method: 'post',
|
method: 'post'
|
||||||
data
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchPythonStatus(data: Api.Python.SaveFileRequest) {
|
export function fetchPythonStatus() {
|
||||||
return request<boolean>({
|
return request<boolean>({
|
||||||
url: '/python/status',
|
url: '/python/status',
|
||||||
method: 'get',
|
method: 'get'
|
||||||
data
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
5
src/typings/api.d.ts
vendored
5
src/typings/api.d.ts
vendored
@ -1260,6 +1260,11 @@ declare namespace Api {
|
|||||||
filePath: string;
|
filePath: string;
|
||||||
content: string;
|
content: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type InitProjectRequest = Common.CommonRecord<{
|
||||||
|
projectName: string;
|
||||||
|
projectUrl: string;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Python {
|
namespace Python {
|
||||||
|
@ -5,6 +5,7 @@ import { Folder, FolderOpenOutline } from '@vicons/ionicons5';
|
|||||||
import { NIcon } from 'naive-ui';
|
import { NIcon } from 'naive-ui';
|
||||||
import MonacoEditor from '@/components/common/monaco-editor.vue';
|
import MonacoEditor from '@/components/common/monaco-editor.vue';
|
||||||
import {
|
import {
|
||||||
|
fetchInitProject,
|
||||||
fetchListFiles,
|
fetchListFiles,
|
||||||
fetchPythonStatus,
|
fetchPythonStatus,
|
||||||
fetchViewFile,
|
fetchViewFile,
|
||||||
@ -14,26 +15,66 @@ import {
|
|||||||
} from '@/service/api';
|
} from '@/service/api';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import { fetchQuickPublish } from '@/service/api/docker';
|
import { fetchQuickPublish } from '@/service/api/docker';
|
||||||
|
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||||
|
|
||||||
const code = ref(`Hello SnailJob`);
|
const code = ref(`Hello SnailJob`);
|
||||||
const dataRef = ref(createData());
|
const dataRef = ref();
|
||||||
const curFile = ref<TreeOption>();
|
const curFile = ref<TreeOption>();
|
||||||
const pyStatus = ref<boolean>(false);
|
const theme = ref('vs');
|
||||||
|
const eol = ref(0);
|
||||||
|
const wordWrap = ref('on');
|
||||||
|
const minimap = ref('true');
|
||||||
|
const themes = [
|
||||||
|
{
|
||||||
|
label: 'Visual Studio',
|
||||||
|
value: 'vs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Visual Studio Dark',
|
||||||
|
value: 'vs-dark'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'High Contrast Dark',
|
||||||
|
value: 'hc-black'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
function createData() {
|
const eols = [
|
||||||
return [
|
{
|
||||||
{
|
label: 'LF (Linux)',
|
||||||
label: 'snail-job-python',
|
value: 0
|
||||||
key: 'snail-job-python',
|
},
|
||||||
isLeaf: false,
|
{
|
||||||
prefix: () => {
|
label: 'CRLF (Windows)',
|
||||||
return h(NIcon, null, {
|
value: 1
|
||||||
default: () => h(Folder)
|
}
|
||||||
});
|
];
|
||||||
}
|
|
||||||
}
|
const wordWraps = [
|
||||||
];
|
{
|
||||||
}
|
label: '启用',
|
||||||
|
value: 'on'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '关闭',
|
||||||
|
value: 'off'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const minimaps = [
|
||||||
|
{
|
||||||
|
label: '启用',
|
||||||
|
value: 'true'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '关闭',
|
||||||
|
value: 'false'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const pyStatus = defineModel<boolean>('pyStatus', {
|
||||||
|
default: false
|
||||||
|
});
|
||||||
|
|
||||||
const updatePrefixWithExpaned = (
|
const updatePrefixWithExpaned = (
|
||||||
_keys: Array<string | number>,
|
_keys: Array<string | number>,
|
||||||
@ -60,6 +101,22 @@ const updatePrefixWithExpaned = (
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { formRef, validate } = useNaiveForm();
|
||||||
|
const { defaultRequiredRule } = useFormRules();
|
||||||
|
|
||||||
|
type Model = Pick<Api.File.InitProjectRequest, 'projectName' | 'projectUrl'>;
|
||||||
|
type RuleKey = Extract<keyof Model, 'projectName' | 'projectUrl'>;
|
||||||
|
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||||
|
projectName: defaultRequiredRule,
|
||||||
|
projectUrl: defaultRequiredRule
|
||||||
|
};
|
||||||
|
|
||||||
|
const model: Model = reactive({
|
||||||
|
projectName: 'project',
|
||||||
|
projectUrl: 'https://github.com/open-snail/python-client/archive/refs/tags/v0.0.1.zip'
|
||||||
|
});
|
||||||
|
|
||||||
const nodeProps = ({ option }: { option: TreeOption }) => {
|
const nodeProps = ({ option }: { option: TreeOption }) => {
|
||||||
return {
|
return {
|
||||||
onClick() {
|
onClick() {
|
||||||
@ -71,6 +128,14 @@ const nodeProps = ({ option }: { option: TreeOption }) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
await validate();
|
||||||
|
const { projectName, projectUrl } = model;
|
||||||
|
const { error } = await fetchInitProject({ projectName, projectUrl });
|
||||||
|
if (error) return;
|
||||||
|
window.$message?.success($t('common.addSuccess'));
|
||||||
|
}
|
||||||
|
|
||||||
async function getViewFile(option: TreeOption) {
|
async function getViewFile(option: TreeOption) {
|
||||||
if (option.isLeaf) {
|
if (option.isLeaf) {
|
||||||
const res = await fetchViewFile(option.key as string);
|
const res = await fetchViewFile(option.key as string);
|
||||||
@ -141,65 +206,18 @@ async function onLoad(node: TreeOption) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
type Model = Pick<Api.File.SaveFileRequest, 'fileName' | 'filePath' | 'content'>;
|
|
||||||
|
|
||||||
const model: Model = reactive(createDefaultModel());
|
|
||||||
|
|
||||||
function createDefaultModel(): Model {
|
|
||||||
return {
|
|
||||||
fileName: curFile.value?.key as string,
|
|
||||||
filePath: curFile.value?.label as string,
|
|
||||||
content: code.value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveFile() {
|
|
||||||
model.fileName = curFile.value?.key as string;
|
|
||||||
model.filePath = curFile.value?.label as string;
|
|
||||||
model.content = code.value;
|
|
||||||
|
|
||||||
const { fileName, filePath, content } = model;
|
|
||||||
const { error } = await saveFileContent({ fileName, filePath, content });
|
|
||||||
if (error) {
|
|
||||||
window.$message?.success($t('common.updateFailed'));
|
|
||||||
} else {
|
|
||||||
window.$message?.success($t('common.updateSuccess'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PythonModel = Pick<Api.Python.SaveFileRequest, 'pythonPath' | 'command'>;
|
|
||||||
|
|
||||||
const pythonModel: PythonModel = reactive(createPythonModelModel());
|
|
||||||
|
|
||||||
function createPythonModelModel(): PythonModel {
|
|
||||||
return {
|
|
||||||
pythonPath: '',
|
|
||||||
command: 'pip3 install -r && python3 ' /// ToDo 这里需要做配置
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function codeUpdate(content: string) {
|
function codeUpdate(content: string) {
|
||||||
code.value = content;
|
code.value = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveFileClick() {
|
async function saveFileClick() {
|
||||||
saveFile();
|
const { error } = await saveFileContent(
|
||||||
}
|
reactive<Api.File.SaveFileRequest>({
|
||||||
|
fileName: curFile.value?.key as string,
|
||||||
async function runPython() {
|
filePath: curFile.value?.label as string,
|
||||||
pythonModel.pythonPath = curFile.value?.key as string;
|
content: code.value
|
||||||
|
})
|
||||||
const { pythonPath, command } = pythonModel;
|
);
|
||||||
const { error } = await runPythonCommand({ pythonPath, command });
|
|
||||||
if (error) {
|
|
||||||
window.$message?.success($t('common.updateFailed'));
|
|
||||||
} else {
|
|
||||||
window.$message?.success($t('common.updateSuccess'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function stopPython() {
|
|
||||||
const { error } = await pythonCommand3(pythonModel);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
window.$message?.success($t('common.updateFailed'));
|
window.$message?.success($t('common.updateFailed'));
|
||||||
} else {
|
} else {
|
||||||
@ -208,7 +226,7 @@ async function stopPython() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function pythonStatus() {
|
async function pythonStatus() {
|
||||||
const { error, data } = await fetchPythonStatus(pythonModel);
|
const { error, data } = await fetchPythonStatus();
|
||||||
if (error) {
|
if (error) {
|
||||||
window.$message?.success($t('common.updateFailed'));
|
window.$message?.success($t('common.updateFailed'));
|
||||||
} else {
|
} else {
|
||||||
@ -216,20 +234,40 @@ async function pythonStatus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerRequestModel = Pick<Api.Docker.CreateContainerRequest, 'groupName' | 'namespaceId' | 'imageName'>;
|
async function runPythonClick() {
|
||||||
|
const { error } = await runPythonCommand(
|
||||||
const containerRequestModel: ContainerRequestModel = reactive(createContainerRequestModelModel());
|
reactive<Api.Python.SaveFileRequest>({
|
||||||
|
pythonPath: curFile.value?.key as string,
|
||||||
function createContainerRequestModelModel(): ContainerRequestModel {
|
command: 'pip3 install -r && python3 ' /// ToDo 这里需要做配置
|
||||||
return {
|
})
|
||||||
groupName: 'snail_job_demo_group',
|
);
|
||||||
namespaceId: '764d604ec6fc45f68cd92514c40e9e1a', /// ToDo 这里需要做配置
|
if (error) {
|
||||||
imageName: ''
|
window.$message?.success($t('common.updateFailed'));
|
||||||
};
|
} else {
|
||||||
|
window.$message?.success($t('common.updateSuccess'));
|
||||||
|
pyStatus.value = true;
|
||||||
|
}
|
||||||
|
// pythonStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function quickPublish() {
|
async function stopPythonClick() {
|
||||||
const { error } = await fetchQuickPublish(containerRequestModel);
|
const { error } = await pythonCommand3();
|
||||||
|
if (error) {
|
||||||
|
window.$message?.success($t('common.updateFailed'));
|
||||||
|
} else {
|
||||||
|
window.$message?.success($t('common.updateSuccess'));
|
||||||
|
}
|
||||||
|
pythonStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function quickPublishClick() {
|
||||||
|
const { error } = await fetchQuickPublish(
|
||||||
|
reactive<Api.Docker.CreateContainerRequest>({
|
||||||
|
groupName: 'snail_job_demo_group',
|
||||||
|
namespaceId: '764d604ec6fc45f68cd92514c40e9e1a', /// ToDo 这里需要做配置
|
||||||
|
imageName: ''
|
||||||
|
})
|
||||||
|
);
|
||||||
if (error) {
|
if (error) {
|
||||||
window.$message?.success($t('common.updateFailed'));
|
window.$message?.success($t('common.updateFailed'));
|
||||||
} else {
|
} else {
|
||||||
@ -237,41 +275,57 @@ async function quickPublish() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runPythonClick() {
|
onMounted(async () => {
|
||||||
runPython();
|
const res = await fetchListFiles('');
|
||||||
pythonStatus();
|
const files = res.data as Api.File.FileInfo[];
|
||||||
}
|
dataRef.value = [
|
||||||
|
{
|
||||||
function stopPythonClick() {
|
label: files[0].fileName,
|
||||||
stopPython();
|
key: files[0].fileName,
|
||||||
pythonStatus();
|
isLeaf: false,
|
||||||
}
|
prefix: () => {
|
||||||
|
return h(NIcon, null, {
|
||||||
function quickPublishClick() {
|
default: () => h(Folder)
|
||||||
quickPublish();
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onMounted(() => {
|
];
|
||||||
pythonStatus();
|
await pythonStatus();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="code-editor">
|
<div v-if="dataRef">
|
||||||
<NSpace>
|
<NCard>
|
||||||
<NButton strong secondary type="primary" @click="saveFileClick">保存</NButton>
|
<NGrid x-gap="12" :cols="4">
|
||||||
<NButton v-if="pyStatus" strong secondary type="primary" @click="stopPythonClick">停止</NButton>
|
<NGi>
|
||||||
<NButton v-else strong secondary type="primary" @click="runPythonClick">运行</NButton>
|
主题: <NSelect v-model:value="theme" :options="themes" />
|
||||||
<NButton strong secondary type="primary" @click="quickPublishClick">一键发布</NButton>
|
</NGi>
|
||||||
</NSpace>
|
<NGi>
|
||||||
|
<NSelect v-model:value="eol" :options="eols" />
|
||||||
|
</NGi>
|
||||||
|
<NGi>
|
||||||
|
<NSelect v-model:value="wordWrap" :options="wordWraps" />
|
||||||
|
</NGi>
|
||||||
|
<NGi>
|
||||||
|
<NSelect v-model:value="minimap" :options="minimaps" />
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
<br/>
|
||||||
|
<NSpace reverse>
|
||||||
|
<NButton strong secondary type="success" @click="quickPublishClick">一键发布</NButton>
|
||||||
|
<NButton v-if="pyStatus" strong secondary type="error" @click="stopPythonClick">停止</NButton>
|
||||||
|
<NButton v-else strong secondary type="info" @click="runPythonClick">运行</NButton>
|
||||||
|
<NButton strong secondary type="warning" @click="saveFileClick">保存</NButton>
|
||||||
|
</NSpace>
|
||||||
|
</NCard>
|
||||||
<NLayout has-sider>
|
<NLayout has-sider>
|
||||||
<NLayoutSider
|
<NLayoutSider
|
||||||
collapse-mode="transform"
|
collapse-mode="transform"
|
||||||
:collapsed-width="120"
|
:collapsed-width="120"
|
||||||
:width="240"
|
:width="240"
|
||||||
show-trigger="bar"
|
show-trigger="bar"
|
||||||
content-style="padding: 24px;"
|
content-style="padding-top: 12px;"
|
||||||
bordered
|
bordered
|
||||||
>
|
>
|
||||||
<NTree
|
<NTree
|
||||||
@ -297,6 +351,23 @@ onMounted(() => {
|
|||||||
</NLayoutContent>
|
</NLayoutContent>
|
||||||
</NLayout>
|
</NLayout>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<NForm ref="formRef" :model="model" :rules="rules">
|
||||||
|
<NFormItem path="projectName" label="项目名称">
|
||||||
|
<NInput v-model:value="model.projectName" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem path="项目地址" label="项目地址">
|
||||||
|
<NInput v-model:value="model.projectUrl" />
|
||||||
|
</NFormItem>
|
||||||
|
<NRow :gutter="[0, 24]">
|
||||||
|
<NCol :span="24">
|
||||||
|
<div style="display: flex; justify-content: flex-end">
|
||||||
|
<NButton type="primary" @click="handleSubmit">{{ $t('common.save') }}</NButton>
|
||||||
|
</div>
|
||||||
|
</NCol>
|
||||||
|
</NRow>
|
||||||
|
</NForm>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
Loading…
Reference in New Issue
Block a user