Skip to content

Commit 8fc53a1

Browse files
committed
Improve setup flow and add guides
1 parent 61b1626 commit 8fc53a1

4 files changed

Lines changed: 250 additions & 5 deletions

File tree

ADMIN_GUIDE.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# EchoWaveBot 群管理员使用指南
2+
3+
面向群管理员/运营,说明需要给 Bot 的权限、日常操作方法、最佳实践。
4+
5+
## 1. 必须赋予的权限
6+
请确保在目标群把 Bot 设为管理员,并勾选:
7+
- 发送消息
8+
- 删除消息(清理验证消息等,推荐开启)
9+
- 邀请用户/创建邀请链接(若希望机器人自动生成入群按钮)
10+
- 管理话题(如使用话题路由广播)
11+
- 限制成员/解除限制(用于入群验证禁言/解禁)
12+
- 查看管理员列表(用于商城核销时验证身份)
13+
14+
## 2. 管理指令(仅管理员或终极管理员)
15+
- `/setup`(私聊):配置群欢迎/验证、积分规则、订阅路由、段位表等。
16+
- `/add_product`(私聊):上架商品。
17+
- `/products`(私聊):管理/下架商品。
18+
- `/use <核销码>`(私聊):核销订单(需在该群拥有管理员权限)。
19+
- `/request_broadcast`(群内):申请成为广播群。
20+
- `/set_topic <news|analysis|marketing|signal>`(在目标话题发送):将当前话题绑定为某类型的广播路由。(仅终极管理员)
21+
- `/report``/revoke <chat_id>`(终极管理员):审计群列表、移除广播权限。
22+
- `/id`:查看当前聊天 ID(便于配置)。
23+
24+
## 3. 配置与运营流程
25+
### 3.1 入群验证与欢迎语
26+
-`/setup` 中可开启/关闭验证码、欢迎语,并自定义欢迎文本(支持 `{name}` 占位)。
27+
- 确保 Bot 有“限制/解除限制”权限,否则无法禁言/解禁新人。
28+
29+
### 3.2 积分规则
30+
- `/setup` 可设置:
31+
- 签到口令与奖励分值。
32+
- 晒单关键词与奖励分值(盈/损),每日上限(-2 表示不限)。
33+
- 段位表 JSON,用于 `/my` 的称号展示。
34+
### 3.3 邀请与入群按钮
35+
- 邀请链接:成员在私聊 `/invite` 选择群生成。若 Bot 无法生成入群按钮,说明缺少“邀请用户/创建链接”权限,或可在群公告提供固定入群链接。
36+
37+
### 3.4 广播(多群分发)
38+
- 群管理员在群内 `/request_broadcast` → 终极管理员批准后,该群加入广播列表。
39+
- 终极管理员在自己的管理群/话题发消息,Bot 弹出类型选择(早报/分析/战绩/信号/General)→ 按群订阅状态、话题绑定进行分发。
40+
- 话题路由:在目标话题里发 `/set_topic <类型>` 绑定,同类型广播会发到该话题。
41+
- 如群被踢或不存在,Bot 会自动关闭该群的广播标记。
42+
43+
### 3.5 商城与核销
44+
- 上架:私聊 `/add_product` → 选群 → 传图(可跳过)→ 输入“价格 商品名”。
45+
- 管理:`/products` 列出商品并下架。
46+
- 购买:用户在群里 `/shop` 购买,扣积分后生成核销码。
47+
- 核销:管理员在私聊 `/use <核销码>`,Bot 会校验你是否是该订单所属群的管理员。
48+
49+
## 4. 最佳实践
50+
- 权限先给全套(见第 1 节),问题减少;如需最小化,至少保留:发送消息、限制成员/解除限制、管理话题(若用话题路由)、查看管理员(核销)、邀请成员(想自动生成入群按钮时)。
51+
- 设定清晰的签到口令、晒单关键词,并在群公告或欢迎语中说明奖励规则和上限。
52+
- 定期用 `/report` 审核广播群状态,停用僵尸群。
53+
- 商城核销建议使用私聊,避免群内刷屏;核销时注意身份验证提醒用户只向管理员提供核销码。
54+
- 更新部署后,若遇到指令失效或菜单未更新,可重启 Bot 或在 BotFather 重新设置命令。
55+
56+
## 5. 常见问题
57+
- `/invite` 生成的邀请里没有入群按钮:检查 Bot 是否有“邀请成员/创建链接”权限,或提供固定邀请链接字段由 Bot 发送。
58+
- 新人验证后不能发图/视频:确保 Bot 能解禁;当前版本已全量开启媒体权限。
59+
- `/report` 无响应:确认 `.env` 的 ADMIN_GROUP_ID 填写并可被解析,且你使用的是对应的终极管理员账号/聊天。
60+
- 购买后用户未收到私聊:用户可能未开启私聊;群消息会提示核销码,提醒用户复制并私发管理员。

GUIDE.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# EchoWaveBot 使用与部署指南
2+
3+
本指南面向运营/管理员,涵盖环境准备、功能说明、数据位置、部署与排障。假设你已拥有一个 Telegram Bot Token,并能把 Bot 拉进你的群组。
4+
5+
## 1. 环境与配置
6+
- Python 3.13(本地调试)或 Docker(推荐生产)。
7+
- 依赖:见 `requirements.txt`,主要包括 `python-telegram-bot[job-queue]``aiosqlite``httpx``python-dotenv`
8+
- 必填环境变量(`.env`):
9+
- `BOT_TOKEN`:BotFather 生成的 token。
10+
- `ADMIN_GROUP_ID`:超级管理员 ID,可填个人 user_id(推荐)或一个“管理员群” chat_id。只有它能使用 `/report``/revoke``/set_topic`
11+
- 数据文件(默认值与位置):
12+
- SQLite DB:`echowave.db`(当前代码指向项目根;若按生产部署方案,则在容器内 `/app/echowave.db`,挂载宿主 `/root/echowave.db`)。
13+
- 旧版 JSON 数据:`bot_data.json`(首次启动会尝试迁移到 DB,迁移后会重命名为 `.bak`)。
14+
- 段位默认值:`{"0":"🌱茁壮韭菜", "100":"💎钻石双手", "500":"🐋潜水巨鲸", "2000":"📈K线主宰", "5000":"🚀交易战神"}`(初始化时写入 groups.rank_config)。
15+
16+
## 2. 本地运行(非 Docker)
17+
1) `python -m venv .venv && source .venv/bin/activate`
18+
2) `pip install -r requirements.txt`
19+
3) 创建 `.env`,填入 `BOT_TOKEN``ADMIN_GROUP_ID`
20+
4) 运行 `python main.py`。启动后日志显示 “EchoWave Pro Max (SQLite Edition) 已启动…”。
21+
22+
## 3. 功能总览
23+
- 公共指令:`/shop`(积分商城)、`/invite`(邀请好友)、`/my`(我的积分)、`/top`(积分榜)、`/fear`(恐慌贪婪指数)、`/help`
24+
- 管理员/高级指令:
25+
- 终极管理员(ADMIN_ID):`/report``/revoke <chat_id>``/set_topic <news|analysis|marketing|signal>``/request_broadcast`
26+
- 群管理员:`/request_broadcast`
27+
- 私聊管理员工具:`/setup`(配置群)、`/add_product``/products``/use <code>`
28+
- 互动与积分规则(默认):
29+
- 签到口令:`恒智牛逼`(可在 `/setup` 修改)。
30+
- 晒单关键词:盈/吃肉 → `kw_profit`,损/止损 → `kw_loss`(默认可在 `/setup` 设置,积分默认 50/30;示例数据为 20/20)。
31+
- 每日晒单上限:5 次(-2 表示不限)。
32+
- 邀请奖励:15 分(通过验证后触发)。
33+
34+
## 4. 核心流程
35+
### 4.1 入群验证与邀请
36+
- 新人进群(非 Bot)会被禁言并收到验证按钮。超时未验证将被封禁后解禁。
37+
- 通过验证后:
38+
- 标记为已验证;
39+
- 若是通过邀请链接(`https://t.me/<bot>?start=ref_<referrerId>_<groupId>`),邀请人得积分奖励;
40+
- 发送欢迎语(支持 `{name}` 占位符)。
41+
- 邀请链接生成:私聊 `/invite` → 选择一个你已经有积分记录的群(users 表里有记录即可)→ Bot 返回带 group_id 的 deep link。管理员需确保 Bot 在目标群且有生成邀请链接权限,否则无法附带入群按钮。
42+
43+
### 4.2 配置面板 `/setup`(仅私聊、群管理员)
44+
- 进入后选择要配置的群。面板项目:
45+
- 开关:欢迎语、验证码、各类型订阅(早报/分析/战绩/信号)、暂停广播。
46+
- 路由:topic ID 绑定(早报/分析/战绩/信号)。
47+
- 欢迎语、签到口令、晒单关键词、各积分数值、段位表 JSON、晒单上限。
48+
- 注意:`/setup` 是会话式指令。若被卡在会话里影响其他回调,请使用关闭/返回或 `/cancel` 结束。
49+
50+
### 4.3 广播与话题绑定
51+
- 在群内 `/request_broadcast` 向 ADMIN_ID 申请;终极管理员批准后该群标记为广播群。
52+
- 终极管理员发消息(常在 ADMIN_ID 对应的聊天/话题)→ Bot弹出类型选择 → 分发到订阅了对应类型的群,支持按话题发送。
53+
- 回执会尝试用原话题回复,找不到则发到 General。
54+
- 如果群不存在/被踢,会自动关闭该群的广播标记。
55+
56+
### 4.4 商城
57+
- `/add_product`(私聊,管理员):选择群→传图(可跳过)→“价格 商品名”→上架。
58+
- `/products`(私聊,管理员):列出商品,点击“下架”。
59+
- `/shop`(群内):列出商品列表,带“购买”按钮。
60+
- 购买流程:扣积分→生成核销码 ORD-XXXXXX → 私聊买家发送核销信息(若无法私聊则回到群提示)。管理员 `/use <code>` 核销,校验管理员身份(需在订单所属群有 admin 权限)。
61+
62+
### 4.5 积分&榜单
63+
- `/my`:当前积分(points),历史总分(total_points),段位基于 total_points。
64+
- `/top`:按当前积分排序显示前 10。
65+
- 积分获取:签到、晒单(盈/亏),邀请奖励。
66+
67+
## 5. 部署(Docker)
68+
### 5.1 镜像构建
69+
- 已提供 `Dockerfile`:基于 `python:3.13-slim`,设置时区为上海,安装依赖后 `CMD ["python", "main.py"]`
70+
- 推荐新增 `.dockerignore`(如排除 `.env``.venv`、本地 DB/WAL/SHM、`__pycache__` 等)。
71+
72+
### 5.2 数据持久化
73+
- 默认 DB 路径:`/app/echowave.db`。必须通过 volume 将宿主机文件或目录挂载进容器,避免重建容器丢数据。
74+
- 现有 GitHub Action 部署脚本(`.github/workflows/deploy.yml` 示例)挂载方式:
75+
- `-v /root/bot_data.json:/app/bot_data.json`
76+
- `-v /root/echowave.db:/app/echowave.db`
77+
- 如果你改成目录挂载(推荐):把代码里的 DB_FILE 指向 `data/echowave.db`,运行容器时 `-v /root/bot_data:/app/data`,WAL/SHM 也会被持久化。
78+
79+
### 5.3 GitHub Action 示例要点
80+
- main 分支推送触发,构建并推送镜像到 Docker Hub。
81+
- SSH 到 VPS,拉取最新镜像,停止旧容器,挂载数据文件后重新运行:
82+
```
83+
docker run -d \
84+
--name echowave \
85+
--restart always \
86+
-v /root/bot_data.json:/app/bot_data.json \
87+
-v /root/echowave.db:/app/echowave.db \
88+
--env-file /root/.env \
89+
jerry113/echowave:latest
90+
```
91+
- 确保 `/root/.env` 存在且含 BOT_TOKEN/ADMIN_GROUP_ID。
92+
93+
## 6. 常见问题与排障
94+
- `/invite` 生成后没有入群按钮:Bot 在目标群没有创建邀请链接权限或不在群。解决:赋予生成链接权限或增加一个“自填邀请链接”字段作为兜底。
95+
- `/invite` 选择群后跳到 `/setup`:旧设计下 setup 会话会截获回调,需要给 setup 的 CallbackQueryHandler 加 pattern 或手动结束会话(本仓库已修复)。
96+
- `/report` 无响应:ADMIN_ID 未正确解析(.env 错误/空),或你不是 ADMIN_ID/所在聊天不是 ADMIN_ID。
97+
- `/report` 订阅只显示“早,信”:旧版漏掉“析”“战”,已在 `handlers/admin.py` 修复。
98+
- 新人验证后仍无法发图/视频:需使用 `ChatPermissions` 的关键字参数覆盖全部媒体字段(本仓库已修复)。
99+
- 数据丢失:检查容器启动命令是否正确挂载 DB 文件/目录。
100+
- 无法推送/拉取镜像:确认网络代理及 Docker Hub 凭证;CI 使用的代理可能导致 127.0.0.1:7890 连接失败。
101+
102+
## 7. 表结构概览(简述)
103+
- `groups`:群配置(订阅开关、topic、欢迎语、积分规则、段位表)。
104+
- `users`:群内用户积分、签到/晒单计数、邀请人、验证状态。
105+
- `message_map`:管理员消息 ID 与各群回执消息 ID 的映射(用于追踪回复)。
106+
- `pending_req`:广播申请队列。
107+
- `admin_topic_mappings`:管理员话题 -> 类型绑定。
108+
- `products` / `orders`:商城商品与订单(核销码)。
109+
110+
## 8. 快速检查清单
111+
1) `.env` 填了 BOT_TOKEN、ADMIN_GROUP_ID。
112+
2) Bot 已加入目标群且是管理员(必要权限:禁言/解禁、发送消息、创建邀请链接(可选)、管理话题(如需话题路由)、读取管理员列表(核销鉴权))。
113+
3) 部署时挂载了 DB 文件/目录;首次运行后确认 DB 文件大小有增长。
114+
4) 终极管理员(ADMIN_ID)能在私聊执行 `/report`;群内管理员能 `/setup`
115+
5) `/invite` 生成的链接能打开,若无按钮检查 Bot 邀请权限或提供手动链接。

USER_GUIDE.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# EchoWaveBot 用户使用指南
2+
3+
这份指南面向普通群成员,教你如何在群里使用 EchoWaveBot 赚钱积分、兑换商品、查看排行。
4+
5+
## 1. 快速上手
6+
1) 加入群 → 点击机器人弹出的验证按钮完成真人验证(必须通过才能发言和获取积分)。
7+
2) 每日签到:在群里发送签到口令即可得分(默认口令为管理员设置,进群欢迎语或群公告会写明)。
8+
3) 晒单得分:按群规则发送带关键词的图片(收益/亏损),可获得奖励积分。
9+
4) 邀请好友:私聊机器人 `/invite` 生成专属链接,好友通过链接加入群并验证后,你获得邀请积分。
10+
5) 积分商城:在群里发 `/shop` 查看商品,直接用积分兑换。
11+
6) 查看个人与排行:`/my` 查看自己的积分、段位;`/top` 查看群积分榜。
12+
13+
## 2. 可用指令(群内)
14+
- `/shop`:查看本群可兑换的商品,点“购买”按钮扣积分并生成核销码。
15+
- `/invite`(请先私聊机器人使用):生成你的专属邀请链接。
16+
- `/my`:查看当前积分、历史总分和段位。
17+
- `/top`:查看本群积分排行榜。
18+
- `/fear`:查看恐慌贪婪指数。
19+
- `/help`:指令帮助。
20+
21+
## 3. 积分规则(具体数值以管理员设置为准)
22+
- 签到:发送指定口令得分(每天一次)。
23+
- 晒单:在图片描述/文字中包含群设定的“晒盈/晒损”关键词即可得分;每日有次数上限(默认 5 次,-2 表示不限)。
24+
- 邀请:好友通过你的邀请链接加入并完成验证,你获得邀请奖励积分。
25+
- 段位:根据历史总分(total_points)评定称号,当前积分(points)用于兑换商品。
26+
27+
## 4. 商城与核销
28+
1) 在群里 `/shop` → 点商品的“购买”按钮 → 扣除积分并生成核销码(若能私聊,机器人会把核销码发到私聊;否则会在群里提示)。
29+
2) 将核销码私发给群管理员兑换(管理员会用 `/use <核销码>` 核销)。
30+
31+
## 5. 常见问题
32+
- 看不到“验证”按钮或无法发言:先在群里完成验证;若按钮点不了,联系管理员解禁。
33+
- `/invite` 没有入群按钮:可能机器人在该群没有生成邀请链接的权限,联系管理员提供固定入群链接。
34+
- 购买后没收到私聊消息:可能你没开启与机器人的私聊。查看群内提示文字,核销码会显示在群里,复制后私发管理员。
35+
- `/my``/top` 没反应:这些指令只能在群里用;确认机器人已在群内且未被限制。
36+
37+
## 6. 安全提示
38+
- 不要相信任何自称管理员的私聊索要资产或验证码。
39+
- 核销码只用于群内兑换商品,不要泄露给陌生人。

handlers/setup.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ async def setup_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
3636
kb = [[InlineKeyboardButton(g["title"], callback_data=f"root_{g['id']}")] for g in groups]
3737
kb.append([InlineKeyboardButton("❌ 关闭菜单", callback_data="close_setup")])
3838

39-
await reply_func("🛠 **选择配置群组:**", reply_markup=InlineKeyboardMarkup(kb))
39+
# 如果之前有卡住的会话,提示重启
40+
prefix = "♻️ 已重启配置,旧菜单可忽略。\n\n" if context.user_data.get("setup_active") else ""
41+
context.user_data["setup_active"] = True
42+
await reply_func(f"{prefix}🛠 **选择配置群组:**", reply_markup=InlineKeyboardMarkup(kb))
4043
return STATE_MENU
4144

4245
async def setup_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -47,6 +50,7 @@ async def setup_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE
4750
# [修改] 处理关闭逻辑
4851
if data == "close_setup":
4952
await query.edit_message_text("✅ 配置已结束")
53+
context.user_data.pop("setup_active", None)
5054
return ConversationHandler.END
5155

5256
if data == "back": return await setup_start(update, context)
@@ -59,6 +63,7 @@ async def setup_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE
5963

6064
if not info:
6165
await query.edit_message_text("❌ 读库失败")
66+
context.user_data.pop("setup_active", None)
6267
return ConversationHandler.END
6368

6469
# --- 开关逻辑 ---
@@ -149,7 +154,14 @@ def limit_str(v): return "♾️无限" if v == -2 else f"{v}次"
149154
[InlineKeyboardButton("🔙 返回列表", callback_data="back"), InlineKeyboardButton("❌ 关闭菜单", callback_data="close_setup")]
150155
]
151156

152-
await query.edit_message_text(txt, reply_markup=InlineKeyboardMarkup(kb), parse_mode=ParseMode.MARKDOWN)
157+
try:
158+
await query.edit_message_text(txt, reply_markup=InlineKeyboardMarkup(kb), parse_mode=ParseMode.MARKDOWN)
159+
except Exception:
160+
try:
161+
await query.answer("会话已过期,请重新 /setup", show_alert=True)
162+
except: pass
163+
context.user_data.pop("setup_active", None)
164+
return ConversationHandler.END
153165
return STATE_MENU
154166

155167
async def save_input(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -196,13 +208,32 @@ async def save_input(update: Update, context: ContextTypes.DEFAULT_TYPE):
196208

197209
async def cancel(u, c): await u.message.reply_text("已取消"); return ConversationHandler.END
198210

211+
async def input_nav_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
212+
"""允许在输入状态也能关闭/返回"""
213+
query = update.callback_query
214+
data = query.data
215+
await query.answer()
216+
if data == "close_setup":
217+
try: await query.edit_message_text("✅ 配置已结束")
218+
except: pass
219+
context.user_data.pop("setup_active", None)
220+
return ConversationHandler.END
221+
if data == "back":
222+
return await setup_start(update, context)
223+
return ConversationHandler.END
224+
199225
setup_handler = ConversationHandler(
200226
entry_points=[CommandHandler("setup", setup_start)],
201227
states={
202228
# [关键修复] 增加 pattern,只捕获 setup 相关的按钮
203229
# 这样其他功能的按钮(如 inv_sel_, buy_ 等)就会穿透过去,不会被这里截获
204230
STATE_MENU: [CallbackQueryHandler(setup_menu_callback, pattern="^(root_|tg_|set_|back|close_setup)")],
205-
STATE_INPUT_GENERIC: [MessageHandler(filters.TEXT & ~filters.COMMAND, save_input)]
231+
STATE_INPUT_GENERIC: [
232+
MessageHandler(filters.TEXT & ~filters.COMMAND, save_input),
233+
CallbackQueryHandler(input_nav_callback, pattern="^(back|close_setup)$")
234+
]
206235
},
207-
fallbacks=[CommandHandler("cancel", cancel)]
208-
)
236+
fallbacks=[CommandHandler("cancel", cancel)],
237+
conversation_timeout=180,
238+
allow_reentry=True
239+
)

0 commit comments

Comments
 (0)