mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-17 21:57:44 +00:00
feat: 挑战定时提醒
This commit is contained in:
parent
607b85c922
commit
534ef0765e
6 changed files with 340 additions and 0 deletions
|
|
@ -12,6 +12,8 @@ import * as version from './version.js';
|
||||||
|
|
||||||
import * as device from './device.js';
|
import * as device from './device.js';
|
||||||
|
|
||||||
|
import * as remind from './remind.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
assets,
|
assets,
|
||||||
guides,
|
guides,
|
||||||
|
|
@ -20,4 +22,5 @@ export default {
|
||||||
panel,
|
panel,
|
||||||
version,
|
version,
|
||||||
device,
|
device,
|
||||||
|
remind,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
29
apps/manage/remind.js
Normal file
29
apps/manage/remind.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import settings from '../../lib/settings.js';
|
||||||
|
import { rulePrefix } from '../../lib/common.js';
|
||||||
|
import ZZZPlugin from '../../lib/plugin.js';
|
||||||
|
|
||||||
|
export class RemindManage extends ZZZPlugin {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
name: '[ZZZ-Plugin]RemindManage',
|
||||||
|
dsc: '提醒功能管理',
|
||||||
|
event: 'message',
|
||||||
|
priority: 40, // 管理插件优先级较高
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}设置提醒时间\\s*(.+)`,
|
||||||
|
fnc: 'setCron',
|
||||||
|
permission: 'master',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setCron() {
|
||||||
|
const match = this.e.msg.match(/设置提醒时间\s*(.+)/);
|
||||||
|
if (!match) return;
|
||||||
|
const cron = match.trim();
|
||||||
|
settings.setSingleConfig('remind', 'cron', cron);
|
||||||
|
await this.reply(`式舆防卫战/危局强袭战提醒的定时任务已更新为: ${cron}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
227
apps/remind.js
Normal file
227
apps/remind.js
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
import { ZZZPlugin } from '../lib/plugin.js';
|
||||||
|
import settings from '../lib/settings.js';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { rulePrefix } from '../lib/common.js';
|
||||||
|
import { ZZZChallenge } from '../model/abyss.js';
|
||||||
|
import { Deadly } from '../model/deadly.js';
|
||||||
|
|
||||||
|
const USER_CONFIGS_KEY = 'ZZZ:REMIND:USER_CONFIGS';
|
||||||
|
|
||||||
|
export class Remind extends ZZZPlugin {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
name: '[ZZZ-Plugin]Remind',
|
||||||
|
dsc: '式舆防卫战/危局强袭战未完成提醒',
|
||||||
|
event: 'message',
|
||||||
|
priority: _.get(settings.getConfig('priority'), 'remind', 80),
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}开启挑战提醒$`,
|
||||||
|
fnc: 'subscribe',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}关闭挑战提醒$`,
|
||||||
|
fnc: 'unsubscribe',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}设置式舆阈值\\s*(\\d+)`,
|
||||||
|
fnc: 'setMyAbyssThreshold',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}设置危局阈值\\s*(\\d+)`,
|
||||||
|
fnc: 'setMyDeadlyThreshold',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}查询挑战状态$`,
|
||||||
|
fnc: 'checkNow',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.task = {
|
||||||
|
name: 'ZZZ-Plugin式舆防卫战/危局强袭战提醒任务',
|
||||||
|
cron: this.getCron(),
|
||||||
|
fnc: () => this.runTask(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getCron() {
|
||||||
|
const remindConfig = settings.getConfig('remind');
|
||||||
|
return _.get(remindConfig, 'cron', '0 30 20 * * ? *');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserConfig(userId) {
|
||||||
|
const userConfigJson = await redis.hGet(USER_CONFIGS_KEY, String(userId));
|
||||||
|
return userConfigJson ? JSON.parse(userConfigJson) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setUserConfig(userId, config) {
|
||||||
|
await redis.hSet(USER_CONFIGS_KEY, String(userId), JSON.stringify(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async subscribe() {
|
||||||
|
const uid = await this.getUID();
|
||||||
|
if (!uid) {
|
||||||
|
await this.reply('未绑定UID,请先绑定');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let userConfig = await this.getUserConfig(this.e.user_id);
|
||||||
|
|
||||||
|
if (userConfig && userConfig.enable) {
|
||||||
|
await this.reply('提醒已开启,请勿重复操作');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userConfig) {
|
||||||
|
userConfig.enable = true;
|
||||||
|
} else {
|
||||||
|
const defaultConfig = settings.getConfig('remind');
|
||||||
|
userConfig = {
|
||||||
|
enable: true,
|
||||||
|
abyssCheckLevel: defaultConfig.abyssCheckLevel,
|
||||||
|
deadlyStars: defaultConfig.deadlyStars,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.setUserConfig(this.e.user_id, userConfig);
|
||||||
|
await this.reply('提醒功能已开启');
|
||||||
|
}
|
||||||
|
|
||||||
|
async unsubscribe() {
|
||||||
|
let userConfig = await this.getUserConfig(this.e.user_id);
|
||||||
|
if (!userConfig || !userConfig.enable) {
|
||||||
|
await this.reply('提醒功能尚未开启');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
userConfig.enable = false;
|
||||||
|
await this.setUserConfig(this.e.user_id, userConfig);
|
||||||
|
await this.reply('提醒功能已关闭');
|
||||||
|
}
|
||||||
|
|
||||||
|
async setMyAbyssThreshold() {
|
||||||
|
const match = this.e.msg.match(/设置式舆阈值\s*(\d+)/);
|
||||||
|
if (!match) return;
|
||||||
|
const threshold = Number(match);
|
||||||
|
|
||||||
|
if (threshold < 1 || threshold > 7) {
|
||||||
|
await this.reply('阈值必须在1到7之间');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let userConfig = await this.getUserConfig(this.e.user_id);
|
||||||
|
if (!userConfig) {
|
||||||
|
const defaultConfig = settings.getConfig('remind');
|
||||||
|
userConfig = {
|
||||||
|
enable: false,
|
||||||
|
abyssCheckLevel: defaultConfig.abyssCheckLevel,
|
||||||
|
deadlyStars: defaultConfig.deadlyStars,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
userConfig.abyssCheckLevel = threshold;
|
||||||
|
await this.setUserConfig(this.e.user_id, userConfig);
|
||||||
|
await this.reply(`式舆防卫战提醒阈值已设为: 检查前 ${threshold} 层`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setMyDeadlyThreshold() {
|
||||||
|
const match = this.e.msg.match(/设置危局阈值\s*(\d+)/);
|
||||||
|
if (!match) return;
|
||||||
|
const threshold = Number(match);
|
||||||
|
|
||||||
|
let userConfig = await this.getUserConfig(this.e.user_id);
|
||||||
|
if (!userConfig) {
|
||||||
|
const defaultConfig = settings.getConfig('remind');
|
||||||
|
userConfig = {
|
||||||
|
enable: false,
|
||||||
|
abyssCheckLevel: defaultConfig.abyssCheckLevel,
|
||||||
|
deadlyStars: defaultConfig.deadlyStars,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
userConfig.deadlyStars = threshold;
|
||||||
|
await this.setUserConfig(this.e.user_id, userConfig);
|
||||||
|
await this.reply(`危局强袭战星星阈值已设为: ${threshold}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkNow() {
|
||||||
|
const userConfig = await this.getUserConfig(this.e.user_id);
|
||||||
|
if (!userConfig) {
|
||||||
|
await this.reply('尚未设置任何提醒,请先设置阈值');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await this.reply('正在查询,请稍候...');
|
||||||
|
const messages = await this.checkUser(this.e.user_id, userConfig, true); // 主动查询,显示所有状态
|
||||||
|
if (messages.length > 0) {
|
||||||
|
await this.reply(messages.join('\n'));
|
||||||
|
} else {
|
||||||
|
await this.reply('查询失败,请稍后再试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkUser(userId, userConfig, showAll = false) {
|
||||||
|
let messages = [];
|
||||||
|
try {
|
||||||
|
const user = this.e.bot.pickUser(userId);
|
||||||
|
const tempE = { ...this.e, user_id: userId, reply: (msg) => user.sendMsg(msg) };
|
||||||
|
|
||||||
|
const { api, deviceFp } = await this.getAPI(tempE);
|
||||||
|
await this.getPlayerInfo(tempE);
|
||||||
|
|
||||||
|
// 检查式舆防卫战
|
||||||
|
const abyssRawData = await api
|
||||||
|
.getFinalData('zzzChallenge', { deviceFp })
|
||||||
|
.catch(() => ({}));
|
||||||
|
if (!abyssRawData.has_data) {
|
||||||
|
messages.push(`式舆防卫战S评级: 0/7`);
|
||||||
|
} else {
|
||||||
|
const abyssData = new ZZZChallenge(abyssRawData);
|
||||||
|
const userThreshold = userConfig.abyssCheckLevel || 7;
|
||||||
|
if (showAll || !abyssData.areAllSUpTo(userThreshold)) {
|
||||||
|
const sCount = abyssData.getSRankCountUpTo(7);
|
||||||
|
const status = abyssData.areAllSUpTo(userThreshold) ? ' ✓' : '';
|
||||||
|
messages.push(`式舆防卫战S评级: ${sCount}/7${status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查危局强袭战
|
||||||
|
const deadlyRawData = await api.getFinalData('zzzDeadly', { deviceFp }).catch(() => ({}));
|
||||||
|
if (!deadlyRawData.has_data) {
|
||||||
|
messages.push(`危局强袭战星星: 0/9`);
|
||||||
|
} else {
|
||||||
|
const deadlyData = new Deadly(deadlyRawData);
|
||||||
|
if (showAll || deadlyData.total_star < userConfig.deadlyStars) {
|
||||||
|
const status = deadlyData.total_star >= userConfig.deadlyStars ? ' ✓' : '';
|
||||||
|
messages.push(`危局强袭战星星: ${deadlyData.total_star}/9${status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`[ZZZ-Plugin] 为用户 ${userId} 执行检查失败: ${error}`);
|
||||||
|
messages.push('查询失败,请稍后再试');
|
||||||
|
}
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
async runTask() {
|
||||||
|
const globalRemindConfig = settings.getConfig('remind');
|
||||||
|
if (!globalRemindConfig.enable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info('[ZZZ-Plugin] 开始执行式舆防卫战/危局强袭战提醒任务');
|
||||||
|
|
||||||
|
const allUserConfigs = await redis.hGetAll(USER_CONFIGS_KEY);
|
||||||
|
|
||||||
|
for (const userId in allUserConfigs) {
|
||||||
|
const userConfig = JSON.parse(allUserConfigs[userId]);
|
||||||
|
if (!userConfig.enable) continue;
|
||||||
|
|
||||||
|
const messages = await this.checkUser(userId, userConfig);
|
||||||
|
if (messages.length > 0) {
|
||||||
|
const user = this.e.bot.pickUser(userId);
|
||||||
|
await user.sendMsg(messages.join('\n'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info('[ZZZ-Plugin] 式舆防卫战/危局强袭战提醒任务执行完毕');
|
||||||
|
}
|
||||||
|
}
|
||||||
4
defSet/remind.yaml
Normal file
4
defSet/remind.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
enable: true # 功能总开关
|
||||||
|
cron: 0 30 20 * * ? * # 定时任务cron表达式,默认每天晚上8:30
|
||||||
|
abyssCheckLevel: 7 # 式舆防卫战提醒检查的最高关卡(用户可自行设置,最高为7)
|
||||||
|
deadlyStars: 6 # 危局强袭战星星阈值
|
||||||
|
|
@ -194,6 +194,45 @@ export function supportGuoba() {
|
||||||
addonAfter: "s",
|
addonAfter: "s",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: 'SOFT_GROUP_BEGIN',
|
||||||
|
label: '提醒功能设置',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remind.enable',
|
||||||
|
label: '开启提醒功能',
|
||||||
|
bottomHelpMessage: '是否启用式舆防卫战/危局强袭战的定时提醒功能',
|
||||||
|
component: 'Switch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remind.cron',
|
||||||
|
label: '提醒时间',
|
||||||
|
bottomHelpMessage: '设置新用户订阅时的默认Cron表达式',
|
||||||
|
component: 'EasyCron',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入或选择cron表达式',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remind.abyssSCount',
|
||||||
|
label: '默认式舆S评级阈值',
|
||||||
|
bottomHelpMessage: '新用户订阅时,S评级数量低于此值会收到提醒',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入数字',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remind.deadlyStars',
|
||||||
|
label: '默认危局星星阈值',
|
||||||
|
bottomHelpMessage: '新用户订阅时,星星总数低于此值会收到提醒',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入数字',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: 'SOFT_GROUP_BEGIN',
|
component: 'SOFT_GROUP_BEGIN',
|
||||||
label: '攻略设置',
|
label: '攻略设置',
|
||||||
|
|
|
||||||
|
|
@ -369,4 +369,42 @@ export class ZZZChallenge {
|
||||||
'0'
|
'0'
|
||||||
)}`;
|
)}`;
|
||||||
}
|
}
|
||||||
|
getSRankCountUpTo(maxLevel) {
|
||||||
|
let s_rank_count = 0;
|
||||||
|
const min_level = Math.min(
|
||||||
|
...this.all_floor_detail.map(f => f.layer_index)
|
||||||
|
);
|
||||||
|
for (let level = 1; level <= maxLevel; level++) {
|
||||||
|
const floor = this.all_floor_detail.find(f => f.layer_index === level);
|
||||||
|
if (floor) {
|
||||||
|
if (floor.rating === 'S') {
|
||||||
|
s_rank_count++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (level < min_level) {
|
||||||
|
s_rank_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s_rank_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
areAllSUpTo(maxLevel) {
|
||||||
|
const min_level = Math.min(
|
||||||
|
...this.all_floor_detail.map(f => f.layer_index)
|
||||||
|
);
|
||||||
|
for (let level = 1; level <= maxLevel; level++) {
|
||||||
|
const floor = this.all_floor_detail.find(f => f.layer_index === level);
|
||||||
|
if (floor) {
|
||||||
|
if (floor.rating !== 'S') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (level >= min_level) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue