feat: 前后端+飞书全链路联调成功 - 创建项目自动发送飞书通知
Some checks failed
CI / lint-and-typecheck (push) Failing after 33s
CI / test (push) Has been skipped
CI / build (push) Has been skipped

This commit is contained in:
2026-04-12 02:08:02 +08:00
parent 28340b23c1
commit ab0154bcf9
4 changed files with 107 additions and 4 deletions

13
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "0.5.0",
"dependencies": {
"@arco-design/web-react": "^2.66.0",
"@hono/node-server": "^1.19.13",
"@larksuiteoapi/node-sdk": "^1.60.0",
"hono": "^4.7.0",
"react": "^18.3.0",
@@ -1020,6 +1021,18 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@hono/node-server": {
"version": "1.19.13",
"resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.13.tgz",
"integrity": "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==",
"license": "MIT",
"engines": {
"node": ">=18.14.1"
},
"peerDependencies": {
"hono": "^4"
}
},
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz",

View File

@@ -14,6 +14,7 @@
},
"dependencies": {
"@arco-design/web-react": "^2.66.0",
"@hono/node-server": "^1.19.13",
"@larksuiteoapi/node-sdk": "^1.60.0",
"hono": "^4.7.0",
"react": "^18.3.0",

View File

@@ -185,13 +185,29 @@ const WizardPage: React.FC = () => {
const [project, setProject] = useState<ProjectData>(createEmptyProject());
const [submitted, setSubmitted] = useState(false);
const [submitting, setSubmitting] = useState(false);
const next = () => setCurrent(Math.min(current + 1, STEPS.length - 1));
const prev = () => setCurrent(Math.max(current - 1, 0));
const handleSubmit = () => {
setSubmitted(true);
Message.success(`项目「${project.name}」已创建!`);
console.log('Project created:', project);
const handleSubmit = async () => {
setSubmitting(true);
try {
const res = await fetch('/api/projects', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(project),
});
const data = await res.json();
setSubmitted(true);
Message.success(`项目「${project.name}」已创建!飞书通知已发送。`);
console.log('Project created:', data);
} catch (err) {
Message.error('创建失败,请重试');
console.error('Failed to create project:', err);
} finally {
setSubmitting(false);
}
};
const renderStep = () => {
@@ -328,6 +344,7 @@ const WizardPage: React.FC = () => {
type="primary"
onClick={handleSubmit}
disabled={!project.name || !project.goal}
loading={submitting}
>
</Button>

72
src/server/dev.ts Normal file
View File

@@ -0,0 +1,72 @@
// Dev server entry - runs Hono on Node.js
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { executionApiHandlers } from './execution-api';
import { handleDecompose, handleFeishuCallback } from './index';
import { sendFeishuMessage, notifyProjectCreated, notifyMilestoneReminder, notifyRiskAlert, sendDecisionCard } from './feishu';
import { handleDecisionCallback, createDecision, getPendingDecisions, DECISION_TEMPLATES } from '../lib/decision-cards';
const projects: Record<string, any> = {};
const app = new Hono();
app.use('*', cors());
app.use('*', logger());
app.get('/api/health', (c) => c.json({ status: 'ok', version: '0.5.0', message: 'FlowPilot API is running' }));
// Create project + send Feishu notification
app.post('/api/projects', async (c) => {
const body = await c.req.json();
const projectId = `proj-${Date.now()}`;
const project = { id: projectId, ...body, status: 'active', createdAt: new Date().toISOString() };
projects[projectId] = project;
// Send Feishu notification
try {
await notifyProjectCreated(project.name || '未命名项目', project.goal || '', 'ou_41d14aca8278e605d98e33b1221777e4', 'open_id');
console.log('✅ Feishu notification sent for project:', project.name);
} catch (e: any) {
console.error('❌ Feishu notification failed:', e.message);
}
return c.json(project);
});
app.get('/api/projects/:id', (c) => c.json(projects[c.req.param('id')] || { error: 'not found' }));
app.get('/api/projects/:id/tasks', (c) => c.json({ tasks: [], projectId: c.req.param('id') }));
app.post('/api/projects/:id/tasks', async (c) => {
const body = await c.req.json();
return c.json({ id: `task-${Date.now()}`, projectId: c.req.param('id'), ...body, status: 'todo', createdAt: new Date().toISOString() });
});
app.patch('/api/projects/:id/tasks/:taskId', async (c) => {
const body = await c.req.json();
return c.json({ id: c.req.param('taskId'), ...body, updatedAt: new Date().toISOString() });
});
app.get('/api/projects/:id/executions', (c) => c.json({ executions: executionApiHandlers.getExecutions(c.req.param('id')) }));
app.post('/api/projects/:id/executions', async (c) => { const b = await c.req.json(); return c.json(executionApiHandlers.createExecution(c.req.param('id'), b), 201); });
app.get('/api/projects/:id/stats', (c) => c.json(executionApiHandlers.getStats(c.req.param('id'))));
app.post('/api/projects/:id/decompose', async (c) => {
const b = await c.req.json();
return c.json(handleDecompose(b.task, b.context));
});
app.get('/api/projects/:id/decisions', (c) => c.json({ decisions: executionApiHandlers.getDecisions(c.req.param('id')) }));
app.post('/api/projects/:id/decisions', async (c) => { const b = await c.req.json(); return c.json(executionApiHandlers.createDecision(c.req.param('id'), b), 201); });
app.post('/api/feishu/webhook', async (c) => { const e = await c.req.json(); return c.json(handleFeishuCallback(e)); });
app.post('/api/feishu/decision/callback', async (c) => { const b = await c.req.json(); console.log('Decision callback:', JSON.stringify(b)); return c.json({ ok: true }); });
// Start with Node.js native http
const port = Number(process.env.PORT) || 3001;
import { createServer } from 'http';
import { serve } from '@hono/node-server';
serve({ fetch: app.fetch, port }, () => {
console.log(`🚀 FlowPilot API running on http://localhost:${port}`);
});