Files
code-center/.opencode/skills/create-routes/SKILL.md

6.3 KiB
Raw Blame History

name, description
name description
create-routes 创建路由例子模板代码

创建路由例子模板代码

app是自定义@kevisual/router的一个APP

  1. 一般来说修改path和对应的schema表就可以快速创建对应的增删改查接口。
  2. 根据需要,每一个功能需要添加对应的描述
  3. 根据需要对应schema表的字段进行修改代码

示例:

import { desc, eq, count, or, like, and } from 'drizzle-orm';
import { schema, app, db } from '@/app.ts';
import { z } from 'zod';

app
  .route({
    path: 'prompts',
    key: 'list',
    middleware: ['auth'],
    description: '获取提示词列表',
    metadata: {
      args: {
        page: z.number().optional().default(1).describe('页码'),
        pageSize: z.number().optional().default(20).describe('每页数量'),
        search: z.string().optional().describe('搜索关键词'),
        sort: z.enum(['ASC', 'DESC']).optional().default('DESC').describe('排序方式'),
      },
    },
  })
  .define(async (ctx) => {
    const tokenUser = ctx.state.tokenUser;
    const uid = tokenUser.id;
    const { page = 1, pageSize = 20, search, sort = 'DESC' } = ctx.query || {};

    const offset = (page - 1) * pageSize;
    const orderByField = sort === 'ASC' ? schema.prompts.updatedAt : desc(schema.prompts.updatedAt);

    let whereCondition = eq(schema.prompts.uid, uid);
    if (search) {
      whereCondition = and(eq(schema.prompts.uid, uid), or(like(schema.prompts.title, `%${search}%`), like(schema.prompts.summary, `%${search}%`)));
    }

    const [list, totalCount] = await Promise.all([
      db.select().from(schema.prompts).where(whereCondition).limit(pageSize).offset(offset).orderBy(orderByField),
      db.select({ count: count() }).from(schema.prompts).where(whereCondition),
    ]);

    ctx.body = {
      list,
      pagination: {
        page,
        current: page,
        pageSize,
        total: totalCount[0]?.count || 0,
      },
    };
    return ctx;
  })
  .addTo(app);
app
  .route({
    path: 'prompts',
    key: 'create',
    middleware: ['auth'],
    description: '创建提示词',
    metadata: {
      args: {
        data: z
          .object({
            title: z.string().describe('提示词标题'),
            description: z.string().optional().describe('描述'),
            summary: z.string().optional().describe('摘要'),
            tags: z.array(z.string()).optional().describe('标签'),
            link: z.string().optional().describe('链接'),
            data: z.record(z.string(), z.any()).optional().describe('数据对象'),
            parents: z.array(z.string()).optional().describe('父级ID数组'),
          })
          .describe('提示词对象'),
      },
    },
  })
  .define(async (ctx) => {
    const tokenUser = ctx.state.tokenUser;
    const { title, description, summary, tags, link, data, parents } = ctx.query.data || {};
    if (!title) {
      ctx.throw(400, 'title 参数缺失');
    }
    const newPrompt = await db
      .insert(schema.prompts)
      .values({
        title,
        description,
        summary,
        tags,
        link,
        data,
        parents,
        uid: tokenUser.id,
      })
      .returning();

    ctx.body = newPrompt;
  })
  .addTo(app);
app
  .route({
    path: 'prompts',
    key: 'update',
    middleware: ['auth'],
    description: '更新提示词',
    metadata: {
      args: {
        data: z
          .object({
            id: z.string().optional().describe('提示词ID, 不填表示创建'),
            title: z.string().describe('提示词标题'),
            description: z.string().optional().describe('描述'),
            summary: z.string().optional().describe('摘要'),
            tags: z.array(z.string()).optional().describe('标签'),
            link: z.string().optional().describe('链接'),
            data: z.record(z.string(), z.any()).optional().describe('数据对象'),
            parents: z.array(z.string()).optional().describe('父级ID数组'),
          })
          .describe('提示词对象'),
      },
    },
  })
  .define(async (ctx) => {
    const { id, uid, updatedAt, ...rest } = ctx.query.data || {};
    const tokenUser = ctx.state.tokenUser;
    let prompt;
    if (!id) {
      ctx.throw(400, 'id 参数缺失');
    }
    const existing = await db.select().from(schema.prompts).where(eq(schema.prompts.id, id)).limit(1);
    if (existing.length === 0) {
      ctx.throw(404, '没有找到对应的提示词');
    }
    if (existing[0].uid !== tokenUser.id) {
      ctx.throw(403, '没有权限更新该提示词');
    }
    prompt = await db
      .update(schema.prompts)
      .set({
        ...rest,
      })
      .where(eq(schema.prompts.id, id))
      .returning();
    ctx.body = prompt;
  })
  .addTo(app);

app
  .route({
    path: 'prompts',
    key: 'delete',
    middleware: ['auth'],
    description: '删除提示词, 参数: id 提示词ID',
    metadata: {
      args: {
        id: z.string().describe('提示词ID'),
      },
    },
  })
  .define(async (ctx) => {
    const tokenUser = ctx.state.tokenUser;
    const { id } = ctx.query || {};
    if (!id) {
      ctx.throw(400, 'id 参数缺失');
    }
    const existing = await db.select().from(schema.prompts).where(eq(schema.prompts.id, id)).limit(1);
    if (existing.length === 0) {
      ctx.throw(404, '没有找到对应的提示词');
    }
    if (existing[0].uid !== tokenUser.id) {
      ctx.throw(403, '没有权限删除该提示词');
    }
    await db.delete(schema.prompts).where(eq(schema.prompts.id, id));
    ctx.body = { success: true };
  })
  .addTo(app);

app
  .route({
    path: 'prompts',
    key: 'get',
    middleware: ['auth'],
    description: '获取单个提示词, 参数: id 提示词ID',
    metadata: {
      args: {
        id: z.string().describe('提示词ID'),
      },
    },
  })
  .define(async (ctx) => {
    const tokenUser = ctx.state.tokenUser;
    const { id } = ctx.query || {};
    if (!id) {
      ctx.throw(400, 'id 参数缺失');
    }
    const existing = await db.select().from(schema.prompts).where(eq(schema.prompts.id, id)).limit(1);
    if (existing.length === 0) {
      ctx.throw(404, '没有找到对应的提示词');
    }
    if (existing[0].uid !== tokenUser.id) {
      ctx.throw(403, '没有权限查看该提示词');
    }
    ctx.body = existing[0];
  })
  .addTo(app);