Build a personal dashboard for OpenClaw with task management, memory browser, calendar, team tracking, and GitHub trends. Use when the user wants to create a web-based mission control dashboard for their OpenClaw instance, track tasks, view memories, manage calendar events, or build a custom dashboard interface.
技能名称:mission-control
详细描述:
为OpenClaw构建个人仪表盘——一个集任务、记忆、日历和团队管理于一体的中央指挥中心。
一个连接到OpenClaw实例的Next.js网页仪表盘,提供以下功能:
┌─────────────────────────────────────┐
│ Next.js 前端 │
│ ┌─────────┐ ┌─────────┐ ┌────────┐ │
│ │ 任务 │ │ 记忆 │ │ 日历 │ │
│ │ 看板 │ │ 列表 │ │ 视图 │ │
│ └────┬────┘ └────┬────┘ └───┬────┘ │
│ └───────────┴──────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ API 路由 │ │
│ └──────┬──────┘ │
└──────────────┼───────────────────────┘
│
┌───────┴───────┐
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ 本地JSON │ │ OpenClaw │
│ 文件 │ │ 记忆 │
└─────────────┘ └─────────────┘
bash
npx create-next-app@latest mission-control --typescript --tailwind
bash
cd mission-control
npm install lucide-react
创建src/lib/data.ts用于文件存储:
typescript
import fs from fs/promises;
import path from path;
const DATA_DIR = path.join(process.cwd(), src, data);
// 类型定义
export interface Task {
id: string;
title: string;
description: string;
status: todo | in-progress | done;
assignee: string;
createdAt: string;
updatedAt: string;
}
// 初始化数据文件
async function initDataFile(filename: string, defaultData: unknown) {
const filepath = path.join(DATA_DIR, filename);
try {
await fs.access(filepath);
} catch {
await fs.mkdir(DATA_DIR, { recursive: true });
await fs.writeFile(filepath, JSON.stringify(defaultData, null, 2));
}
return filepath;
}
// 任务
export async function getTasks(): Promise
const filepath = await initDataFile(tasks.json, []);
const data = await fs.readFile(filepath, utf-8);
return JSON.parse(data);
}
export async function addTask(task: Omit
const tasks = await getTasks();
const newTask: Task = {
...task,
id: Date.now().toString(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
tasks.push(newTask);
await fs.writeFile(
path.join(DATA_DIR, tasks.json),
JSON.stringify(tasks, null, 2)
);
return newTask;
}
export async function updateTask(id: string, updates: Partial
const tasks = await getTasks();
const index = tasks.findIndex((t) => t.id === id);
if (index === -1) return null;
tasks[index] = {
...tasks[index],
...updates,
updatedAt: new Date().toISOString()
};
await fs.writeFile(
path.join(DATA_DIR, tasks.json),
JSON.stringify(tasks, null, 2)
);
return tasks[index];
}
创建src/app/api/tasks/route.ts:
typescript
import { NextRequest, NextResponse } from next/server;
import { getTasks, addTask, updateTask } from @/lib/data;
export async function GET() {
const tasks = await getTasks();
return NextResponse.json(tasks);
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const task = await addTask(body);
return NextResponse.json(task, { status: 201 });
} catch (error) {
return NextResponse.json(
{ error: 创建任务失败 },
{ status: 500 }
);
}
}
export async function PUT(request: NextRequest) {
try {
const { id, ...updates } = await request.json();
const task = await updateTask(id, updates);
if (!task) {
return NextResponse.json({ error: 任务未找到 }, { status: 404 });
}
return NextResponse.json(task);
} catch (error) {
return NextResponse.json(
{ error: 更新任务失败 },
{ status: 500 }
);
}
}
导航组件 (src/components/Navigation.tsx):
typescript
use client;
import Link from next/link;
import { usePathname } from next/navigation;
import { useState } from react;
import { LayoutDashboard, ClipboardList, Menu, X } from lucide-react;
const navItems = [
{ href: /, label: 仪表盘, icon: LayoutDashboard },
{ href: /tasks, label: 任务, icon: ClipboardList },
];
export function Navigation() {
const pathname = usePathname();
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
<>
{/ 桌面端侧边栏 /}
{/ 移动端头部 /}
{/ 移动端抽屉 /}
{mobileMenuOpen && (
)}
>
);
}
typescript
use client;
import { useState, useEffect } from react;
interface Task {
id: string;
title: string;
description: string;
status: todo | in-progress | done;
assignee: string;
}
export function TaskBoard() {
const [tasks, setTasks] = useState
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchTasks();
}, []);
const fetchTasks = async () => {
try {
const response = await fetch(/api
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 mission-control-builder-1776420085 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 mission-control-builder-1776420085 技能
skillhub install mission-control-builder-1776420085
文件大小: 5.07 KB | 发布时间: 2026-4-17 19:39