goals.js 3.12 KB
/**
 * Goals API — OKR 目标管理路由
 *
 * GET    /api/goals                      → 列出所有目标
 * POST   /api/goals                      → 创建新目标
 * GET    /api/goals/:goalId              → 获取完整 OKR 树
 * PUT    /api/goals/:goalId              → 更新目标元数据
 * POST   /api/goals/:goalId/nodes        → 添加节点
 * GET    /api/goals/:goalId/nodes/:nodeId → 获取节点 + 上下文
 * PUT    /api/goals/:goalId/nodes/:nodeId → 更新节点状态
 * GET    /api/goals/:goalId/progress     → 获取进度统计
 *
 * 参考: docs/architecture-v5.md 第二章
 */

const { Router } = require('express');
const { GoalsService } = require('../services/goals');

const router = Router();
const goals = new GoalsService();

// ── 列出所有目标 ──
router.get('/', (req, res) => {
  res.json(goals.list());
});

// ── 创建新目标 ──
router.post('/', (req, res) => {
  try {
    const { title, description, owner } = req.body;
    if (!title || !owner) {
      return res.status(400).json({ error: 'title and owner are required' });
    }
    const goal = goals.create({ title, description, owner });
    res.status(201).json(goal);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// ── 获取完整 OKR 树 ──
router.get('/:goalId', (req, res) => {
  const goal = goals.get(req.params.goalId);
  if (!goal) return res.status(404).json({ error: 'Goal not found' });
  res.json(goal);
});

// ── 更新目标元数据 ──
router.put('/:goalId', (req, res) => {
  const result = goals.updateGoal(req.params.goalId, req.body);
  if (!result) return res.status(404).json({ error: 'Goal not found' });
  res.json(result);
});

// ── 添加节点 ──
router.post('/:goalId/nodes', (req, res) => {
  try {
    const { parentNodeId, title, owner, priority } = req.body;
    if (!title || !owner) {
      return res.status(400).json({ error: 'title and owner are required' });
    }

    const result = goals.addNode(req.params.goalId, parentNodeId || null, {
      title, owner, priority,
    });

    if (!result) return res.status(404).json({ error: 'Goal not found' });
    res.status(201).json({ nodeId: result.nodeId, node: result.goal.nodes[result.nodeId] });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// ── 获取节点 + 上下文 ──
router.get('/:goalId/nodes/:nodeId', (req, res) => {
  const node = goals.getNode(req.params.goalId, req.params.nodeId);
  if (!node) return res.status(404).json({ error: 'Node not found' });
  res.json(node);
});

// ── 更新节点状态 ──
router.put('/:goalId/nodes/:nodeId', (req, res) => {
  const result = goals.updateNode(req.params.goalId, req.params.nodeId, req.body);
  if (!result) return res.status(404).json({ error: 'Node not found' });
  res.json({ nodeId: result.nodeId, node: result.node });
});

// ── 获取进度 ──
router.get('/:goalId/progress', (req, res) => {
  const progress = goals.getProgress(req.params.goalId);
  if (!progress) return res.status(404).json({ error: 'Goal not found' });
  res.json(progress);
});

module.exports = router;