本文最后更新于 2025年6月14日 凌晨
前言
在上一篇教程中,我们学习了如何调用api发送消息,以及发送不同的消息类型,那我们今天来实战写一个签到插件
签到插件的原理就是写入今天的时间,如果判断上一次签到时间和今天是一致的,那就签到失败,否则就是签到成功
指令匹配
在Koishi
这个框架中,我们除了可以用ctx.on
去判断消息外,我们可以直接使用最直接的ctx.command
去判断消息
示例代码如下
1 2 3 4
| ctx.command('签到') .action(async({session}) => { await session.send("1") })
|

数据库基础使用
这里是点我具体的文档,那么我们来写一个基础的,首先是声明数据类型
1 2 3 4
| export interface sign{ time : string user_id : string }
|
第二步声明使用了数据库插件,否则会出现黄色警告
1
| export const inject = ["database"]
|
在Koishi
里面声明数据库
1 2 3 4 5
| declare module 'koishi' { interface Tables { sign : sign } }
|
最后是创建数据库
1 2 3 4
| ctx.model.extend('sign',{ time: 'string', user_id: 'string' })
|
数据库创建代码为
1
| await ctx.database.create(table_name, {.....})
|
数据库更新代码为
1
| await ctx.database.upsert(table_name, [{....}])
|
数据库搜索代码为
1
| await ctx.database.get(table_name, {....})
|
获取年月日
这里我们可以使用js
的库获取
1 2 3 4 5 6 7
| function getCurrentDate(): string { const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }
|
开始编写
在我们前面了解完这些知识后,我们先创建一个存放签到数据的数据库
根据上面的代码讲解,我们可以这样写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import { Context, Schema, h } from 'koishi'
export const name = 'test'
export interface Config {}
declare module 'koishi' { interface Tables { sign_today : sign_today } }
export const inject = ["database"]
export const Config: Schema<Config> = Schema.object({})
export interface sign_today { id?: number now_time: string user_id: string }
export function apply(ctx: Context) { ctx.model.extend("sign_today", { id: 'unsigned', now_time: 'string', user_id: 'string' }, { primary: 'id', autoInc: true }) ctx.command('签到') .action(async({session}) => { await session.send("1") }) }
|
我们运行一下代码,如果日志出现了
1 2
| 2025-06-14 00:57:40 [I] hmr reload plugin at external\test\src\index.ts 2025-06-14 00:57:40 [I] sqlite auto creating table sign_today
|
说明你的数据库已经初始化了,现在我们缺少读写数据库
读写内容
对数据库进行搜索,然后数据库会返回数组
1 2 3 4 5 6 7 8 9
| ctx.command('签到') .action(async({session}) => { var get_user_sign_time = await ctx.database.get("sign_today", {user_id: session.userId}) if(get_user_sign_time.length == 0){
}else{ } })
|
当返回长度为0的数组,说明这个人不存在,我们要创建数据,然后返回签到成功
1 2 3 4 5 6 7 8 9 10 11 12 13
| ctx.command('签到') .action(async({session}) => { var get_user_sign_time = await ctx.database.get("sign_today", {user_id: session.userId}) if(get_user_sign_time.length == 0){ await ctx.database.create("sign_today", { "now_time": getCurrentDate(), "user_id": session.userId }) await session.send("签到成功") }else{
} })
|
那么我们就要讨论另外一种情况了,如果这个人在数据库有记录的话,我们需要对比时间,如果时间恰好等于今天的时间,说明他已经签到了,否则就是失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ctx.command('签到') .action(async({session}) => { var get_user_sign_time = await ctx.database.get("sign_today", {user_id: session.userId}) if(get_user_sign_time.length == 0){ await ctx.database.create("sign_today", { "now_time": getCurrentDate(), "user_id": session.userId }) await session.send("签到成功") }else{ if(get_user_sign_time[0]['now_time'] == getCurrentDate()){ await session.send("签到失败,你今天已经签到了") }else{ await ctx.database.upsert("sign_today", [{ "now_time" : getCurrentDate(), "user_id" : session.userId, }]) await session.send("签到成功") } } })
|
好了,这样就大功告成了

效果如上图
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import { Context, Schema, h } from 'koishi'
export const name = 'test'
export interface Config {}
declare module 'koishi' { interface Tables { sign_today : sign_today } }
export const inject = ["database"]
export const Config: Schema<Config> = Schema.object({})
export interface sign_today { id?: number now_time: string user_id: string }
export function apply(ctx: Context) { ctx.model.extend("sign_today", { id: 'unsigned', now_time: 'string', user_id: 'string' }, { primary: 'id', autoInc: true }) ctx.command('签到') .action(async({session}) => { var get_user_sign_time = await ctx.database.get("sign_today", {user_id: session.userId}) if(get_user_sign_time.length == 0){ await ctx.database.create("sign_today", { "now_time": getCurrentDate(), "user_id": session.userId }) await session.send("签到成功") }else{ if(get_user_sign_time[0]['now_time'] == getCurrentDate()){ await session.send("签到失败,你今天已经签到了") }else{ await ctx.database.upsert("sign_today", [{ "now_time" : getCurrentDate(), "user_id" : session.userId, }]) await session.send("签到成功") } } }) }
function getCurrentDate(): string { const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }
|
后记
学习了如何通过数据库读写实现签到功能后,下期我们来写一个定时任务计划