ONLINE

任务管理

共 3 条任务
0
待处理
0
执行中
0
已完成
0
失败
任务列表
ID 任务名称 状态 执行结果 创建时间
3 好的,我们开始。以下是为您生成的详细项目开发任务描述。 completed # TG USDT 地址监控机器人 - 完整实现 ## 项目结构 ``` tg_usdt_monitor/ ├── .env ├── requirements.txt ├── main.py ├── bot/ │ ├── __init__.py │ ├── handlers.py │ ├── monitor.py │ └── keyboards.py ├── db/ │ ├── __init__.py │ └── database.py ├── services/ │ ├── __init__.py │ ├── blockchain.py │ └── validator.py └── utils/ ├── __init__.py └── helpers.py ``` --- ## 配置文件 ### `.env` ```env # Telegram Bot Token (从 @BotFather 获取) BOT_TOKEN=your_telegram_bot_token_here # TronGrid API Key (https://www.trongrid.io/) TRONGRID_API_KEY=your_trongrid_api_key_here # BSCScan API Key (https://bscscan.com/apis) BSCSCAN_API_KEY=your_bscscan_api_key_here # 监控轮询间隔(秒) MONITOR_INTERVAL=60 # 每次查询获取的最大交易数 MAX_TRANSACTIONS=50 ``` ### `requirements.txt` ```txt python-telegram-bot==20.7 httpx==0.26.0 python-dotenv==1.0.0 aiosqlite==0.19.0 ``` --- ## 数据库层 ### `db/database.py` ```python import aiosqlite import logging from datetime import datetime from typing import Optional logger = logging.getLogger(__name__) DB_PATH = "monitor.db" async def init_db(): """初始化数据库,创建所需表""" async with aiosqlite.connect(DB_PATH) as db: # 监控列表表:存储 chat_id 与 address 的对应关系 await db.execute(""" CREATE TABLE IF NOT EXISTS monitor_list ( id INTEGER PRIMARY KEY AUTOINCREMENT, chat_id INTEGER NOT NULL, address TEXT NOT NULL, chain TEXT NOT NULL, -- 'TRC20' 或 'BEP20' label TEXT, -- 用户自定义标签 added_at TEXT NOT NULL, UNIQUE(chat_id, address) ) """) # 地址状态表:记录每个地址最后一次检查的交易哈希 await db.execute(""" CREATE TABLE IF NOT EXISTS address_state ( address TEXT PRIMARY KEY, chain TEXT NOT NULL, last_tx_hash TEXT, -- 最新的交易哈希 last_checked_at TEXT, total_received REAL DEFAULT 0 ) """) # 交易记录表:避免重复推送 await db.execute(""" CREATE TABLE IF NOT EXISTS sent_transactions ( tx_hash TEXT PRIMARY KEY, address TEXT NOT NULL, pushed_at TEXT NOT NULL ) """) await db.commit() logger.info("数据库初始化完成") async def add_monitor(chat_id: int, address: str, chain: str, label: Optional[str] = None) -> bool: """ 添加监控地址 Returns: True 表示新增成功, False 表示已存在 """ async with aiosqlite.connect(DB_PATH) as db: try: await db.execute( """ INSERT INTO monitor_list (chat_id, address, chain, label, added_at) VALUES (?, ?, ?, ?, ?) """, (chat_id, address, chain, label, datetime.utcnow().isoformat()) ) await db.commit() # 若地址状态表中不存在该地址,则初始化 await db.execute( """ INSERT OR IGNORE INTO address_state (address, chain, last_checked_at) VALUES (?, ?, ?) """, (address, chain, datetime.utcnow().isoformat()) ) await db.commit() return True except aiosqlite.IntegrityError: return False # 已存在该监控关系 async def remove_monitor(chat_id: int, address: str) -> bool: """ 移除监控地址 Returns: True 表示删除成功, False 表示记录不存在 """ async with aiosqlite.connect(DB_PATH) as db: cursor = await db.execute( "DELETE FROM monitor_list WHERE chat_id = ? AND address = ?", (chat_id, address) ) await db.commit() return cursor.rowcount > 0 async def list_monitors(chat_id: int) -> list[dict]: """获取某个 chat_id 的所有监控地址""" async with aiosqlite.connect(DB_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( """ SELECT ml.address, ml.chain, ml.label, ml.added_at, ads.last_tx_hash, ads.last_checked_at, ads.total_received FROM monitor_list ml LEFT JOIN address_state ads ON ml.address = ads.address WHERE ml.chat_id = ? ORDER BY ml.added_at DESC """, (chat_id,) ) rows = await cursor.fetchall() return [dict(row) for row in rows] async def get_all_monitored_addresses() -> list[dict]: """获取所有被监控的唯一地址(供监控任务使用)""" async with aiosqlite.connect(DB_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( """ SELECT DISTINCT address, chain FROM monitor_list """ ) rows = await cursor.fetchall() return [dict(row) for row in rows] async def get_subscribers(address: str) -> list[int]: """获取订阅了某个地址的所有 chat_id""" async with aiosqlite.connect(DB_PATH) as db: cursor = await db.execute( "SELECT chat_id FROM monitor_list WHERE address = ?", (address,) ) rows = await cursor.fetchall() return [row[0] for row in rows] async def get_address_state(address: str) -> Optional[dict]: """获取地址状态""" async with aiosqlite.connect(DB_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT * FROM address_state WHERE address = ?", (address,) ) row = await cursor.fetchone() return dict(row) if row else None async def update_address_state(address: str, last_tx_hash: str, total_received: float): """更新地址状态""" async with aiosqlite.connect(DB_PATH) as db: await db.execute( """ UPDATE address_state SET last_tx_hash = ?, last_checked_at = ?, total_received = ? WHERE address = ? """, (last_tx_hash, datetime.utcnow().isoformat(), total_received, address) ) await db.commit() async def is_tx_sent(tx_hash: str) -> bool: """检查某交易是否已推送过""" async with aiosqlite.connect(DB_PATH) as db: cursor = await db.execute( "SELECT 1 FROM sent_transactions WHERE tx_hash = ?", (tx_hash,) ) return await cursor.fetchone() is not None async def mark_tx_sent(tx_hash: str, address: str): """标记交易已推送""" async with aiosqlite.connect(DB_PATH) as db: await db.execute( """ INSERT OR IGNORE INTO sent_transactions (tx_hash, address, pushed_at) VALUES (?, ?, ?) """, (tx_hash, address, datetime.utcnow().isoformat()) ) await db.commit() async def count_monitors(chat_id: int) -> int: """统计某 chat_id 的监控数量""" async with aiosqlite.connect(DB_PATH) as db: cursor = await db.execute( "SELECT COUNT(*) FROM monitor_list WHERE chat_id = ?", (chat_id,) ) row = await cursor.fetchone() return row[0] ``` --- ## 地址验证服务 ### `services/validator.py` ```python import re from typing import Tuple # TRC20 地址:T 开头,34位 Base58 TRC20_PATTERN = re.compile(r'^T[A-Za-z1-9]{33}$') # BEP20 地址:0x 开头,40位十六进制 BEP20_PATTERN = re.compile(r'^0x[0-9a-fA-F]{40}$') # 单个用户最大监控数量 MAX_MONITORS_PER_USER = 10 def validate_address(address: str) -> Tuple[bool, str]: """ 验证地址格式 Returns: (is_valid, chain_type) chain_type: 'TRC20' | 'BEP20' | '' """ address = address.strip() if TRC20_PATTERN.match(address): return True, "TRC20" if BEP20_PATTERN.match(address): return True, "BEP20" return False, "" def format_address(address: str) -> str: """格式化地址显示(中间省略)""" if len(address) <= 12: return address return f"{address[:6]}...{address[-6:]}" def format_usdt_amount(amount: float) -> str: """格式化 USDT 金额""" if amount >= 1_000_000: return f"{amount / 1_000_000:.2f}M USDT" elif amount >= 1_000: return f"{amount / 1_000:.2f}K USDT" else: return f"{amount:.2f} USDT" ``` --- ## 区块链查询服务 ### `services/blockchain.py` ```python import httpx import logging import os from typing import Optional logger = logging.getLogger(__name__) TRONGRID_API_KEY = os.getenv("TRONGRID_API_KEY", "") BSCSCAN_API_KEY = os.getenv("BSCSCAN_API_KEY", "") # USDT 合约地址 USDT_TRC20_CONTRACT = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" USDT_BEP20_CONTRACT = "0x55d398326f99059ff775485246999027b3197955" # USDT 精度 TRC20_DECIMALS = 1_000_000 # 6位小数 BEP20_DECIMALS = 10**18 # 18位小数 async def fetch_trc20_transactions(address: str, limit: int = 50) -> list[dict]: """ 从 TronGrid 获取 TRC20 USDT 转入交易 """ url = f"https://api.trongrid.io/v1/accounts/{address}/transactions/trc20" params = { "limit": limit, "contract_address": USDT_TRC20_CONTRACT, "only_to": "true", # 只获取转入 "order_by": "block_timestamp,desc" } headers = { "TRON-PRO-API-KEY": TRONGRID_API_KEY, "Accept": "application/json" } try: async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.get(url, params=params, headers=headers) resp.raise_for_status() data = resp.json() transactions = [] for tx in data.get("data", []): # 过滤确认的 USDT 转入交易 if ( tx.get("to") == address and tx.get("token_info", {}).get("address") == USDT_TRC20_CONTRACT ): amount_raw = int(tx.get("value", 0)) amount_usdt = amount_raw / TRC20_DECIMALS transactions.append({ "tx_hash": tx.get("transaction_id", ""), "from_address": tx.get("from", ""), "to_address": tx.get("to", ""), "amount": amount_usdt, "timestamp": tx.get("block_timestamp", 0) // 1000, "chain": "TRC20", "explorer_url": f"https://tronscan.org/#/transaction/{tx.get('transaction_id', '')}" }) return transactions except httpx.HTTPStatusError as e: logger.error(f"TronGrid HTTP 错误 {e.response.status_code}: {address}") return [] except httpx.RequestError as e: logger.error(f"TronGrid 请求错误: {e}") return [] except Exception as e: logger.error(f"TronGrid 未知错误: {e}") return [] async def fetch_bep20_transactions(address: str, limit: int = 50) -> list[dict]: """ 从 BSCScan 获取 BEP20 USDT 转入交易 """ url = "https://api.bscscan.com/api" params = { "module": "account", "action": "tokentx", "contractaddress": USDT_BEP20_CONTRACT, "address": address, "page": 1, "offset": limit, "sort": "desc", "apikey": BSCSCAN_API_KEY } try: async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.get(url, params=params) resp.raise_for_status() data = resp.json() if data.get("status") != "1": if data.get("message") == "No transactions found": return [] logger.warning(f"BSCScan API 返回: {data.get('message')} for {address}") return [] transactions = [] for tx in data.get("result", []): # 只取转入交易 if tx.get("to", "").lower() != address.lower(): continue amount_raw = int(tx.get("value", 0)) amount_usdt = amount_raw / BEP20_DECIMALS tx_hash = tx.get("hash", "") transactions.append({ "tx_hash": tx_hash, "from_address": tx.get("from", ""), "to_address": tx.get("to", ""), "amount": amount_usdt, " 2026-05-10 13:49:22
2 测试代码执行 completed # Python 代码:当前时间 + 九九乘法表 ## 代码实现 ```python import datetime # 打印当前时间 now = datetime.datetime.now() print("=" * 40) print(f" 当前时间:{now.strftime('%Y年%m月%d日 %H:%M:%S')}") print("=" * 40) print() # 打印九九乘法表 print("九九乘法表:") print() for i in range(1, 10): for j in range(1, i + 1): result = i * j print(f"{j}×{i}={result:<2}", end=" ") print() ``` ## 代码说明 | 部分 | 说明 | |------|------| | `datetime.datetime.now()` | 获取当前本地时间 | | `strftime(...)` | 格式化时间为中文友好格式 | | 外层 `for i` | 控制行数(1~9) | | 内层 `for j` | 控制每行的列数(1~i) | | `{result:<2}` | 左对齐,宽度为2,保持对齐美观 | ## 预期输出示例 ``` ======================================== 当前时间:2025年01月23日 14:30:05 ======================================== 九九乘法表: 1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×4=4 2×4=8 3×4=12 4×4=16 1×5=5 2×5=10 3×5=15 4×5=20 5×5=25 1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36 1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49 1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64 1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81 ``` --- ## Summary 以上代码使用 `datetime` 模块获取并格式化当前时间,使用双层 `for` 循环生成下三角形式的九九乘法表。代码结构清晰、无需额外依赖,直接点击"执行"按钮即可看到实时运行结果(时间会显示为实际执行时刻)。 2026-05-10 12:47:50
1 做一个白虎群发的tg助手的说明文档 completed # 白虎TG助手 — 说明文档 > 以下为完整的文档站结构 + 独立发内容后台的实现方案,内容留白供你后台填充。 --- ## 一、文档站结构设计 参考目标站结构,规划如下导航体系: ``` 白虎TG助手 文档站 ├── 🏠 首页(产品介绍 + 快速开始入口) ├── 📖 新手指引 │ ├── 产品简介 │ ├── 功能概览 │ └── 快速上手 ├── 🚀 功能说明 │ ├── 群发消息 │ ├── 定时任务 │ ├── 关键词回复 │ ├── 成员管理 │ └── 数据统计 ├── ⚙️ 配置教程 │ ├── 账号绑定 │ ├── 机器人设置 │ └── API 对接 ├── 💰 套餐与计费 ├── ❓ 常见问题 └── 📞 联系我们 ``` --- ## 二、完整代码实现 ### 文件结构 ``` baihu-docs/ ├── index.html # 文档站前台 ├── admin.html # 发内容后台 ├── css/ │ └── style.css ├── js/ │ └── app.js └── data/ └── docs.json # 文档数据存储 ``` --- ### `index.html` — 文档站前台 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>白虎TG助手 — 官方文档</title> <link rel="stylesheet" href="css/style.css" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> <!-- Markdown 渲染 --> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> </head> <body> <!-- ===== 顶部导航 ===== --> <header class="top-bar"> <div class="logo"> <span class="logo-icon">🐯</span> <span class="logo-text">白虎TG助手</span> <span class="logo-badge">文档中心</span> </div> <nav class="top-nav"> <a href="#" class="active">文档</a> <a href="#">官网</a> <a href="#">频道</a> <a href="admin.html" class="btn-admin">管理后台</a> </nav> <button class="menu-toggle" id="menuToggle">☰</button> </header> <!-- ===== 主体布局 ===== --> <div class="layout"> <!-- 左侧菜单 --> <aside class="sidebar" id="sidebar"> <div class="sidebar-search"> <input type="text" id="searchInput" placeholder="🔍 搜索文档..." /> </div> <nav class="side-nav" id="sideNav"> <!-- 由 JS 动态渲染 --> </nav> </aside> <!-- 中间内容区 --> <main class="content-area" id="contentArea"> <div class="content-inner" id="contentInner"> <!-- 默认首页 --> <div class="home-hero"> <div class="hero-icon">🐯</div> <h1>白虎 TG 助手</h1> <p class="hero-sub">专业的 Telegram 群发与自动化运营工具</p> <div class="hero-btns"> <button class="btn-primary" onclick="loadDoc('quick-start')">🚀 快速开始</button> <button class="btn-outline" onclick="loadDoc('intro')">📖 产品介绍</button> </div> <div class="feature-cards"> <div class="feature-card"> <div class="fc-icon">📢</div> <h3>批量群发</h3> <p>支持文字、图片、视频、文件多类型内容一键群发</p> </div> <div class="feature-card"> <div class="fc-icon">⏰</div> <h3>定时任务</h3> <p>设定发送时间,自动执行,解放双手</p> </div> <div class="feature-card"> <div class="fc-icon">🤖</div> <h3>智能回复</h3> <p>关键词触发自动回复,提升运营效率</p> </div> <div class="feature-card"> <div class="fc-icon">📊</div> <h3>数据统计</h3> <p>实时查看发送数据,优化运营策略</p> </div> </div> </div> </div> </main> <!-- 右侧目录 --> <aside class="toc-bar" id="tocBar"> <div class="toc-title">本页目录</div> <ul class="toc-list" id="tocList"></ul> </aside> </div> <!-- ===== 底部 ===== --> <footer class="footer"> <span>© 2024 白虎TG助手 版权所有</span> <span>·</span> <a href="#">TG频道</a> <span>·</span> <a href="#">联系客服</a> </footer> <script src="js/app.js"></script> </body> </html> ``` --- ### `admin.html` — 独立发内容后台 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>白虎TG助手 — 内容管理后台</title> <link rel="stylesheet" href="css/style.css" /> <!-- Markdown 编辑器 --> <link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css" /> <script src="https://unpkg.com/easymde/dist/easymde.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script> </head> <body class="admin-body"> <!-- 登录遮罩 --> <div class="login-mask" id="loginMask"> <div class="login-box"> <div class="login-logo">🐯 白虎后台</div> <h2>内容管理登录</h2> <input type="password" id="loginPwd" placeholder="请输入管理密码" /> <button onclick="doLogin()">登 录</button> <p class="login-tip">默认密码:baihu2024</p> </div> </div> <!-- 后台主体 --> <div class="admin-layout" id="adminLayout" style="display:none"> <!-- 左侧管理菜单 --> <aside class="admin-sidebar"> <div class="admin-logo">🐯 白虎后台</div> <nav> <a href="#" class="admin-nav-item active" data-panel="doc-list"> <span>📄</span> 文档列表 </a> <a href="#" class="admin-nav-item" data-panel="doc-edit"> <span>✏️</span> 新建/编辑 </a> <a href="#" class="admin-nav-item" data-panel="nav-manage"> <span>🗂️</span> 菜单管理 </a> <a href="#" class="admin-nav-item" data-panel="site-setting"> <span>⚙️</span> 站点设置 </a> </nav> <div class="admin-sidebar-footer"> <a href="index.html" target="_blank">👁 预览前台</a> <button onclick="doLogout()">退出登录</button> </div> </aside> <!-- 右侧面板 --> <main class="admin-main"> <!-- ① 文档列表面板 --> <div class="panel active" id="panel-doc-list"> <div class="panel-header"> <h2>📄 文档列表</h2> <button class="btn-primary" onclick="switchPanel('doc-edit'); newDoc()">+ 新建文档</button> </div> <!-- 筛选栏 --> <div class="filter-bar"> <input type="text" id="filterKeyword" placeholder="搜索标题..." oninput="renderDocList()" /> <select id="filterCategory" onchange="renderDocList()"> <option value="">全部分类</option> </select> </div> <table class="doc-table"> <thead> <tr> <th>标题</th> <th>分类</th> <th>排序</th> <th>状态</th> <th>更新时间</th> <th>操作</th> </tr> </thead> <tbody id="docTableBody"></tbody> </table> </div> <!-- ② 新建/编辑面板 --> <div class="panel" id="panel-doc-edit"> <div class="panel-header"> <h2 id="editPanelTitle">✏️ 新建文档</h2> <div> <button class="btn-outline" onclick="switchPanel('doc-list')">← 返回列表</button> <button class="btn-primary" onclick="saveDoc()">💾 保存发布</button> </div> </div> <div class="edit-form"> <div class="form-row"> <div class="form-group" style="flex:2"> <label>文档标题 *</label> <input type="text" id="docTitle" placeholder="输入文档标题" /> </div> <div class="form-group"> <label>所属分类 *</label> <select id="docCategory"> <option value="">请选择分类</option> </select> </div> <div class="form-group"> <label>排序权重</label> <input type="number" id="docOrder" value="0" min="0" /> </div> </div> <div class="form-row"> <div class="form-group" style="flex:2"> <label>文档ID(路由slug)</label> <input type="text" id="docSlug" placeholder="例: quick-start(留空自动生成)" /> </div> <div class="form-group"> <label>状态</label> <select id="docStatus"> <option value="published">已发布</option> <option value="draft">草稿</option> </select> </div> </div> <div class="form-group"> <label>文档正文(支持 Markdown)</label> <textarea id="docContent"></textarea> </div> <div class="form-row" style="margin-top:10px;"> <div class="form-group"> <label>SEO 描述</label> <input type="text" id="docDesc" placeholder="简短描述,用于搜索展示" /> </div> </div> </div> </div> <!-- ③ 菜单管理面板 --> <div class="panel" id="panel-nav-manage"> <div class="panel-header"> <h2>🗂️ 菜单/分类管理</h2> <button class="btn-primary" onclick="addCategory()">+ 新建分类</button> </div> <p class="tip-text">💡 拖动可调整菜单排序,双击名称可编辑</p> <ul class="category-list" id="categoryList"></ul> </div> <!-- ④ 站点设置面板 --> <div class="panel" id="panel-site-setting"> <div class="panel-header"> <h2>⚙️ 站点设置</h2> <button class="btn-primary" onclick="saveSiteSettings()">💾 保存设置</button> </div> <div class="edit-form"> <div class="form-group"> <label>网站标题</label> <input type="text" id="siteTitle" placeholder="白虎TG助手" /> </div> <div class="form-group"> <label>网站 Logo 文字/Emoji</label> <input type="text" id="siteLogo" placeholder="🐯" /> </div> <div class="form-group"> <label>首页副标题</label> <input type="text" id="siteSubtitle" placeholder="专业的 Telegram 群发与自动化运营工具" /> </div> <div class="form-group"> <label>TG 频道链接</label> <input type="text" id="siteTgLink" placeholder="https://t.me/yourChannel" /> </div> <div class="form-group"> <label>客服联系方式</label> <input type="text" id="siteContact" placeholder="@yourUsername" /> </div> <div class="form-group"> <label>管理密码(留空不修改)</label> <input type="password" id="newPassword" placeholder="输入新密码" /> </div> <div class="form-group"> <label>页脚版权文字</label> <input type="text" id="siteFooter" placeholder="© 2024 白虎TG助手 版权所有" /> </div> </div> </div> </main> </div> <script src="js/app.js"></script> <script src="js/admin.js"></script> </body> </html> ``` --- ### `css/style.css 2026-05-10 12:09:24