Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# 九号出行自动签到脚本

这是一个用于九号出行自动签到的 Node.js 脚本,基于 [wan-kong/ninebot-sign](https://github.com/wan-kong/ninebot-sign) 修改,新增了一些内容。
这是一个用于九号出行自动签到的 Node.js 脚本,基于 [waistu/Ninebot][(https://github.com/waistu/Ninebot)](https://github.com/waistu/Ninebot) 修改,新增了一些内容。

# 功能特点

- 💻本地运行
- ✅自动签到 (GitHub Actions & 青龙面板)
- 👋单账号/多账号签到
- 🔔Bark 通知推送
- 🔔企业微信应用推送

# 所需依赖

Expand All @@ -27,7 +28,17 @@
|`BARK_URL`|`https://api.day.app`(默认值)|❌|选填,自定义 BARK 服务器地址(默认官方地址)|
|`BARK_GROUP`|`九号签到`(推送分组名称)|❌|选填,推送消息的分组标签|
|`BARK_ICON`|`https://example.com/icon.png`(图标 URL)|❌|选填,推送消息显示的图标|
|`BARK_SOUND`|`chime`(铃声名称)|❌|选填,推送消息的铃声(默认 `bell`,支持 `chime`、`alarm` 等)|
|`BARK_SOUND`|`chime`(铃声名称)|❌|选填,推送消息的铃声(默认 `bell`,支持 `chime`、`alarm` 等)|
|`WECOM_CORP_ID`|`ww1234567890abcdef`(企业 ID)|❌|选填,企业微信管理后台「我的企业」页面获取|
|`WECOM_CORP_SECRET`|`xxxxxxxxxxxxxxxxxxxxxxxx`(应用 Secret)|❌|选填,企业微信管理后台对应应用的 Secret|
|`WECOM_AGENT_ID`|`1000002`(应用 AgentId)|❌|选填,企业微信管理后台对应应用的 AgentId|
|`WECOM_PROXY_URL`|`https://qyapi.weixin.qq.com`(默认值)|❌|选填,企业微信 API 代理地址(默认官方地址,可替换为自建代理)|
|`WECOM_TO_USER`|`UserID1\|UserID2` 或 `@all`(默认 `@all`)|❌|选填,消息接收人,默认发送给全体成员|
|`WECOM_TO_PARTY`|`1\|2`(部门 ID 列表)|❌|选填,发送给指定部门|
|`WECOM_TO_TAG`|`1\|2`(标签 ID 列表)|❌|选填,发送给指定标签下的成员|
|`WECOM_MSG_TYPE`|`text` / `textcard` / `markdown`(默认 `text`)|❌|选填,消息类型:纯文本 / 文本卡片 / Markdown|
|`WECOM_CARD_URL`|`https://h5-bj.ninebot.com`(默认值)|❌|选填,文本卡片消息点击后跳转的 URL(仅 `textcard` 类型生效)|
|`WECOM_CARD_BTN`|`查看详情`(默认值)|❌|选填,文本卡片消息按钮文字(仅 `textcard` 类型生效)|


# 使用方法
Expand Down Expand Up @@ -76,6 +87,15 @@ BARK_URL=https://api.day.app # 默认使用 APP 自带服务器
# BARK_GROUP=九号签到通知 # 通知分组
# BARK_ICON=https://xxx.png # 通知图标URL
# BARK_SOUND=bell # 通知铃声

# 企业微信应用推送相关(可选,需要则配置)

# WECOM_CORP_ID=你的企业ID # 企业微信管理后台「我的企业」获取
# WECOM_CORP_SECRET=你的应用Secret # 应用管理页面获取
# WECOM_AGENT_ID=你的应用AgentId # 应用管理页面获取
# WECOM_PROXY_URL=https://qyapi.weixin.qq.com # 企业微信API代理地址,默认官方地址
# WECOM_TO_USER=@all # 接收人,默认@all
# WECOM_MSG_TYPE=text # 消息类型:text / textcard / markdown
```

4. 运行脚本
Expand All @@ -86,7 +106,7 @@ npm start

## 青龙面板

1. 添加订阅 https://github.com/waistu/Ninebot.git
1. 添加订阅 [https://github.com/waistu/Ninebot.git](https://github.com/cheny95/Ninebot.git)
2. 安装NodeJs 依赖:axios、moment、dotenv
3. 添加环境变量
4. 修改任务定时
Expand Down
99 changes: 96 additions & 3 deletions sign_ninebot.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,96 @@ async function sendBarkNotification(title, message) {
}
}

// 发送企业微信应用推送
async function sendWeComNotification(title, message) {
// 从环境变量获取企业微信配置
const corpId = process.env.WECOM_CORP_ID; // 企业ID
const corpSecret = process.env.WECOM_CORP_SECRET; // 应用Secret
const agentId = process.env.WECOM_AGENT_ID; // 应用AgentId
const toUser = process.env.WECOM_TO_USER || "@all"; // 接收人,默认@all全体
const proxyUrl = (process.env.WECOM_PROXY_URL || "https://qyapi.weixin.qq.com").replace(/\/+$/, ""); // 代理地址,默认官方API

// 缺少必要配置则跳过
if (!corpId || !corpSecret || !agentId) {
console.log("未配置企业微信应用推送(WECOM_CORP_ID / WECOM_CORP_SECRET / WECOM_AGENT_ID),跳过企业微信通知");
return false;
}

try {
// 第一步:获取 access_token
console.log(`企业微信: 正在获取access_token...(API地址: ${proxyUrl})`);
const tokenUrl = `${proxyUrl}/cgi-bin/gettoken?corpid=${corpId}&corpsecret=${corpSecret}`;
const tokenRes = await axios.get(tokenUrl, { timeout: 5000 });

if (tokenRes.data.errcode !== 0) {
console.error("企业微信获取access_token失败:", tokenRes.data.errmsg);
return false;
}

const accessToken = tokenRes.data.access_token;
console.log("企业微信: access_token获取成功");

// 第二步:构建消息体
// 判断消息类型:支持文本卡片(textcard)或纯文本(text)
const msgType = process.env.WECOM_MSG_TYPE || "text"; // 默认文本消息

let msgBody = {
touser: toUser,
agentid: parseInt(agentId),
safe: 0,
};

// 如果配置了发送给指定部门
if (process.env.WECOM_TO_PARTY) {
msgBody.toparty = process.env.WECOM_TO_PARTY;
}

// 如果配置了发送给指定标签
if (process.env.WECOM_TO_TAG) {
msgBody.totag = process.env.WECOM_TO_TAG;
}

if (msgType === "textcard") {
// 文本卡片消息
msgBody.msgtype = "textcard";
msgBody.textcard = {
title: title,
description: message.replace(/\n/g, "<br>"),
url: process.env.WECOM_CARD_URL || "https://h5-bj.ninebot.com",
btntxt: process.env.WECOM_CARD_BTN || "查看详情"
};
} else if (msgType === "markdown") {
// Markdown消息(仅企业微信内部支持,不支持微信插件)
msgBody.msgtype = "markdown";
msgBody.markdown = {
content: `## ${title}\n${message}`
};
} else {
// 默认纯文本消息
msgBody.msgtype = "text";
msgBody.text = {
content: `${title}\n\n${message}`
};
}

// 第三步:发送消息
const sendUrl = `${proxyUrl}/cgi-bin/message/send?access_token=${accessToken}`;
console.log("企业微信: 正在发送消息...");
const sendRes = await axios.post(sendUrl, msgBody, { timeout: 5000 });

if (sendRes.data.errcode === 0) {
console.log("企业微信应用推送发送成功");
return true;
} else {
console.error("企业微信应用推送发送失败:", sendRes.data.errmsg);
return false;
}
} catch (error) {
console.error("发送企业微信通知异常:", error.message);
return false;
}
}

// 初始化并执行签到
async function init() {
// 处理多账号配置
Expand Down Expand Up @@ -335,11 +425,14 @@ async function init() {
const title = "九号出行签到结果";
let message = allResults.map(acc => {
const status = acc.success ? "✅" : "❌";
return `${status} ${acc.name}\n${acc.logs.replace(/\n/g, "\n ")}`;
return `${status} ${acc.name}\n${acc.logs.replace(/\n/g, "\n")}`;
}).join("\n\n");

// 发送Bark通知
await sendBarkNotification(title, message);
// 发送通知(并行发送,互不影响)
await Promise.allSettled([
sendBarkNotification(title, message),
sendWeComNotification(title, message)
]);
}

// 启动执行
Expand Down