🌍 真实世界示例
展示 Zhin.js 框架在实际项目中的应用场景。
🏢 企业级机器人
客服机器人
typescript
// src/plugins/customer-service-plugin.ts
import {
addCommand,
MessageCommand,
onMessage,
useContext,
useLogger,
register
} from 'zhin.js';
const logger = useLogger();
// 注册客服服务
register({
name: 'customer-service',
description: '客服系统',
async mounted() {
return {
async createTicket(userId: string, issue: string) {
const ticketId = `T${Date.now()}`;
// 创建工单逻辑
logger.info(`创建工单 ${ticketId} 给用户 ${userId}`);
return ticketId;
},
async getTicketStatus(ticketId: string) {
// 查询工单状态
return { status: '处理中', priority: '中等' };
}
};
}
});
// 工单创建命令
useContext('customer-service', (service) => {
addCommand(new MessageCommand('ticket <issue:text>')
.action(async (message, result) => {
const ticketId = await service.createTicket(message.$sender.id, result.params.issue);
return `🎫 工单已创建!
工单号:${ticketId}
问题:${result.params.issue}
状态:已提交,客服将在24小时内回复`;
})
);
});
// 工单查询命令
addCommand(new MessageCommand('status <ticketId:text>')
.action(async (message, result) => {
const status = await service.getTicketStatus(result.params.ticketId);
return `📋 工单状态:
工单号:${result.params.ticketId}
状态:${status.status}
优先级:${status.priority}`;
})
);
});
// 智能回复
onMessage(async (message) => {
const keywords = {
'退款': '请提供订单号,我们将为您处理退款申请',
'发货': '请提供订单号,我们为您查询物流信息',
'密码': '请通过官方渠道重置密码,或联系客服协助',
'账号': '请提供相关信息,我们为您查询账号状态'
};
for (const [keyword, reply] of Object.entries(keywords)) {
if (message.$raw.includes(keyword)) {
await message.$reply(`🤖 自动回复:${reply}`);
break;
}
}
});项目管理机器人
typescript
// src/plugins/project-management-plugin.ts
import { addCommand, MessageCommand, useContext, useLogger } from 'zhin.js';
const logger = useLogger();
interface Task {
id: string;
title: string;
assignee: string;
status: 'todo' | 'in-progress' | 'done';
priority: 'low' | 'medium' | 'high';
createdAt: number;
}
class ProjectManager {
private tasks = new Map<string, Task>();
private nextId = 1;
createTask(title: string, assignee: string, priority: 'low' | 'medium' | 'high' = 'medium'): Task {
const task: Task = {
id: `T${this.nextId++}`,
title,
assignee,
status: 'todo',
priority,
createdAt: Date.now()
};
this.tasks.set(task.id, task);
return task;
}
updateTaskStatus(taskId: string, status: Task['status']): boolean {
const task = this.tasks.get(taskId);
if (task) {
task.status = status;
return true;
}
return false;
}
getTasksByAssignee(assignee: string): Task[] {
return Array.from(this.tasks.values()).filter(task => task.assignee === assignee);
}
getAllTasks(): Task[] {
return Array.from(this.tasks.values());
}
}
const projectManager = new ProjectManager();
// 创建任务命令
addCommand(new MessageCommand('task create <title:text> <assignee:text> [priority:text=medium]')
.action(async (message, result) => {
const { title, assignee, priority } = result.params;
const task = projectManager.createTask(title, assignee, priority as any);
return `✅ 任务已创建!
ID: ${task.id}
标题: ${task.title}
负责人: ${task.assignee}
优先级: ${task.priority}
状态: ${task.status}`;
})
);
// 更新任务状态
addCommand(new MessageCommand('task update <taskId:text> <status:text>')
.action(async (message, result) => {
const { taskId, status } = result.params;
const validStatuses = ['todo', 'in-progress', 'done'];
if (!validStatuses.includes(status)) {
return `❌ 无效状态,请使用: ${validStatuses.join(', ')}`;
}
const success = projectManager.updateTaskStatus(taskId, status as any);
if (success) {
return `✅ 任务 ${taskId} 状态已更新为 ${status}`;
} else {
return `❌ 任务 ${taskId} 不存在`;
}
})
);
// 查看我的任务
addCommand(new MessageCommand('my tasks')
.action(async (message) => {
const tasks = projectManager.getTasksByAssignee(message.sender.id);
if (tasks.length === 0) {
return '📝 您当前没有任务';
}
let response = '📋 您的任务:\n\n';
tasks.forEach(task => {
const statusEmoji = {
'todo': '⏳',
'in-progress': '🔄',
'done': '✅'
};
response += `${statusEmoji[task.status]} **${task.title}** (${task.id})\n`;
response += ` 优先级: ${task.priority} | 状态: ${task.status}\n\n`;
});
return response;
})
);
// 查看所有任务
addCommand(new MessageCommand('tasks all')
.action(async () => {
const tasks = projectManager.getAllTasks();
if (tasks.length === 0) {
return '📝 当前没有任务';
}
let response = '📋 所有任务:\n\n';
tasks.forEach(task => {
const statusEmoji = {
'todo': '⏳',
'in-progress': '🔄',
'done': '✅'
};
response += `${statusEmoji[task.status]} **${task.title}** (${task.id})\n`;
response += ` 负责人: ${task.assignee} | 优先级: ${task.priority}\n\n`;
});
return response;
})
);🎮 游戏机器人
猜数字游戏
typescript
// src/plugins/guess-number-plugin.ts
import { addCommand, MessageCommand, onMessage, useLogger } from 'zhin.js';
const logger = useLogger();
interface GameSession {
userId: string;
number: number;
attempts: number;
maxAttempts: number;
startTime: number;
}
const gameSessions = new Map<string, GameSession>();
// 开始游戏命令
addCommand(new MessageCommand('guess start [max:number=100]')
.action(async (message, result) => {
const userId = message.sender.id;
const max = result.params.max ?? 100;
// 检查是否已有游戏进行中
if (gameSessions.has(userId)) {
return '🎮 您已有游戏进行中,请先完成当前游戏';
}
const session: GameSession = {
userId,
number: Math.floor(Math.random() * max) + 1,
attempts: 0,
maxAttempts: Math.ceil(Math.log2(max)) + 2,
startTime: Date.now()
};
gameSessions.set(userId, session);
return `🎮 猜数字游戏开始!
范围:1-${max}
最大尝试次数:${session.maxAttempts}
输入数字开始猜测!`;
})
);
// 猜测命令
addCommand(new MessageCommand('guess <number:number>')
.action(async (message, result) => {
const userId = message.sender.id;
const session = gameSessions.get(userId);
if (!session) {
return '❌ 请先开始游戏:guess start';
}
const guess = result.params.number;
session.attempts++;
if (guess === session.number) {
const duration = Date.now() - session.startTime;
const minutes = Math.floor(duration / 60000);
const seconds = Math.floor((duration % 60000) / 1000);
gameSessions.delete(userId);
return `🎉 恭喜!猜对了!
答案:${session.number}
尝试次数:${session.attempts}
用时:${minutes}分${seconds}秒`;
}
if (session.attempts >= session.maxAttempts) {
gameSessions.delete(userId);
return `💀 游戏结束!
正确答案:${session.number}
尝试次数:${session.attempts}/${session.maxAttempts}`;
}
const hint = guess > session.number ? '太大了' : '太小了';
const remaining = session.maxAttempts - session.attempts;
return `🤔 ${hint}!
尝试次数:${session.attempts}/${session.maxAttempts}
剩余次数:${remaining}`;
})
);
// 放弃游戏命令
addCommand(new MessageCommand('guess quit')
.action(async (message) => {
const userId = message.sender.id;
const session = gameSessions.get(userId);
if (!session) {
return '❌ 您当前没有进行中的游戏';
}
gameSessions.delete(userId);
return `😔 游戏已放弃!
正确答案:${session.number}
尝试次数:${session.attempts}`;
})
);文字冒险游戏
typescript
// src/plugins/text-adventure-plugin.ts
import { addCommand, MessageCommand, useLogger } from 'zhin.js';
const logger = useLogger();
interface GameState {
userId: string;
location: string;
inventory: string[];
health: number;
score: number;
}
const gameStates = new Map<string, GameState>();
const gameMap = {
'start': {
description: '你站在一个神秘的洞穴入口前,里面传来奇怪的声音。',
exits: ['cave'],
items: ['torch']
},
'cave': {
description: '洞穴内部很暗,只有微弱的火光。你看到前方有两条路。',
exits: ['treasure', 'monster'],
items: ['sword']
},
'treasure': {
description: '你发现了一个宝箱!里面闪闪发光。',
exits: ['cave'],
items: ['gold', 'potion']
},
'monster': {
description: '一只巨大的怪物挡住了去路!',
exits: ['cave'],
items: []
}
};
// 开始冒险命令
addCommand(new MessageCommand('adventure start')
.action(async (message) => {
const userId = message.sender.id;
if (gameStates.has(userId)) {
return '🎮 您已有冒险进行中,请先完成当前冒险';
}
const state: GameState = {
userId,
location: 'start',
inventory: [],
health: 100,
score: 0
};
gameStates.set(userId, state);
return `🎮 冒险开始!
${gameMap[state.location].description}
可用命令:
- look: 查看当前位置
- go <方向>: 移动到指定方向
- take <物品>: 拾取物品
- inventory: 查看背包
- use <物品>: 使用物品`;
})
);
// 查看命令
addCommand(new MessageCommand('look')
.action(async (message) => {
const userId = message.sender.id;
const state = gameStates.get(userId);
if (!state) {
return '❌ 请先开始冒险:adventure start';
}
const location = gameMap[state.location];
let response = `📍 当前位置:${state.location}\n\n`;
response += `${location.description}\n\n`;
if (location.exits.length > 0) {
response += `🚪 可前往:${location.exits.join(', ')}\n`;
}
if (location.items.length > 0) {
response += `📦 可拾取:${location.items.join(', ')}\n`;
}
response += `\n❤️ 生命值:${state.health}\n`;
response += `⭐ 分数:${state.score}`;
return response;
})
);
// 移动命令
addCommand(new MessageCommand('go <direction:text>')
.action(async (message, result) => {
const userId = message.sender.id;
const state = gameStates.get(userId);
if (!state) {
return '❌ 请先开始冒险:adventure start';
}
const direction = result.params.direction;
const location = gameMap[state.location];
if (!location.exits.includes(direction)) {
return `❌ 无法前往 ${direction},可用方向:${location.exits.join(', ')}`;
}
state.location = direction;
// 特殊事件处理
if (direction === 'monster') {
state.health -= 20;
if (state.health <= 0) {
gameStates.delete(userId);
return `💀 你被怪物击败了!游戏结束!\n最终分数:${state.score}`;
}
return `⚔️ 你遇到了怪物!生命值 -20\n当前生命值:${state.health}`;
}
if (direction === 'treasure') {
state.score += 100;
return `💰 你发现了宝藏!分数 +100\n当前分数:${state.score}`;
}
return `✅ 已移动到 ${direction}`;
})
);
// 拾取物品命令
addCommand(new MessageCommand('take <item:text>')
.action(async (message, result) => {
const userId = message.sender.id;
const state = gameStates.get(userId);
if (!state) {
return '❌ 请先开始冒险:adventure start';
}
const item = result.params.item;
const location = gameMap[state.location];
if (!location.items.includes(item)) {
return `❌ 这里没有 ${item},可用物品:${location.items.join(', ')}`;
}
state.inventory.push(item);
location.items.splice(location.items.indexOf(item), 1);
return `✅ 已拾取 ${item}`;
})
);
// 查看背包命令
addCommand(new MessageCommand('inventory')
.action(async (message) => {
const userId = message.sender.id;
const state = gameStates.get(userId);
if (!state) {
return '❌ 请先开始冒险:adventure start';
}
if (state.inventory.length === 0) {
return '📦 背包是空的';
}
return `📦 背包内容:\n${state.inventory.map(item => `- ${item}`).join('\n')}`;
})
);📊 数据分析机器人
数据统计机器人
typescript
// src/plugins/analytics-plugin.ts
import { addCommand, MessageCommand, onMessage, useLogger } from 'zhin.js';
const logger = useLogger();
interface MessageStats {
userId: string;
messageCount: number;
commandCount: number;
lastActive: number;
joinDate: number;
}
const userStats = new Map<string, MessageStats>();
const globalStats = {
totalMessages: 0,
totalCommands: 0,
activeUsers: 0,
startTime: Date.now()
};
// 消息统计中间件
onMessage(async (message, next) => {
const userId = message.sender.id;
// 更新用户统计
if (!userStats.has(userId)) {
userStats.set(userId, {
userId,
messageCount: 0,
commandCount: 0,
lastActive: Date.now(),
joinDate: Date.now()
});
}
const userStat = userStats.get(userId)!;
userStat.messageCount++;
userStat.lastActive = Date.now();
// 更新全局统计
globalStats.totalMessages++;
// 检查是否是命令
if (message.raw.startsWith('/') || message.raw.startsWith('!')) {
userStat.commandCount++;
globalStats.totalCommands++;
}
await next();
});
// 统计命令
addCommand(new MessageCommand('stats')
.action(async (message) => {
const userId = message.sender.id;
const userStat = userStats.get(userId);
if (!userStat) {
return '❌ 没有找到您的统计数据';
}
const now = Date.now();
const daysSinceJoin = Math.floor((now - userStat.joinDate) / (1000 * 60 * 60 * 24));
const hoursSinceActive = Math.floor((now - userStat.lastActive) / (1000 * 60 * 60));
return `📊 您的统计信息:
消息数:${userStat.messageCount}
命令数:${userStat.commandCount}
加入天数:${daysSinceJoin}
最后活跃:${hoursSinceActive}小时前`;
})
);
// 全局统计命令
addCommand(new MessageCommand('stats global')
.action(async () => {
const now = Date.now();
const uptime = Math.floor((now - globalStats.startTime) / (1000 * 60 * 60 * 24));
const activeUsers = Array.from(userStats.values()).filter(
stat => now - stat.lastActive < 24 * 60 * 60 * 1000
).length;
return `📊 全局统计信息:
总消息数:${globalStats.totalMessages}
总命令数:${globalStats.totalCommands}
活跃用户:${activeUsers}
运行天数:${uptime}`;
})
);
// 排行榜命令
addCommand(new MessageCommand('leaderboard [type:text=messages]')
.action(async (message, result) => {
const type = result.params.type;
let sortedUsers: Array<{ userId: string; value: number; name?: string }> = [];
if (type === 'messages') {
sortedUsers = Array.from(userStats.values())
.map(stat => ({ userId: stat.userId, value: stat.messageCount }))
.sort((a, b) => b.value - a.value)
.slice(0, 10);
} else if (type === 'commands') {
sortedUsers = Array.from(userStats.values())
.map(stat => ({ userId: stat.userId, value: stat.commandCount }))
.sort((a, b) => b.value - a.value)
.slice(0, 10);
} else {
return '❌ 无效类型,请使用 messages 或 commands';
}
let response = `🏆 ${type} 排行榜:\n\n`;
sortedUsers.forEach((user, index) => {
const medal = index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : '🏅';
response += `${medal} ${index + 1}. ${user.userId}: ${user.value}\n`;
});
return response;
})
);