feat: 前后端+飞书全链路联调成功 - 创建项目自动发送飞书通知
This commit is contained in:
13
package-lock.json
generated
13
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
72
src/server/dev.ts
Normal 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}`);
|
||||
});
|
||||
Reference in New Issue
Block a user