keli-sign
Version:
keli 的积分签到插件,提供积分签到功能,支持分群、自定义积分名等
320 lines (247 loc) • 7.71 kB
JavaScript
const { parseUin, uploadFileToDir, Plugin, randomInt, segment } = require('keli')
const path = require('node:path')
const { name, version } = require('./package.json')
const plugin = new Plugin(name, version)
const config = {
group: 0,
unit: '积分',
range: [3, 10],
max: 6,
enableGroups: [],
cmds: {
sign: '签到',
rank: '积分排行',
mine: '我的积分'
}
}
const DefaultUserData = {
coins: 0,
days: 0,
last: 0
}
const data = {}
const dataPath = path.join(plugin.dataDir, 'data.json')
plugin.onMounted(() => {
// 载入配置文件
plugin.saveConfig(Object.assign(config, plugin.loadConfig()))
// 载入数据文件
plugin.saveConfig(Object.assign(data, plugin.loadConfig(dataPath)), dataPath)
// 处理管理员命令
plugin.onAdminCmd('/sign', (e, params) => handleAdminCmd(e, params, plugin))
// 处理群员命令
plugin.onGroupMessage(e => {
// 过滤未开启的群聊
if (!config.enableGroups.includes(e.group_id)) {
return
}
// 处理各个积分命令
if (e.raw_message === config.cmds.sign) {
handleSign(e, plugin)
} else if (e.raw_message === config.cmds.rank) {
handleRank(e, plugin)
} else if (e.raw_message === config.cmds.mine) {
handleMine(e, plugin)
}
})
})
function ensureData(gid, qq) {
if (!data[gid]) {
data[gid] = {}
}
if (qq && !data[gid][qq]) {
data[gid][qq] = { ...DefaultUserData }
}
}
function today() {
const oneHourMs = 60 * 60 * 1000
return Math.floor((Date.now() + 8 * oneHourMs) / (24 * oneHourMs))
}
async function handleAdminCmd(e, params, plugin) {
const [cmd, v1, v2] = params
const menus = [
`/sign on/off`,
`/sign group <备份群号>`,
`/sign inc/dec <qq> <${config.unit}数>`,
`/sign stat`,
`/sign backup`
]
const cmds = ['on', 'off', 'group', 'inc', 'dec', 'backup', 'stat']
if (cmds.includes(cmd)) {
if (cmd === 'group' && v1) {
const group = Number(v1)
if (group) {
config.group = group
plugin.saveConfig(config)
return e.reply('备份群号设置成功', true)
}
}
if (cmd === 'inc' && v1 && v2) {
const qq = parseUin(v1)
const count = Number(v2)
if (qq && count > 0) {
if (e.message_type !== 'group') {
return e.reply('请在群聊中使用此命令', true)
} else {
ensureData(e.group_id, qq)
data[e.group_id][qq].coins += count
plugin.saveConfig(data, dataPath)
return e.reply(`已给目标追加 ${count} ${config.unit}`, true)
}
}
}
if (cmd === 'dec' && v1 && v2) {
const qq = parseUin(v1)
const count = Number(v2)
if (qq && count > 0) {
if (e.message_type !== 'group') {
return e.reply('请在群聊中使用此命令', true)
} else {
ensureData(e.group_id, qq)
data[e.group_id][qq].coins -= count
plugin.saveConfig(data, dataPath)
return e.reply(`已扣除目标 ${count} ${config.unit}`, true)
}
}
}
if (cmd === 'backup') {
if (!config.group) {
return e.reply('请先设置数据备份群号', true)
} else {
const isOK = await uploadFileToDir.call(
plugin.bot,
config.group,
dataPath,
`[sign]-data.json`
)
return e.reply(isOK ? '已上传到群文件' : '上传出现问题, 请查看日志', true)
}
}
if (cmd === 'stat') {
const signers = new Set()
const todaySigners = new Set()
const groups = new Set()
const todayGroups = new Set()
for (const [gid, ginfo] of Object.entries(data)) {
for (const [qq, info] of Object.entries(ginfo)) {
const user = `${gid}-${qq}`
signers.add(user)
if (!groups.has(gid)) {
groups.add(gid)
}
const last = info.last
if (last === today()) {
todaySigners.add(user)
if (!todayGroups.has(gid)) {
todayGroups.add(gid)
}
}
if (last !== today() && last !== today() - 1) {
info.days = 0
}
}
}
plugin.saveConfig(data, dataPath)
return e.reply(
[
`〓 签到统计 〓`,
`今日签到人数: ${todaySigners.size}`,
`总计签到人数: ${signers.size}`,
`今日活跃群聊: ${todayGroups.size}`,
`总计活跃群聊: ${groups.size}`
].join('\n')
)
}
if (cmd === 'on') {
if (e.message_type !== 'group') {
return e.reply('请在群聊中使用此命令', true)
}
const gid = e.group_id
if (gid) {
if (!config.enableGroups.includes(gid)) {
config.enableGroups.push(gid)
plugin.saveConfig(config)
}
return e.reply('本群签到功能开启成功', true)
}
}
if (cmd === 'off') {
if (e.message_type !== 'group') {
return e.reply('请在群聊中使用此命令', true)
}
const gid = e.group_id
if (gid) {
if (config.enableGroups.includes(gid)) {
const idx = config.enableGroups.findIndex(e => e === gid)
config.enableGroups.splice(idx, 1)
plugin.saveConfig(config)
}
return e.reply('本群签到功能已关闭', true)
}
}
e.reply(menus.join('\n'), true)
} else {
return e.reply(menus.join('\n'), true)
}
}
function handleSign(e, plugin) {
ensureData(e.group_id, e.sender.user_id)
const user = data[e.group_id][e.sender.user_id]
if (user.last === today()) {
e.reply('今天已经签到过了哦', true)
} else {
const [min, max] = config.range
const todayCoin = randomInt(min, max)
if (user.last === today() - 1) {
user.days += 1
} else {
user.days = 1
}
user.last = today()
user.coins += todayCoin
plugin.saveConfig(data, dataPath)
const days = `, 连签 ${user.days} 天`
e.reply([segment.at(e.sender.user_id), ` 签到成功, 获得 ${todayCoin} ${config.unit}${days}`])
}
}
function handleRank(e, plugin) {
ensureData(e.group_id)
const ginfo = data[e.group_id]
const glist = Object.entries(ginfo)
glist.sort((a, b) => b[1].coins - a[1].coins)
const map = ['〇', '①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩']
if (glist.length) {
let msg = `〓 ${config.unit}排行 〓`
let i = 1
for (const [qq, info] of glist.slice(0, config.max)) {
const name = e.group.pickMember(Number(qq)).card
if (info.last !== today() && info.last !== today() - 1) {
info.days = 0
}
const days = info.days ? `, 连签 ${info.days} 天` : ''
msg += `\n${map[i++]} @${name}`
msg += `\n拥有 ${info.coins} ${config.unit}${days}`
}
plugin.saveConfig(data, dataPath)
e.reply(msg)
} else {
e.reply('本群还没有人签到', true)
}
}
function handleMine(e, plugin) {
ensureData(e.group_id, e.sender.user_id)
const user = data[e.group_id][e.sender.user_id]
if (user.coins) {
const ginfo = data[e.group_id]
const glist = Object.entries(ginfo)
glist.sort((a, b) => b[1].coins - a[1].coins)
const rank = glist.findIndex(([qq]) => Number(qq) === e.sender.user_id) + 1
const days = user.days ? `, 连签 ${user.days} 天` : ''
e.reply([
segment.at(e.sender.user_id),
` 你拥有 ${user.coins} ${config.unit}${days}, 排名第 ${rank}`
])
} else {
e.reply('你还没有在本群签到过', true)
}
}
module.exports = { plugin }