feat: 完成分类、worksheet 接口开发,资源迁移到七牛

This commit is contained in:
R524809
2026-10-16 17:32:23 +08:00
parent e6ded00a4c
commit 8827110f2f
107 changed files with 12775 additions and 125 deletions
+69
View File
@@ -0,0 +1,69 @@
import { spawn } from 'node:child_process';
import { createRequire } from 'node:module';
import { createInterface } from 'node:readline';
const require = createRequire(import.meta.url);
const child = spawn(
process.execPath,
[require.resolve('@nestjs/cli/bin/nest.js'), 'start', '--watch'],
{
env: { ...process.env, DOODLE_DEV_LAUNCHER: '1' },
stdio: ['inherit', 'pipe', 'inherit'],
},
);
let opened = false;
/** 使用系统默认浏览器,不经 shell 拼接 URL;打开失败不影响开发服务继续运行。 */
function openBrowser(url) {
const command =
process.platform === 'darwin'
? 'open'
: process.platform === 'win32'
? 'explorer.exe'
: 'xdg-open';
const browser = spawn(command, [url], { stdio: 'ignore', detached: true });
const warn = () =>
process.stderr.write(`无法自动打开浏览器,请手动访问:${url}\n`);
browser.once('error', warn);
browser.once('exit', (code) => {
if (code !== 0 && code !== null) warn();
});
browser.unref();
}
// 只在本次启动器收到子服务的成功通知后打开;热更新重启不会反复弹出页面。
const lines = createInterface({ input: child.stdout });
lines.on('line', (line) => {
let event;
try {
event = JSON.parse(line);
} catch {
/* Nest 编译提示不是 JSON,原样转发。 */
}
if (event?.event !== 'doodle-dev-ready') {
process.stdout.write(`${line}\n`);
return;
}
if (!event.swaggerUrl) {
process.stdout.write('\nSwagger 已关闭(SWAGGER_ENABLED=false)。\n\n');
return;
}
process.stdout.write(`\nSwagger: ${event.swaggerUrl}\n\n`);
if (!opened) {
opened = true;
openBrowser(event.swaggerUrl);
}
});
// 退出启动器时将信号传给 Nest,保留其对子服务的正常关闭和端口释放流程。
for (const signal of ['SIGINT', 'SIGTERM'])
process.on(signal, () => child.kill(signal));
child.once('error', () => {
process.stderr.write('开发服务启动失败,请检查本地 Node.js 与项目依赖。\n');
process.exitCode = 1;
});
child.once('exit', (code, signal) => {
lines.close();
process.exitCode =
code ?? (signal === 'SIGINT' ? 130 : signal === 'SIGTERM' ? 143 : 1);
});