import { desc, eq, count, or, like } from 'drizzle-orm'; import { schema, app, db } from '@/app.ts' import z from 'zod'; const xhsUser = schema.xhsUser; app.route({ path: 'xhs-users', key: 'list', middleware: ['auth'], description: `获取小红书用户列表, 参数说明: page: 页码,默认1 pageSize: 每页数量,默认20 search: 搜索关键词,模糊匹配昵称、用户名和描述 sort: 排序方式,ASC或DESC,默认DESC按更新时间降序 `, metadata: { tags: ['小红书', '用户'], args: { page: z.number().int().positive().optional().describe('页码,默认为1'), pageSize: z.number().int().positive().optional().describe('每页数量,默认为20'), search: z.string().optional().describe('搜索关键词,支持在昵称、用户名和描述中搜索'), sort: z.enum(['ASC', 'DESC']).optional().describe('排序方式,默认为DESC') } } }).define(async (ctx) => { const { page = 1, pageSize = 20, search, sort = 'DESC' } = ctx.query || {}; const offset = (page - 1) * pageSize; const orderByField = sort === 'ASC' ? xhsUser.updatedAt : desc(xhsUser.updatedAt); let whereCondition = undefined; if (search) { whereCondition = or( like(xhsUser.nickname, `%${search}%`), like(xhsUser.username, `%${search}%`), like(xhsUser.description, `%${search}%`) ); } const [list, totalCount] = await Promise.all([ db.select() .from(xhsUser) .where(whereCondition) .limit(pageSize) .offset(offset) .orderBy(orderByField), db.select({ count: count() }) .from(xhsUser) .where(whereCondition) ]); ctx.body = { list, pagination: { page, current: page, pageSize, total: totalCount[0]?.count || 0, }, }; return ctx; }).addTo(app); const userUpdate = `创建或更新一个小红书用户, 参数定义: nickname: 用户昵称, 必填 username: 用户名, 选填 avatar: 用户头像, 选填 description: 用户描述, 选填 tags: 标签数组, 选填 data: 用户数据, 对象, 选填 `; app.route({ path: 'xhs-users', key: 'update', middleware: ['auth'], description: userUpdate, metadata: { tags: ['小红书', '用户'], } }).define(async (ctx) => { const { id, createdAt, updatedAt, ...rest } = ctx.query.data || {}; let user; if (!id) { user = await db.insert(xhsUser).values({ id: rest.id || `user_${Date.now()}`, nickname: rest.nickname || '', username: rest.username || '', avatar: rest.avatar || '', description: rest.description || '', summary: rest.summary || '', tags: rest.tags ? JSON.stringify(rest.tags) : null, link: rest.link || '', data: rest.data ? JSON.stringify(rest.data) : null, syncStatus: 1, syncAt: Date.now(), createdAt: Date.now(), updatedAt: Date.now(), }).returning(); } else { const existing = await db.select().from(xhsUser).where(eq(xhsUser.id, id)).limit(1); if (existing.length === 0) { ctx.throw(404, '没有找到对应的用户'); } user = await db.update(xhsUser).set({ nickname: rest.nickname, username: rest.username, avatar: rest.avatar, description: rest.description, summary: rest.summary, tags: rest.tags ? JSON.stringify(rest.tags) : undefined, link: rest.link, data: rest.data ? JSON.stringify(rest.data) : undefined, updatedAt: Date.now(), }).where(eq(xhsUser.id, id)).returning(); } ctx.body = user; }).addTo(app); app.route({ path: 'xhs-users', key: 'delete', middleware: ['auth'], description: '删除小红书用户, 参数: data.id 用户ID', metadata: { tags: ['小红书', '用户'], args: { data: z.object({ id: z.string().describe('用户ID') }).describe('请求数据对象,包含用户ID') } } }).define(async (ctx) => { const { id } = ctx.query.data || {}; if (!id) { ctx.throw(400, 'id 参数缺失'); } const existing = await db.select().from(xhsUser).where(eq(xhsUser.id, id)).limit(1); if (existing.length === 0) { ctx.throw(404, '没有找到对应的用户'); } await db.delete(xhsUser).where(eq(xhsUser.id, id)); ctx.body = { success: true }; }).addTo(app); app.route({ path: 'xhs-users', key: 'get', middleware: ['auth'], description: '获取单个小红书用户, 参数: data.id 用户ID', metadata: { tags: ['小红书', '用户'], args: { data: z.object({ id: z.string().describe('用户ID') }).describe('请求数据对象,包含用户ID') } } }).define(async (ctx) => { const { id } = ctx.query.data || {}; if (!id) { ctx.throw(400, 'id 参数缺失'); } const existing = await db.select().from(xhsUser).where(eq(xhsUser.id, id)).limit(1); if (existing.length === 0) { ctx.throw(404, '没有找到对应的用户'); } ctx.body = existing[0]; }).addTo(app);