活动期限/周本通知器 0.0.7 (#2736)

* feat(campaignArea): 添加每日委托OCR识别和提醒功能

- 新增每日委托识别区域坐标配置
- 实现ocrDailyCommission函数进行OCR识别处理
- 添加dailyCommissionMain主函数控制委托提醒流程
- 修改campaignAreaMain函数支持开关热键功能
- 更新main函数调用顺序和参数传递
- 增加版本号至0.0.7并更新README文档

* docs(ActivitySwitchNotice): 更新文档添加核心思维导图

- 添加整体架构流程图展示程序入口和初始化流程
- 添加活动扫描核心流程的详细状态转换图
- 添加征讨领域提醒流程的状态转换图
- 添加通知发送机制的流程图
- 添加配置解析流程的状态转换图
- 添加核心组件依赖关系的架构图
- 将原有的逻辑流程部分后移并保留基础描述
This commit is contained in:
云端客
2026-01-19 17:47:48 +08:00
committed by GitHub
parent 4e4e2a0682
commit e6ae771a8e
4 changed files with 245 additions and 30 deletions

View File

@@ -20,7 +20,136 @@
- ✅ 自动提醒征讨领域减半剩余次数(默认`周日`提醒可配置)
- ✅ 支持独立通知功能(`0.0.4`版本新增 因BGI不支持WebSocket,需搭配bettergi-scripts-tools+开启JS HTTP
权限使用)[前往bettergi-scripts-tools部署](https://github.com/Kirito520Asuna/bettergi-scripts-tools)
## 逻辑流程
## 核心思维导图
### 整体架构流程图
```mermaid
graph TD
A[主程序入口 main.js] --> B[初始化 init]
B --> C[加载工具模块]
C --> D[uid.js, ws.js, notice.js, campaignArea.js, activity.js]
D --> E[读取 manifest.json]
E --> F[检查是否返回主界面]
F --> G[toMainUi]
G --> H[执行主功能 main]
H --> I[每日委托检查]
I --> J[征讨领域检查]
J --> K[活动页面扫描]
K --> L[返回主界面]
L --> M[程序结束]
```
### 活动扫描核心流程
```mermaid
graph TD
A[activityMain函数] --> B[初始化配置]
B --> C[打开活动页面 F5]
C --> D[滚动到页面顶部]
D --> E[开始逐页扫描]
E --> F[OCR识别活动列表]
F --> G{是否有活动?}
G -->|否| H[结束扫描]
G -->|是| I[遍历当前页活动]
I --> J[白名单过滤]
J --> K{是否在白名单?}
K -->|是| L[继续处理]
K -->|否| M[根据关系模式判断]
M --> N{relationship=true?}
N -->|是| O[跳过]
N -->|否| L[继续处理]
L --> P[黑名单过滤]
P --> Q{是否在黑名单?}
Q -->|是| R[条件检测]
Q -->|否| S[点击活动]
R --> T{条件满足?}
T -->|是| U[跳过]
T -->|否| S[点击活动]
S --> V[OCR识别剩余时间]
V --> W[解析时间转小时]
W --> X[应用阈值过滤]
X --> Y[存储活动信息]
Y --> Z[向下滚动一页]
Z --> E
H --> AA[过滤符合条件活动]
AA --> BB[按剩余时间排序]
BB --> CC[发送通知]
CC --> DD[流程结束]
```
### 征讨领域提醒流程
```mermaid
graph TD
A[campaignAreaMain函数] --> B[获取当前星期]
B --> C{是否为提醒日?}
C -->|否| D[结束函数]
C -->|是| E[打开冒险之书 F1]
E --> F[点击秘境坐标]
F --> G[点击征讨领域坐标]
G --> H[OCR识别周次数]
H --> I{剩余次数>0?}
I -->|否| J[结束函数]
I -->|是| K[发送通知]
K --> L[流程结束]
```
### 通知发送机制
```mermaid
graph TD
A[sendNotice函数] --> B[检查通知类型配置]
B --> C[获取通知模式]
C --> D{BGI通知?}
D -->|是| E[notification.send]
C --> F{独立通知?}
F -->|是| G[wsUtil.sendText]
C --> H{两者都发送?}
H -->|是| E
H -->|是| G
E --> I[发送完成]
G --> I
I --> J[流程结束]
```
### 配置解析流程
```mermaid
graph TD
A[配置初始化] --> B[parseWhiteActivity]
A --> C[parseBlackActivity]
B --> D[白名单列表解析]
C --> E[黑名单条件解析]
D --> F[建立whiteActivityNameList]
E --> G[建立blackActivityMap]
F --> H[设置relationship逻辑]
G --> H
H --> I[配置完成]
```
### 核心组件依赖关系
```mermaid
graph LR
subgraph "工具模块"
A[activity.js - 活动处理]
B[notice.js - 通知发送]
C[campaignArea.js - 征讨领域]
D[ws.js - WebSocket通信]
E[uid.js - UID识别]
end
subgraph "主控模块"
F[main.js - 主入口]
G[settings.json - 配置]
end
F --> A
F --> B
F --> C
A --> B
A --> D
A --> E
C --> B
C --> E
G -.-> A
G -.-> B
G -.-> C
G -.-> D
```
### 逻辑流程
```mermaid
sequenceDiagram
autonumber
@@ -382,6 +511,8 @@ ActivitySwitchNotice/
## 版本历史
### 0.0.7 (2026-01-19)
- 新增每日委托提醒
### 0.0.6 (2026-01-06)
- **功能优化**新增识别uid通知提醒
实例:

View File

@@ -56,7 +56,11 @@ async function toMainUi() {
* @returns {Promise<void>}
*/
async function main() {
await campaignAreaUtil.campaignAreaMain()
let ms = 600
await campaignAreaUtil.dailyCommissionMain()
await sleep(ms*2);
await campaignAreaUtil.campaignAreaMain(false)
await sleep(ms*2);
await toMainUi()
await activityUtil.activityMain()
}

View File

@@ -1,6 +1,6 @@
{
"name": "活动期限/周本通知器",
"version": "0.0.6",
"version": "0.0.7",
"description": "",
"settings_ui": "settings.json",
"main": "main.js",

View File

@@ -17,10 +17,50 @@ const config = {
}
const ocrRegionConfig = {
weeklyCount: {x: 809, y: 258, width: 277, height: 37},//征讨领域减半次数识别区域坐标和尺寸
dailyCommission: {x: 630, y: 312, width: 105, height: 118},//每日委托识别区域坐标和尺寸
}
const xyConfig = {
campaignArea: {x: 493, y: 537},//征讨领域坐标
secretRealm: {x: 304, y: 448},//秘境坐标
dailyCommission: {x: 266, y: 318},//委托坐标 x=266, y=318, width=69, height=44
}
/**
* 每日委托OCR识别函数
* @param {Object} ocrRegion - OCR识别区域配置默认为ocrRegionConfig.dailyCommission
* @returns {Object} 返回包含每日委托和体力使用情况的对象
*/
async function ocrDailyCommission(ocrRegion = ocrRegionConfig.dailyCommission) {
let captureRegion = captureGameRegion(); // 获取游戏区域截图
try {
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height); // 创建OCR识别对象
// ocrObject.threshold = 1.0;
let resList = captureRegion.findMulti(ocrObject); // 在指定区域进行OCR识别
let dailyCommission = resList[0].text?.trim();
const lastName = dailyCommission.at(dailyCommission.length - 1);
if (dailyCommission.lastIndexOf('1') === 1) {
// 0/4 被识别成==>014
dailyCommission = dailyCommission.replace('1' + lastName, '/' + lastName)
}
const dailyCommissionSplit = dailyCommission.split('/');
// physical
let physical = resList[1].text?.trim();
const physicalSplit = physical.split('/');
return {
daily: {
total: parseInt(dailyCommissionSplit[1]),
use: parseInt(dailyCommissionSplit[0]),
},
physical: {
total: parseInt(physicalSplit[1]),
use: parseInt(physicalSplit[0]),
},
}
} finally {
captureRegion.dispose(); // 释放截图资源
}
}
/**
@@ -31,29 +71,32 @@ const xyConfig = {
*/
async function ocrWeeklyCount(ocrRegion = ocrRegionConfig.weeklyCount) {
let captureRegion = captureGameRegion(); // 获取游戏区域截图
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height); // 创建OCR识别对象
// ocrObject.threshold = 1.0;
let res = captureRegion.find(ocrObject); // 在指定区域进行OCR识别
captureRegion.dispose(); // 释放截图资源
if (!res.isExist()) {
log.error(`ocrWeeklyCount not found`) // 记录错误日志
throw new Error(`ocrWeeklyCount not found`) // 抛出错误异常
}
let weekJson = { // 初始化周计数JSON对象
text: res.text,
total: 3,
count: 3,
}
let weekCountText = res.text // 获取OCR识别的文本结果
let result = weekCountText.match(/[0-9/]+/g)?.join('') || ''; // 使用正则表达式提取数字和斜杠
try {
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height); // 创建OCR识别对象
// ocrObject.threshold = 1.0;
let res = captureRegion.find(ocrObject); // 在指定区域进行OCR识别
if (!res.isExist()) {
log.error(`ocrWeeklyCount not found`) // 记录错误日志
throw new Error(`ocrWeeklyCount not found`) // 抛出错误异常
}
let weekJson = { // 初始化周计数JSON对象
text: res.text,
total: 3,
count: 3,
}
let weekCountText = res.text // 获取OCR识别的文本结果
let result = weekCountText.match(/[0-9/]+/g)?.join('') || ''; // 使用正则表达式提取数字和斜杠
log.debug(`识别结果:{weekCountText}`, weekCountText) // 记录原始识别结果
log.debug(`处理结果:{result}`, result) // 记录处理后的结果
const numbers = result.split('/').map((item) => parseInt(item)); // 分割字符串并转换为数字数组
weekJson.total = numbers[1] // 设置总数
weekJson.count = numbers[0] // 设置当前计数
log.debug(`Json:{weekJson}`, weekJson) // 记录最终JSON结果
return weekJson // 返回处理后的周计数JSON对象
log.debug(`识别结果:{weekCountText}`, weekCountText) // 记录原始识别结果
log.debug(`处理结果:{result}`, result) // 记录处理后的结果
const numbers = result.split('/').map((item) => parseInt(item)); // 分割字符串并转换为数字数组
weekJson.total = numbers[1] // 设置总数
weekJson.count = numbers[0] // 设置当前计数
log.debug(`Json:{weekJson}`, weekJson) // 记录最终JSON结果
return weekJson // 返回处理后的周计数JSON对象
} finally {
captureRegion.dispose(); // 释放截图资源
}
}
/**
@@ -82,7 +125,7 @@ async function getDayOfWeek() {
* 执行秘境征讨剩余次数提醒的主函数
* 该函数会在每周日执行,检查秘境征讨的剩余次数并发送提醒
*/
async function campaignAreaMain() {
async function campaignAreaMain(openKey = true) {
// 获取当前星期信息
let dayOfWeek = await getDayOfWeek();
// 如果不是周日(0代表周日),则直接返回
@@ -94,10 +137,12 @@ async function campaignAreaMain() {
}
// 设置操作间隔时间(毫秒)
let ms = 600
// 等待一段时间
await sleep(ms)
// 按下配置的热键
await keyPress(config.campaignAreaKey)
if (openKey) {
// 等待一段时间
await sleep(ms)
// 按下配置的热键
await keyPress(config.campaignAreaKey)
}
await sleep(ms * 2)
// 点击秘境入口坐标
await click(xyConfig.secretRealm.x, xyConfig.secretRealm.y)
@@ -117,6 +162,41 @@ async function campaignAreaMain() {
}
/**
* 每日委托主函数
* @param {boolean} openKey - 是否开启热键功能默认为true
* @returns {Promise<void>}
*/
async function dailyCommissionMain(openKey = true) {
// 获取当前星期信息
let dayOfWeek = await getDayOfWeek();
// 如果不是周日(0代表周日)
const bool = dayOfWeek.day != config.campaignAreaReminderDay;
// 设置操作间隔时间(毫秒)
let ms = 600
// 等待一段时间
await sleep(ms)
if (openKey || bool) {
// 按下配置的热键
await keyPress(config.campaignAreaKey)
}
await sleep(ms * 2)
// 点击秘境入口坐标
await click(xyConfig.dailyCommission.x, xyConfig.dailyCommission.y)
await sleep(ms * 2)
const re = await ocrDailyCommission();
log.debug(`dailyCommission:{re}`, re)
// 如果有每日未完成/领取,则记录日志并发送通知
if (re.daily.total > re.daily.use
|| re.physical.total > re.physical.use
) {
let uid = await uidUtil.ocrUID()
await noticeUtil.sendText(`>|每日委托奖励:${re.daily.use}/${re.daily.total}\n>|原粹树脂消耗:${re.physical.use}/${re.physical.total}`, `UID:${uid}\n每日委托`)
}
}
this.campaignAreaUtil = {
campaignAreaMain,
dailyCommissionMain,
}