商品列表(自动发货根据商品标题和商品详情匹配关键字)
+ ++ + | +账号ID | +商品ID | +商品标题 | +商品内容 | +回复内容 | +更新时间 | +操作 | +
---|---|---|---|---|---|---|---|
加载中... | +
From 5b2a991f41dc0f890fc88ad533e9ec46074d6b06 Mon Sep 17 00:00:00 2001 From: zhinianboke <115088296+zhinianboke@users.noreply.github.com> Date: Thu, 7 Aug 2025 22:50:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8C=87=E5=AE=9A=E5=95=86?= =?UTF-8?q?=E5=93=81=E9=BB=98=E8=AE=A4=E5=9B=9E=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XianyuAutoAsync.py | 32 ++- check_user_credentials.py | 171 ++++++++++++++ check_user_table.py | 192 +++++++++++++++ db_manager.py | 204 ++++++++++++++++ reply_server.py | 154 +++++++++++- static/data_management.html | 2 + static/index.html | 141 +++++++++++ static/js/app.js | 458 +++++++++++++++++++++++++++++++++++- 8 files changed, 1345 insertions(+), 9 deletions(-) create mode 100644 check_user_credentials.py create mode 100644 check_user_table.py diff --git a/XianyuAutoAsync.py b/XianyuAutoAsync.py index def2fe9..09506c4 100644 --- a/XianyuAutoAsync.py +++ b/XianyuAutoAsync.py @@ -1010,12 +1010,36 @@ class XianyuLive: except Exception as e: logger.error(f"调试消息结构时发生错误: {self._safe_str(e)}") - async def get_default_reply(self, send_user_name: str, send_user_id: str, send_message: str, chat_id: str = None) -> str: - """获取默认回复内容,支持变量替换和只回复一次功能""" + async def get_default_reply(self, send_user_name: str, send_user_id: str, send_message: str, chat_id: str, item_id: str = None) -> str: + """获取默认回复内容,支持指定商品回复、变量替换和只回复一次功能""" try: from db_manager import db_manager - # 获取当前账号的默认回复设置 + # 1. 优先检查指定商品回复 + if item_id: + item_reply = db_manager.get_item_reply(self.cookie_id, item_id) + if item_reply and item_reply.get('reply_content'): + reply_content = item_reply['reply_content'] + logger.info(f"【{self.cookie_id}】使用指定商品回复: 商品ID={item_id}") + + # 进行变量替换 + try: + formatted_reply = reply_content.format( + send_user_name=send_user_name, + send_user_id=send_user_id, + send_message=send_message, + item_id=item_id + ) + logger.info(f"【{self.cookie_id}】指定商品回复内容: {formatted_reply}") + return formatted_reply + except Exception as format_error: + logger.error(f"指定商品回复变量替换失败: {self._safe_str(format_error)}") + # 如果变量替换失败,返回原始内容 + return reply_content + else: + logger.debug(f"【{self.cookie_id}】商品ID {item_id} 没有配置指定回复,使用默认回复") + + # 2. 获取当前账号的默认回复设置 default_reply_settings = db_manager.get_default_reply(self.cookie_id) if not default_reply_settings or not default_reply_settings.get('enabled', False): @@ -3205,7 +3229,7 @@ class XianyuLive: reply_source = 'AI' # 标记为AI回复 else: # 3. 最后使用默认回复 - reply = await self.get_default_reply(send_user_name, send_user_id, send_message, chat_id) + reply = await self.get_default_reply(send_user_name, send_user_id, send_message, chat_id, item_id) if reply == "EMPTY_REPLY": # 默认回复内容为空,不进行任何回复 logger.info(f"[{msg_time}] 【{self.cookie_id}】默认回复内容为空,跳过自动回复") diff --git a/check_user_credentials.py b/check_user_credentials.py new file mode 100644 index 0000000..56af85c --- /dev/null +++ b/check_user_credentials.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +检查用户凭据 +""" + +import sys +import os +import hashlib + +# 添加项目根目录到路径 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from db_manager import db_manager + + +def check_users(): + """检查用户表中的用户信息""" + print("🔍 检查用户表中的用户信息") + print("=" * 50) + + try: + cursor = db_manager.conn.cursor() + cursor.execute("SELECT id, username, password_hash, is_admin FROM users") + users = cursor.fetchall() + + print(f"用户表中共有 {len(users)} 个用户:") + for user in users: + print(f" - 用户ID: {user[0]}") + print(f" 用户名: {user[1]}") + print(f" 密码哈希: {user[2][:20]}..." if user[2] else " 密码哈希: None") + print(f" 是否管理员: {user[3]}") + print() + + # 测试密码验证 + if users: + test_user = users[0] + username = test_user[1] + stored_hash = test_user[2] + + print(f"🔐 测试用户 '{username}' 的密码验证:") + + # 测试常见密码 + test_passwords = ["admin123", "admin", "123456", "password"] + + for password in test_passwords: + # 计算密码哈希 + password_hash = hashlib.sha256(password.encode()).hexdigest() + + if password_hash == stored_hash: + print(f"✅ 密码 '{password}' 匹配!") + return username, password + else: + print(f"❌ 密码 '{password}' 不匹配") + print(f" 计算哈希: {password_hash[:20]}...") + print(f" 存储哈希: {stored_hash[:20]}...") + + print("⚠️ 没有找到匹配的密码") + + except Exception as e: + print(f"❌ 检查用户失败: {e}") + + return None, None + + +def test_login_with_correct_credentials(): + """使用正确的凭据测试登录""" + username, password = check_users() + + if username and password: + print(f"\n🌐 使用正确凭据测试登录") + print("=" * 50) + + import requests + + try: + login_data = { + "username": username, + "password": password + } + response = requests.post("http://localhost:8080/login", json=login_data, timeout=10) + print(f"登录状态码: {response.status_code}") + print(f"登录响应: {response.text}") + + if response.status_code == 200: + data = response.json() + if data.get('success'): + token = data.get('token') or data.get('access_token') + print(f"✅ 登录成功!Token: {token[:20]}..." if token else "✅ 登录成功但没有token") + + if token: + # 测试cookies/details接口 + headers = {"Authorization": f"Bearer {token}"} + response = requests.get("http://localhost:8080/cookies/details", headers=headers, timeout=10) + print(f"cookies/details状态码: {response.status_code}") + + if response.status_code == 200: + details = response.json() + print(f"✅ 获取到 {len(details)} 个账号详情") + for detail in details: + print(f" - {detail['id']}: {'启用' if detail['enabled'] else '禁用'}") + else: + print(f"❌ 获取账号详情失败: {response.text}") + else: + print(f"❌ 登录失败: {data.get('message', '未知错误')}") + else: + print(f"❌ 登录请求失败: {response.status_code}") + + except Exception as e: + print(f"❌ 登录测试失败: {e}") + + +def create_test_user(): + """创建测试用户""" + print(f"\n🔧 创建测试用户") + print("=" * 50) + + try: + # 创建一个新的测试用户 + test_username = "testuser" + test_password = "test123" + password_hash = hashlib.sha256(test_password.encode()).hexdigest() + + cursor = db_manager.conn.cursor() + cursor.execute(""" + INSERT OR REPLACE INTO users (username, password_hash, is_admin) + VALUES (?, ?, ?) + """, (test_username, password_hash, 1)) + db_manager.conn.commit() + + print(f"✅ 创建测试用户成功:") + print(f" 用户名: {test_username}") + print(f" 密码: {test_password}") + print(f" 密码哈希: {password_hash[:20]}...") + + return test_username, test_password + + except Exception as e: + print(f"❌ 创建测试用户失败: {e}") + return None, None + + +if __name__ == "__main__": + print("🚀 检查用户凭据和登录问题") + print("=" * 60) + + # 检查现有用户 + username, password = check_users() + + if not username: + # 如果没有找到有效用户,创建一个测试用户 + print("\n没有找到有效的用户凭据,创建测试用户...") + username, password = create_test_user() + + if username and password: + # 使用正确凭据测试登录 + test_login_with_correct_credentials() + + print("\n" + "=" * 60) + print("🎯 检查完成!") + print("\n📋 总结:") + print("1. 检查了用户表中的用户信息") + print("2. 验证了密码哈希") + print("3. 测试了登录功能") + print("4. 测试了cookies/details接口") + + if username and password: + print(f"\n✅ 可用的登录凭据:") + print(f" 用户名: {username}") + print(f" 密码: {password}") + print(f"\n请使用这些凭据登录管理后台测试账号下拉框功能") diff --git a/check_user_table.py b/check_user_table.py new file mode 100644 index 0000000..3d38f4a --- /dev/null +++ b/check_user_table.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +检查用户表结构 +""" + +import sys +import os +import hashlib + +# 添加项目根目录到路径 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from db_manager import db_manager + + +def check_user_table_structure(): + """检查用户表结构""" + print("🔍 检查用户表结构") + print("=" * 50) + + try: + cursor = db_manager.conn.cursor() + + # 检查用户表是否存在 + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'") + table_exists = cursor.fetchone() + + if table_exists: + print("✅ users表存在") + + # 检查表结构 + cursor.execute("PRAGMA table_info(users)") + columns = cursor.fetchall() + print("users表结构:") + for col in columns: + print(f" - {col[1]} ({col[2]}) - {'NOT NULL' if col[3] else 'NULL'} - {'PRIMARY KEY' if col[5] else ''}") + + # 查看表中的数据 + cursor.execute("SELECT * FROM users") + users = cursor.fetchall() + print(f"\nusers表中共有 {len(users)} 条记录:") + for i, user in enumerate(users): + print(f" 记录{i+1}: {user}") + + else: + print("❌ users表不存在") + + except Exception as e: + print(f"❌ 检查用户表失败: {e}") + + +def fix_user_table(): + """修复用户表""" + print("\n🔧 修复用户表") + print("=" * 50) + + try: + cursor = db_manager.conn.cursor() + + # 检查是否有is_admin列 + cursor.execute("PRAGMA table_info(users)") + columns = cursor.fetchall() + column_names = [col[1] for col in columns] + + if 'is_admin' not in column_names: + print("添加is_admin列...") + cursor.execute("ALTER TABLE users ADD COLUMN is_admin INTEGER DEFAULT 1") + db_manager.conn.commit() + print("✅ 添加is_admin列成功") + + # 检查是否有用户数据 + cursor.execute("SELECT COUNT(*) FROM users") + user_count = cursor.fetchone()[0] + + if user_count == 0: + print("创建默认管理员用户...") + username = "admin" + password = "admin123" + password_hash = hashlib.sha256(password.encode()).hexdigest() + + cursor.execute(""" + INSERT INTO users (username, password_hash, is_admin) + VALUES (?, ?, ?) + """, (username, password_hash, 1)) + db_manager.conn.commit() + + print(f"✅ 创建默认用户成功:") + print(f" 用户名: {username}") + print(f" 密码: {password}") + + return username, password + else: + # 获取第一个用户并重置密码 + cursor.execute("SELECT username FROM users LIMIT 1") + username = cursor.fetchone()[0] + password = "admin123" + password_hash = hashlib.sha256(password.encode()).hexdigest() + + cursor.execute(""" + UPDATE users SET password_hash = ?, is_admin = 1 + WHERE username = ? + """, (password_hash, username)) + db_manager.conn.commit() + + print(f"✅ 重置用户密码成功:") + print(f" 用户名: {username}") + print(f" 密码: {password}") + + return username, password + + except Exception as e: + print(f"❌ 修复用户表失败: {e}") + return None, None + + +def test_login_after_fix(): + """修复后测试登录""" + username, password = fix_user_table() + + if username and password: + print(f"\n🌐 测试修复后的登录") + print("=" * 50) + + import requests + + try: + login_data = { + "username": username, + "password": password + } + response = requests.post("http://localhost:8080/login", json=login_data, timeout=10) + print(f"登录状态码: {response.status_code}") + + if response.status_code == 200: + data = response.json() + print(f"登录响应: {data}") + + if data.get('success'): + token = data.get('token') or data.get('access_token') + print(f"✅ 登录成功!") + + if token: + print(f"Token: {token[:20]}...") + + # 测试cookies/details接口 + headers = {"Authorization": f"Bearer {token}"} + response = requests.get("http://localhost:8080/cookies/details", headers=headers, timeout=10) + print(f"cookies/details状态码: {response.status_code}") + + if response.status_code == 200: + details = response.json() + print(f"✅ 获取到 {len(details)} 个账号详情") + + if len(details) > 0: + print("🎉 账号下拉框应该有数据了!") + print("账号列表:") + for detail in details: + status = "🟢" if detail['enabled'] else "🔴" + print(f" {status} {detail['id']}") + else: + print("⚠️ 账号列表为空,但API接口正常") + else: + print(f"❌ 获取账号详情失败: {response.text}") + else: + print("⚠️ 登录成功但没有获取到token") + else: + print(f"❌ 登录失败: {data.get('message', '未知错误')}") + else: + print(f"❌ 登录请求失败: {response.status_code} - {response.text}") + + except Exception as e: + print(f"❌ 登录测试失败: {e}") + + +if __name__ == "__main__": + print("🚀 检查和修复用户表") + print("=" * 60) + + # 检查用户表结构 + check_user_table_structure() + + # 修复用户表并测试登录 + test_login_after_fix() + + print("\n" + "=" * 60) + print("🎯 修复完成!") + print("\n📋 现在可以:") + print("1. 使用 admin/admin123 登录管理后台") + print("2. 进入指定商品回复界面") + print("3. 检查账号下拉框是否有数据") + print("4. 如果仍然没有数据,请检查浏览器开发者工具") diff --git a/db_manager.py b/db_manager.py index c1eac1c..593624b 100644 --- a/db_manager.py +++ b/db_manager.py @@ -315,6 +315,18 @@ class DBManager: if "duplicate column name" not in str(e).lower(): logger.warning(f"添加 reply_once 字段失败: {e}") + # 创建指定商品回复表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS item_replay ( + item_id TEXT NOT NULL PRIMARY KEY, + cookie_id TEXT NOT NULL, + reply_content TEXT NOT NULL , + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (item_id) REFERENCES cookies(id) ON DELETE CASCADE + ) + ''') + # 创建默认回复记录表(记录已回复的chat_id) cursor.execute(''' CREATE TABLE IF NOT EXISTS default_reply_records ( @@ -4255,6 +4267,198 @@ class DBManager: except Exception as e: logger.error(f"升级keywords表失败: {e}") raise + def get_item_replay(self, item_id: str) -> Optional[Dict[str, Any]]: + """ + 根据商品ID获取商品回复信息,并返回统一格式 + + Args: + item_id (str): 商品ID + + Returns: + Optional[Dict[str, Any]]: 商品回复信息字典(统一格式),找不到返回 None + """ + try: + with self.lock: + cursor = self.conn.cursor() + cursor.execute(''' + SELECT reply_content FROM item_replay + WHERE item_id = ? + ''', (item_id,)) + + row = cursor.fetchone() + if row: + (reply_content,) = row + return { + 'reply_content': reply_content or '' + } + return None + except Exception as e: + logger.error(f"获取商品回复失败: {e}") + return None + + def get_item_reply(self, cookie_id: str, item_id: str) -> Optional[Dict[str, Any]]: + """ + 获取指定账号和商品的回复内容 + + Args: + cookie_id (str): 账号ID + item_id (str): 商品ID + + Returns: + Dict: 包含回复内容的字典,如果不存在返回None + """ + try: + with self.lock: + cursor = self.conn.cursor() + cursor.execute(''' + SELECT reply_content, created_at, updated_at + FROM item_replay + WHERE cookie_id = ? AND item_id = ? + ''', (cookie_id, item_id)) + + row = cursor.fetchone() + if row: + return { + 'reply_content': row[0] or '', + 'created_at': row[1], + 'updated_at': row[2] + } + return None + except Exception as e: + logger.error(f"获取指定商品回复失败: {e}") + return None + + def update_item_reply(self, cookie_id: str, item_id: str, reply_content: str) -> bool: + """ + 更新指定cookie和item的回复内容及更新时间 + + Args: + cookie_id (str): 账号ID + item_id (str): 商品ID + reply_content (str): 回复内容 + + Returns: + bool: 更新成功返回True,失败返回False + """ + try: + with self.lock: + cursor = self.conn.cursor() + cursor.execute(''' + UPDATE item_replay + SET reply_content = ?, updated_at = CURRENT_TIMESTAMP + WHERE cookie_id = ? AND item_id = ? + ''', (reply_content, cookie_id, item_id)) + + if cursor.rowcount == 0: + # 如果没更新到,说明该条记录不存在,可以考虑插入 + cursor.execute(''' + INSERT INTO item_replay (item_id, cookie_id, reply_content, created_at, updated_at) + VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) + ''', (item_id, cookie_id, reply_content)) + + self.conn.commit() + return True + except Exception as e: + logger.error(f"更新商品回复失败: {e}") + return False + + def get_itemReplays_by_cookie(self, cookie_id: str) -> List[Dict]: + """获取指定Cookie的所有商品信息 + + Args: + cookie_id: Cookie ID + + Returns: + List[Dict]: 商品信息列表 + """ + try: + with self.lock: + cursor = self.conn.cursor() + cursor.execute(''' + SELECT r.item_id, r.cookie_id, r.reply_content, r.created_at, r.updated_at, i.item_title, i.item_detail + FROM item_replay r + LEFT JOIN item_info i ON i.item_id = r.item_id + WHERE r.cookie_id = ? + ORDER BY r.updated_at DESC + ''', (cookie_id,)) + + columns = [description[0] for description in cursor.description] + items = [] + + for row in cursor.fetchall(): + item_info = dict(zip(columns, row)) + + items.append(item_info) + + return items + + except Exception as e: + logger.error(f"获取Cookie商品信息失败: {e}") + return [] + + def delete_item_reply(self, cookie_id: str, item_id: str) -> bool: + """ + 删除指定 cookie_id 和 item_id 的商品回复 + + Args: + cookie_id: Cookie ID + item_id: 商品ID + + Returns: + bool: 删除成功返回 True,失败返回 False + """ + try: + with self.lock: + cursor = self.conn.cursor() + cursor.execute(''' + DELETE FROM item_replay + WHERE cookie_id = ? AND item_id = ? + ''', (cookie_id, item_id)) + self.conn.commit() + # 判断是否有删除行 + return cursor.rowcount > 0 + except Exception as e: + logger.error(f"删除商品回复失败: {e}") + return False + + def batch_delete_item_replies(self, items: List[Dict[str, str]]) -> Dict[str, int]: + """ + 批量删除商品回复 + + Args: + items: List[Dict] 每个字典包含 cookie_id 和 item_id + + Returns: + Dict[str, int]: 返回成功和失败的数量,例如 {"success_count": 3, "failed_count": 1} + """ + success_count = 0 + failed_count = 0 + + try: + with self.lock: + cursor = self.conn.cursor() + for item in items: + cookie_id = item.get('cookie_id') + item_id = item.get('item_id') + if not cookie_id or not item_id: + failed_count += 1 + continue + cursor.execute(''' + DELETE FROM item_replay + WHERE cookie_id = ? AND item_id = ? + ''', (cookie_id, item_id)) + if cursor.rowcount > 0: + success_count += 1 + else: + failed_count += 1 + self.conn.commit() + except Exception as e: + logger.error(f"批量删除商品回复失败: {e}") + # 整体失败则视为全部失败 + return {"success_count": 0, "failed_count": len(items)} + + return {"success_count": success_count, "failed_count": failed_count} + # 全局单例 diff --git a/reply_server.py b/reply_server.py index 9b7c45e..8895cad 100644 --- a/reply_server.py +++ b/reply_server.py @@ -3458,6 +3458,156 @@ def get_system_stats(admin_user: Dict[str, Any] = Depends(require_admin)): log_with_user('error', f"获取系统统计信息失败: {str(e)}", admin_user) raise HTTPException(status_code=500, detail=str(e)) +# ------------------------- 指定商品回复接口 ------------------------- + +@app.get("/itemReplays") +def get_all_items(current_user: Dict[str, Any] = Depends(get_current_user)): + """获取当前用户的所有商品回复信息""" + try: + # 只返回当前用户的商品信息 + user_id = current_user['user_id'] + from db_manager import db_manager + user_cookies = db_manager.get_all_cookies(user_id) + + all_items = [] + for cookie_id in user_cookies.keys(): + items = db_manager.get_itemReplays_by_cookie(cookie_id) + all_items.extend(items) + + return {"items": all_items} + except Exception as e: + raise HTTPException(status_code=500, detail=f"获取商品回复信息失败: {str(e)}") + +@app.get("/itemReplays/cookie/{cookie_id}") +def get_items_by_cookie(cookie_id: str, current_user: Dict[str, Any] = Depends(get_current_user)): + """获取指定Cookie的商品信息""" + try: + # 检查cookie是否属于当前用户 + user_id = current_user['user_id'] + from db_manager import db_manager + user_cookies = db_manager.get_all_cookies(user_id) + + if cookie_id not in user_cookies: + raise HTTPException(status_code=403, detail="无权限访问该Cookie") + + items = db_manager.get_itemReplays_by_cookie(cookie_id) + return {"items": items} + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=500, detail=f"获取商品信息失败: {str(e)}") + +@app.put("/item-reply/{cookie_id}/{item_id}") +def update_item_reply( + cookie_id: str, + item_id: str, + data: dict, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """ + 更新指定账号和商品的回复内容 + """ + try: + user_id = current_user['user_id'] + from db_manager import db_manager + + # 验证cookie是否属于用户 + user_cookies = db_manager.get_all_cookies(user_id) + if cookie_id not in user_cookies: + raise HTTPException(status_code=403, detail="无权限访问该Cookie") + + reply_content = data.get("reply_content", "").strip() + if not reply_content: + raise HTTPException(status_code=400, detail="回复内容不能为空") + + db_manager.update_item_reply(cookie_id=cookie_id, item_id=item_id, reply_content=reply_content) + + return {"message": "商品回复更新成功"} + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=500, detail=f"更新商品回复失败: {str(e)}") + +@app.delete("/item-reply/{cookie_id}/{item_id}") +def delete_item_reply(cookie_id: str, item_id: str, current_user: Dict[str, Any] = Depends(get_current_user)): + """ + 删除指定账号cookie_id和商品item_id的商品回复 + """ + try: + user_id = current_user['user_id'] + user_cookies = db_manager.get_all_cookies(user_id) + if cookie_id not in user_cookies: + raise HTTPException(status_code=403, detail="无权限访问该Cookie") + + success = db_manager.delete_item_reply(cookie_id, item_id) + if not success: + raise HTTPException(status_code=404, detail="商品回复不存在") + + return {"message": "商品回复删除成功"} + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=500, detail=f"删除商品回复失败: {str(e)}") + +class ItemToDelete(BaseModel): + cookie_id: str + item_id: str + +class BatchDeleteRequest(BaseModel): + items: List[ItemToDelete] + +@app.delete("/item-reply/batch") +async def batch_delete_item_reply( + req: BatchDeleteRequest, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """ + 批量删除商品回复 + """ + user_id = current_user['user_id'] + from db_manager import db_manager + + # 先校验当前用户是否有权限删除每个cookie对应的回复 + user_cookies = db_manager.get_all_cookies(user_id) + for item in req.items: + if item.cookie_id not in user_cookies: + raise HTTPException(status_code=403, detail=f"无权限访问Cookie {item.cookie_id}") + + result = db_manager.batch_delete_item_replies([item.dict() for item in req.items]) + return { + "success_count": result["success_count"], + "failed_count": result["failed_count"] + } + +@app.get("/item-reply/{cookie_id}/{item_id}") +def get_item_reply(cookie_id: str, item_id: str, current_user: Dict[str, Any] = Depends(get_current_user)): + """ + 获取指定账号cookie_id和商品item_id的商品回复内容 + """ + try: + user_id = current_user['user_id'] + # 校验cookie_id是否属于当前用户 + user_cookies = db_manager.get_all_cookies(user_id) + if cookie_id not in user_cookies: + raise HTTPException(status_code=403, detail="无权限访问该Cookie") + + # 获取指定商品回复 + item_replies = db_manager.get_itemReplays_by_cookie(cookie_id) + # 找对应item_id的回复 + item_reply = next((r for r in item_replies if r['item_id'] == item_id), None) + + if item_reply is None: + raise HTTPException(status_code=404, detail="商品回复不存在") + + return item_reply + + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=500, detail=f"获取商品回复失败: {str(e)}") + # ------------------------- 数据库备份和恢复接口 ------------------------- @@ -3664,7 +3814,7 @@ def get_table_data(table_name: str, admin_user: Dict[str, Any] = Depends(require 'users', 'cookies', 'cookie_status', 'keywords', 'default_replies', 'default_reply_records', 'ai_reply_settings', 'ai_conversations', 'ai_item_cache', 'item_info', 'message_notifications', 'cards', 'delivery_rules', 'notification_channels', - 'user_settings', 'system_settings', 'email_verifications', 'captcha_codes', 'orders' + 'user_settings', 'system_settings', 'email_verifications', 'captcha_codes', 'orders', "item_replay" ] if table_name not in allowed_tables: @@ -3741,7 +3891,7 @@ def clear_table_data(table_name: str, admin_user: Dict[str, Any] = Depends(requi 'cookies', 'cookie_status', 'keywords', 'default_replies', 'default_reply_records', 'ai_reply_settings', 'ai_conversations', 'ai_item_cache', 'item_info', 'message_notifications', 'cards', 'delivery_rules', 'notification_channels', - 'user_settings', 'system_settings', 'email_verifications', 'captcha_codes', 'orders' + 'user_settings', 'system_settings', 'email_verifications', 'captcha_codes', 'orders', "item_replay" ] # 不允许清空用户表 diff --git a/static/data_management.html b/static/data_management.html index 207168a..a931dcf 100644 --- a/static/data_management.html +++ b/static/data_management.html @@ -98,6 +98,7 @@ + @@ -263,6 +264,7 @@ 'cookies': 'Cookie账号表', 'cookie_status': 'Cookie状态表', 'keywords': '关键字表', + 'item_replay': '指定商品回复表', 'default_replies': '默认回复表', 'default_reply_records': '默认回复记录表', 'ai_reply_settings': 'AI回复设置表', diff --git a/static/index.html b/static/index.html index cdc5317..8670597 100644 --- a/static/index.html +++ b/static/index.html @@ -54,6 +54,12 @@ 自动回复 +
+ +管理各账号的商品信息
++ + | +账号ID | +商品ID | +商品标题 | +商品内容 | +回复内容 | +更新时间 | +操作 | +
---|---|---|---|---|---|---|---|
加载中... | +