-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
287 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<script setup lang="ts"> | ||
import { outputsStore, exportZip } from "@/workspace"; | ||
const items = [ | ||
{ name: "console", description: "控制台机器人" }, | ||
{ name: "onebot", description: "OneBot V11 & V12" }, | ||
]; | ||
const itemProps = (item: { name: string; description: string }) => { | ||
return { | ||
title: item.name, | ||
subtitle: item.description, | ||
}; | ||
}; | ||
const nameRules = [ | ||
(value: string) => { | ||
if (value) return true; | ||
return "请填写项目名称"; | ||
}, | ||
]; | ||
const presetRules = [ | ||
(value: string) => { | ||
if (value) return true; | ||
return "请选择一个预设"; | ||
}, | ||
]; | ||
const portRules = [ | ||
(value: string) => { | ||
if (!value) return "请填写端口"; | ||
if (!/^\d+$/.test(value)) return "端口必须为数字"; | ||
if (parseInt(value) < 1 || parseInt(value) > 65535) | ||
return "端口范围为 1-65535"; | ||
return true; | ||
}, | ||
]; | ||
</script> | ||
|
||
<template> | ||
<v-form> | ||
<v-container> | ||
<v-row> | ||
<v-col cols="12" md="4"> | ||
<v-text-field | ||
v-model="outputsStore.export.name" | ||
:counter="10" | ||
:rules="nameRules" | ||
label="项目名称" | ||
required | ||
></v-text-field> | ||
</v-col> | ||
<v-col cols="12" md="4"> | ||
<v-select | ||
v-model="outputsStore.export.preset" | ||
:item-props="itemProps" | ||
:items="items" | ||
:rules="presetRules" | ||
label="预设" | ||
required | ||
></v-select> | ||
</v-col> | ||
<v-col cols="12" md="4"> | ||
<v-text-field | ||
v-model="outputsStore.export.port" | ||
:rules="portRules" | ||
label="端口" | ||
required | ||
></v-text-field> | ||
</v-col> | ||
</v-row> | ||
|
||
<v-row> | ||
<v-col cols="12" md="4"> | ||
<v-checkbox | ||
v-model="outputsStore.export.platform" | ||
label="包含 Windows 环境配置脚本" | ||
value="windows" | ||
hide-details | ||
></v-checkbox> | ||
</v-col> | ||
<v-col cols="12" md="4"> | ||
<v-checkbox | ||
v-model="outputsStore.export.platform" | ||
label="包含 Linux 环境配置脚本" | ||
value="linux" | ||
hide-details | ||
></v-checkbox> | ||
</v-col> | ||
</v-row> | ||
|
||
<v-row> | ||
<v-col cols="12" md="12"> | ||
<v-btn class="mt-4" @click="exportZip" block> | ||
导出 NoneBot 项目 | ||
</v-btn> | ||
</v-col> | ||
</v-row> | ||
</v-container> | ||
</v-form> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,12 @@ export const outputsStore = reactive({ | |
snackbarMsg: "" as string, | ||
snackbarTimeout: 2500 as number, | ||
snackbarColor: "green" as string, | ||
export: { | ||
name: "app" as string, | ||
preset: { name: "console", description: "控制台机器人" }, | ||
port: 8080 as number, | ||
platform: ["windows", "linux"] as string[], | ||
}, | ||
}); | ||
|
||
export function setWorkspaceTheme(theme: string) { | ||
|
@@ -111,15 +117,175 @@ export function generateCode() { | |
outputsStore.code = pythonGenerator.workspaceToCode(workspace); | ||
} | ||
|
||
export function exportPress() { | ||
outputsStore.activeTab = "tab-3"; | ||
} | ||
|
||
function generatePyproject(code: string, preset: string) { | ||
const dependencies = new Set<string>([ | ||
"nonebot2[fastapi,httpx,websockets]>=2.3.3", | ||
"nb-cli>=1.4.2", | ||
]); | ||
const importLines = code.split("\n\n")[0].split("\n"); | ||
importLines.forEach((line) => { | ||
if (line.startsWith("from nonebot_plugin_alconna")) { | ||
dependencies.add("nonebot-plugin-alconna>=0.52.3"); | ||
} else if (line.startsWith("from nonebot_plugin_apscheduler")) { | ||
dependencies.add("nonebot-plugin-apscheduler>=0.5.0"); | ||
} else if (line.startsWith("import nonebot_plugin_localstore")) { | ||
dependencies.add("nonebot-plugin-localstore>=0.7.1"); | ||
} | ||
}); | ||
let adapters = ""; | ||
if (preset === "console") { | ||
adapters = '{ name = "Console", module_name = "nonebot.adapters.console" }'; | ||
dependencies.add("nonebot-adapter-console>=0.6.0"); | ||
} else if (preset === "onebot") { | ||
adapters = | ||
'{ name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" }'; | ||
adapters += | ||
', { name = "OneBot V12", module_name = "nonebot.adapters.onebot.v12" }'; | ||
dependencies.add("nonebot-adapter-onebot>=2.4.5"); | ||
} | ||
return `\ | ||
[project] | ||
name = "noneblockly-app" | ||
version = "0.1.0" | ||
description = "NoneBot project generated by NoneBlockly" | ||
authors = [{name = "name", email = "[email protected]"}] | ||
dependencies = [ | ||
${Array.from(dependencies) | ||
.map((dep) => `"${dep}"`) | ||
.join(", \n")} | ||
] | ||
requires-python = ">=3.9" | ||
license = {text = "MIT"} | ||
[tool.nonebot] | ||
adapters = [ | ||
{ name = "Console", module_name = "nonebot.adapters.console" } | ||
] | ||
plugin_dirs = ["plugins"]`; | ||
} | ||
|
||
function generateEnv(port: number) { | ||
return `\ | ||
DRIVER=~fastapi+~httpx+~websockets | ||
PORT=${port}`; | ||
} | ||
|
||
const windowsScripts = { | ||
install: `\ | ||
# Step 1: Check if 'uv' is installed | ||
$uvVersion = try { | ||
uv --version | ||
} catch { | ||
$null | ||
} | ||
if ($uvVersion) { | ||
Write-Host "UV is installed. Version: " | ||
Write-Host $uvVersion | ||
} else { | ||
# Step 2: If 'uv' is not installed, ask user for confirmation to install | ||
Write-Host "UV is not installed on this system." | ||
$confirmation = Read-Host "Do you want to install UV? (Press Enter to confirm or type 'n' to cancel)" | ||
if ($confirmation -eq '') { | ||
Write-Host "Installing UV..." | ||
Invoke-RestMethod https://astral.sh/uv/install.ps1 | Invoke-Expression | ||
Write-Host "UV has been installed successfully." | ||
} else { | ||
Write-Host "Installation canceled." | ||
exit | ||
} | ||
} | ||
# Step 3: Create a Python virtual environment | ||
Write-Host "Creating a Python virtual environment with Python 3.12..." | ||
uv venv --python 3.12 | ||
Write-Host "Python virtual environment created successfully." | ||
# Step 4: Install dependencies | ||
uv pip install -r pyproject.toml`, | ||
run: `\ | ||
$uvVersion = try { | ||
uv --version | ||
} catch { | ||
$null | ||
} | ||
if ($null -eq $uvVersion) { | ||
Write-Host "Please run 'install.ps1' first." | ||
exit | ||
} | ||
uv run nb run`, | ||
}; | ||
|
||
const linuxScripts = { | ||
install: `\ | ||
#!/bin/bash | ||
# Step 1: Check if 'uv' is installed | ||
if command -v uv &> /dev/null | ||
then | ||
echo "UV is installed. Version info:" | ||
uv --version | ||
else | ||
# Step 2: If 'uv' is not installed, ask user for confirmation to install | ||
echo "UV is not installed on this system." | ||
read -p "Do you want to install UV? (Press Enter to confirm or type 'n' to cancel): " confirmation | ||
if [ "$confirmation" == "" ]; then | ||
echo "Installing UV..." | ||
curl -LsSf https://astral.sh/uv/install.sh | sh | ||
echo "UV has been installed successfully." | ||
else | ||
echo "Installation canceled." | ||
exit 1 | ||
fi | ||
fi | ||
# Step 3: Create a Python virtual environment | ||
echo "Creating a Python virtual environment with Python 3.12..." | ||
uv venv --python 3.12 | ||
echo "Python virtual environment created successfully."`, | ||
run: `\ | ||
if ! command -v uv &> /dev/null | ||
then | ||
echo "Please run 'install.sh' first" | ||
exit | ||
fi | ||
uv run nb run`, | ||
}; | ||
|
||
export function exportZip() { | ||
let workspace = Blockly.getMainWorkspace(); | ||
let zip = new JSZip(); | ||
let workspace = Blockly.getMainWorkspace(); | ||
let code = pythonGenerator.workspaceToCode(workspace); | ||
zip.file("plugins/plugin_example.py", code); | ||
zip.file("plugins/plugin_exported.py", code); | ||
zip.file( | ||
"pyproject.toml", | ||
generatePyproject(code, outputsStore.export.preset.name), | ||
); | ||
zip.file(".env.prod", generateEnv(outputsStore.export.port)); | ||
outputsStore.export.platform.forEach((platform) => { | ||
if (platform === "windows") { | ||
zip.file("install.ps1", windowsScripts.install); | ||
zip.file("run.ps1", windowsScripts.run); | ||
} else if (platform === "linux") { | ||
zip.file("install.sh", linuxScripts.install); | ||
zip.file("run.sh", linuxScripts.run); | ||
} | ||
}); | ||
outputsStore.snackbarColor = "green"; | ||
outputsStore.snackbarMsg = "😎 已导出 Python 项目"; | ||
outputsStore.snackbar = true; | ||
zip.generateAsync({ type: "blob" }).then(function (content) { | ||
saveAs(content, "noneblockly.zip"); | ||
saveAs(content, `${outputsStore.export.name}.zip`); | ||
}); | ||
} |