mirror of
https://github.com/zhinianboke/xianyu-auto-reply.git
synced 2025-08-30 09:37:35 +08:00
支持设置默认回复只回复一次
This commit is contained in:
parent
aae9d1ab46
commit
0b9b81bc4e
@ -961,8 +961,8 @@ class XianyuLive:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"调试消息结构时发生错误: {self._safe_str(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) -> str:
|
async def get_default_reply(self, send_user_name: str, send_user_id: str, send_message: str, chat_id: str = None) -> str:
|
||||||
"""获取默认回复内容,支持变量替换"""
|
"""获取默认回复内容,支持变量替换和只回复一次功能"""
|
||||||
try:
|
try:
|
||||||
from db_manager import db_manager
|
from db_manager import db_manager
|
||||||
|
|
||||||
@ -973,6 +973,13 @@ class XianyuLive:
|
|||||||
logger.debug(f"账号 {self.cookie_id} 未启用默认回复")
|
logger.debug(f"账号 {self.cookie_id} 未启用默认回复")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# 检查"只回复一次"功能
|
||||||
|
if default_reply_settings.get('reply_once', False) and chat_id:
|
||||||
|
# 检查是否已经回复过这个chat_id
|
||||||
|
if db_manager.has_default_reply_record(self.cookie_id, chat_id):
|
||||||
|
logger.info(f"【{self.cookie_id}】chat_id {chat_id} 已使用过默认回复,跳过(只回复一次)")
|
||||||
|
return None
|
||||||
|
|
||||||
reply_content = default_reply_settings.get('reply_content', '')
|
reply_content = default_reply_settings.get('reply_content', '')
|
||||||
if not reply_content:
|
if not reply_content:
|
||||||
logger.warning(f"账号 {self.cookie_id} 默认回复内容为空")
|
logger.warning(f"账号 {self.cookie_id} 默认回复内容为空")
|
||||||
@ -985,6 +992,12 @@ class XianyuLive:
|
|||||||
send_user_id=send_user_id,
|
send_user_id=send_user_id,
|
||||||
send_message=send_message
|
send_message=send_message
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 如果开启了"只回复一次"功能,记录这次回复
|
||||||
|
if default_reply_settings.get('reply_once', False) and chat_id:
|
||||||
|
db_manager.add_default_reply_record(self.cookie_id, chat_id)
|
||||||
|
logger.info(f"【{self.cookie_id}】记录默认回复: chat_id={chat_id}")
|
||||||
|
|
||||||
logger.info(f"【{self.cookie_id}】使用默认回复: {formatted_reply}")
|
logger.info(f"【{self.cookie_id}】使用默认回复: {formatted_reply}")
|
||||||
return formatted_reply
|
return formatted_reply
|
||||||
except Exception as format_error:
|
except Exception as format_error:
|
||||||
@ -2896,7 +2909,7 @@ class XianyuLive:
|
|||||||
reply_source = 'AI' # 标记为AI回复
|
reply_source = 'AI' # 标记为AI回复
|
||||||
else:
|
else:
|
||||||
# 3. 最后使用默认回复
|
# 3. 最后使用默认回复
|
||||||
reply = await self.get_default_reply(send_user_name, send_user_id, send_message)
|
reply = await self.get_default_reply(send_user_name, send_user_id, send_message, chat_id)
|
||||||
reply_source = '默认' # 标记为默认回复
|
reply_source = '默认' # 标记为默认回复
|
||||||
|
|
||||||
# 注意:这里只有商品ID,没有标题和详情,根据新的规则不保存到数据库
|
# 注意:这里只有商品ID,没有标题和详情,根据新的规则不保存到数据库
|
||||||
|
@ -281,12 +281,34 @@ class DBManager:
|
|||||||
cookie_id TEXT PRIMARY KEY,
|
cookie_id TEXT PRIMARY KEY,
|
||||||
enabled BOOLEAN DEFAULT FALSE,
|
enabled BOOLEAN DEFAULT FALSE,
|
||||||
reply_content TEXT,
|
reply_content TEXT,
|
||||||
|
reply_once BOOLEAN DEFAULT FALSE,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (cookie_id) REFERENCES cookies(id) ON DELETE CASCADE
|
FOREIGN KEY (cookie_id) REFERENCES cookies(id) ON DELETE CASCADE
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# 添加 reply_once 字段(如果不存在)
|
||||||
|
try:
|
||||||
|
cursor.execute('ALTER TABLE default_replies ADD COLUMN reply_once BOOLEAN DEFAULT FALSE')
|
||||||
|
self.conn.commit()
|
||||||
|
logger.info("已添加 reply_once 字段到 default_replies 表")
|
||||||
|
except sqlite3.OperationalError as e:
|
||||||
|
if "duplicate column name" not in str(e).lower():
|
||||||
|
logger.warning(f"添加 reply_once 字段失败: {e}")
|
||||||
|
|
||||||
|
# 创建默认回复记录表(记录已回复的chat_id)
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS default_reply_records (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
cookie_id TEXT NOT NULL,
|
||||||
|
chat_id TEXT NOT NULL,
|
||||||
|
replied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(cookie_id, chat_id),
|
||||||
|
FOREIGN KEY (cookie_id) REFERENCES cookies(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
|
||||||
# 创建通知渠道表
|
# 创建通知渠道表
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS notification_channels (
|
CREATE TABLE IF NOT EXISTS notification_channels (
|
||||||
@ -1588,17 +1610,17 @@ class DBManager:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
# -------------------- 默认回复操作 --------------------
|
# -------------------- 默认回复操作 --------------------
|
||||||
def save_default_reply(self, cookie_id: str, enabled: bool, reply_content: str = None):
|
def save_default_reply(self, cookie_id: str, enabled: bool, reply_content: str = None, reply_once: bool = False):
|
||||||
"""保存默认回复设置"""
|
"""保存默认回复设置"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
try:
|
try:
|
||||||
cursor = self.conn.cursor()
|
cursor = self.conn.cursor()
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT OR REPLACE INTO default_replies (cookie_id, enabled, reply_content, updated_at)
|
INSERT OR REPLACE INTO default_replies (cookie_id, enabled, reply_content, reply_once, updated_at)
|
||||||
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
|
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||||
''', (cookie_id, enabled, reply_content))
|
''', (cookie_id, enabled, reply_content, reply_once))
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
logger.debug(f"保存默认回复设置: {cookie_id} -> {'启用' if enabled else '禁用'}")
|
logger.debug(f"保存默认回复设置: {cookie_id} -> {'启用' if enabled else '禁用'}, 只回复一次: {'是' if reply_once else '否'}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"保存默认回复设置失败: {e}")
|
logger.error(f"保存默认回复设置失败: {e}")
|
||||||
raise
|
raise
|
||||||
@ -1609,14 +1631,15 @@ class DBManager:
|
|||||||
try:
|
try:
|
||||||
cursor = self.conn.cursor()
|
cursor = self.conn.cursor()
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
SELECT enabled, reply_content FROM default_replies WHERE cookie_id = ?
|
SELECT enabled, reply_content, reply_once FROM default_replies WHERE cookie_id = ?
|
||||||
''', (cookie_id,))
|
''', (cookie_id,))
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
if result:
|
if result:
|
||||||
enabled, reply_content = result
|
enabled, reply_content, reply_once = result
|
||||||
return {
|
return {
|
||||||
'enabled': bool(enabled),
|
'enabled': bool(enabled),
|
||||||
'reply_content': reply_content or ''
|
'reply_content': reply_content or '',
|
||||||
|
'reply_once': bool(reply_once) if reply_once is not None else False
|
||||||
}
|
}
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1628,14 +1651,15 @@ class DBManager:
|
|||||||
with self.lock:
|
with self.lock:
|
||||||
try:
|
try:
|
||||||
cursor = self.conn.cursor()
|
cursor = self.conn.cursor()
|
||||||
cursor.execute('SELECT cookie_id, enabled, reply_content FROM default_replies')
|
cursor.execute('SELECT cookie_id, enabled, reply_content, reply_once FROM default_replies')
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
for row in cursor.fetchall():
|
for row in cursor.fetchall():
|
||||||
cookie_id, enabled, reply_content = row
|
cookie_id, enabled, reply_content, reply_once = row
|
||||||
result[cookie_id] = {
|
result[cookie_id] = {
|
||||||
'enabled': bool(enabled),
|
'enabled': bool(enabled),
|
||||||
'reply_content': reply_content or ''
|
'reply_content': reply_content or '',
|
||||||
|
'reply_once': bool(reply_once) if reply_once is not None else False
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -1643,6 +1667,45 @@ class DBManager:
|
|||||||
logger.error(f"获取所有默认回复设置失败: {e}")
|
logger.error(f"获取所有默认回复设置失败: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def add_default_reply_record(self, cookie_id: str, chat_id: str):
|
||||||
|
"""记录已回复的chat_id"""
|
||||||
|
with self.lock:
|
||||||
|
try:
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT OR IGNORE INTO default_reply_records (cookie_id, chat_id)
|
||||||
|
VALUES (?, ?)
|
||||||
|
''', (cookie_id, chat_id))
|
||||||
|
self.conn.commit()
|
||||||
|
logger.debug(f"记录默认回复: {cookie_id} -> {chat_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"记录默认回复失败: {e}")
|
||||||
|
|
||||||
|
def has_default_reply_record(self, cookie_id: str, chat_id: str) -> bool:
|
||||||
|
"""检查是否已经回复过该chat_id"""
|
||||||
|
with self.lock:
|
||||||
|
try:
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
SELECT 1 FROM default_reply_records WHERE cookie_id = ? AND chat_id = ?
|
||||||
|
''', (cookie_id, chat_id))
|
||||||
|
result = cursor.fetchone()
|
||||||
|
return result is not None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"检查默认回复记录失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def clear_default_reply_records(self, cookie_id: str):
|
||||||
|
"""清空指定账号的默认回复记录"""
|
||||||
|
with self.lock:
|
||||||
|
try:
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute('DELETE FROM default_reply_records WHERE cookie_id = ?', (cookie_id,))
|
||||||
|
self.conn.commit()
|
||||||
|
logger.debug(f"清空默认回复记录: {cookie_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"清空默认回复记录失败: {e}")
|
||||||
|
|
||||||
def delete_default_reply(self, cookie_id: str) -> bool:
|
def delete_default_reply(self, cookie_id: str) -> bool:
|
||||||
"""删除指定账号的默认回复设置"""
|
"""删除指定账号的默认回复设置"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
@ -858,13 +858,22 @@ async def register(request: RegisterRequest):
|
|||||||
@app.post("/xianyu/reply", response_model=ResponseModel)
|
@app.post("/xianyu/reply", response_model=ResponseModel)
|
||||||
async def xianyu_reply(req: RequestModel):
|
async def xianyu_reply(req: RequestModel):
|
||||||
msg_template = match_reply(req.cookie_id, req.send_message)
|
msg_template = match_reply(req.cookie_id, req.send_message)
|
||||||
|
is_default_reply = False
|
||||||
|
|
||||||
if not msg_template:
|
if not msg_template:
|
||||||
# 从数据库获取默认回复
|
# 从数据库获取默认回复
|
||||||
from db_manager import db_manager
|
from db_manager import db_manager
|
||||||
default_reply_settings = db_manager.get_default_reply(req.cookie_id)
|
default_reply_settings = db_manager.get_default_reply(req.cookie_id)
|
||||||
|
|
||||||
if default_reply_settings and default_reply_settings.get('enabled', False):
|
if default_reply_settings and default_reply_settings.get('enabled', False):
|
||||||
|
# 检查是否开启了"只回复一次"功能
|
||||||
|
if default_reply_settings.get('reply_once', False):
|
||||||
|
# 检查是否已经回复过这个chat_id
|
||||||
|
if db_manager.has_default_reply_record(req.cookie_id, req.chat_id):
|
||||||
|
raise HTTPException(status_code=404, detail="该对话已使用默认回复,不再重复回复")
|
||||||
|
|
||||||
msg_template = default_reply_settings.get('reply_content', '')
|
msg_template = default_reply_settings.get('reply_content', '')
|
||||||
|
is_default_reply = True
|
||||||
|
|
||||||
# 如果数据库中没有设置或为空,返回错误
|
# 如果数据库中没有设置或为空,返回错误
|
||||||
if not msg_template:
|
if not msg_template:
|
||||||
@ -881,6 +890,13 @@ async def xianyu_reply(req: RequestModel):
|
|||||||
# 如果格式化失败,返回原始内容
|
# 如果格式化失败,返回原始内容
|
||||||
send_msg = msg_template
|
send_msg = msg_template
|
||||||
|
|
||||||
|
# 如果是默认回复且开启了"只回复一次",记录回复记录
|
||||||
|
if is_default_reply:
|
||||||
|
from db_manager import db_manager
|
||||||
|
default_reply_settings = db_manager.get_default_reply(req.cookie_id)
|
||||||
|
if default_reply_settings and default_reply_settings.get('reply_once', False):
|
||||||
|
db_manager.add_default_reply_record(req.cookie_id, req.chat_id)
|
||||||
|
|
||||||
return {"code": 200, "data": {"send_msg": send_msg}}
|
return {"code": 200, "data": {"send_msg": send_msg}}
|
||||||
|
|
||||||
# ------------------------- 账号 / 关键字管理接口 -------------------------
|
# ------------------------- 账号 / 关键字管理接口 -------------------------
|
||||||
@ -898,6 +914,7 @@ class CookieStatusIn(BaseModel):
|
|||||||
class DefaultReplyIn(BaseModel):
|
class DefaultReplyIn(BaseModel):
|
||||||
enabled: bool
|
enabled: bool
|
||||||
reply_content: Optional[str] = None
|
reply_content: Optional[str] = None
|
||||||
|
reply_once: bool = False
|
||||||
|
|
||||||
|
|
||||||
class NotificationChannelIn(BaseModel):
|
class NotificationChannelIn(BaseModel):
|
||||||
@ -1179,7 +1196,7 @@ def get_default_reply(cid: str, current_user: Dict[str, Any] = Depends(get_curre
|
|||||||
result = db_manager.get_default_reply(cid)
|
result = db_manager.get_default_reply(cid)
|
||||||
if result is None:
|
if result is None:
|
||||||
# 如果没有设置,返回默认值
|
# 如果没有设置,返回默认值
|
||||||
return {'enabled': False, 'reply_content': ''}
|
return {'enabled': False, 'reply_content': '', 'reply_once': False}
|
||||||
return result
|
return result
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
@ -1199,8 +1216,8 @@ def update_default_reply(cid: str, reply_data: DefaultReplyIn, current_user: Dic
|
|||||||
if cid not in user_cookies:
|
if cid not in user_cookies:
|
||||||
raise HTTPException(status_code=403, detail="无权限操作该Cookie")
|
raise HTTPException(status_code=403, detail="无权限操作该Cookie")
|
||||||
|
|
||||||
db_manager.save_default_reply(cid, reply_data.enabled, reply_data.reply_content)
|
db_manager.save_default_reply(cid, reply_data.enabled, reply_data.reply_content, reply_data.reply_once)
|
||||||
return {'msg': 'default reply updated', 'enabled': reply_data.enabled}
|
return {'msg': 'default reply updated', 'enabled': reply_data.enabled, 'reply_once': reply_data.reply_once}
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1247,6 +1264,26 @@ def delete_default_reply(cid: str, current_user: Dict[str, Any] = Depends(get_cu
|
|||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.post('/default-replies/{cid}/clear-records')
|
||||||
|
def clear_default_reply_records(cid: str, current_user: Dict[str, Any] = Depends(get_current_user)):
|
||||||
|
"""清空指定账号的默认回复记录"""
|
||||||
|
from db_manager import db_manager
|
||||||
|
try:
|
||||||
|
# 检查cookie是否属于当前用户
|
||||||
|
user_id = current_user['user_id']
|
||||||
|
user_cookies = db_manager.get_all_cookies(user_id)
|
||||||
|
|
||||||
|
if cid not in user_cookies:
|
||||||
|
raise HTTPException(status_code=403, detail="无权限操作该Cookie")
|
||||||
|
|
||||||
|
db_manager.clear_default_reply_records(cid)
|
||||||
|
return {'msg': 'default reply records cleared'}
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
# ------------------------- 通知渠道管理接口 -------------------------
|
# ------------------------- 通知渠道管理接口 -------------------------
|
||||||
|
|
||||||
@app.get('/notification-channels')
|
@app.get('/notification-channels')
|
||||||
|
@ -1888,6 +1888,8 @@
|
|||||||
<code>{send_user_name}</code> 用户昵称、
|
<code>{send_user_name}</code> 用户昵称、
|
||||||
<code>{send_user_id}</code> 用户ID、
|
<code>{send_user_id}</code> 用户ID、
|
||||||
<code>{send_message}</code> 用户消息
|
<code>{send_message}</code> 用户消息
|
||||||
|
<br><br>
|
||||||
|
<strong>只回复一次:</strong>开启后,每个对话只会触发一次默认回复,避免重复回复同一用户。
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
@ -1895,8 +1897,9 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 15%">账号ID</th>
|
<th style="width: 15%">账号ID</th>
|
||||||
<th style="width: 15%">状态</th>
|
<th style="width: 12%">状态</th>
|
||||||
<th style="width: 50%">默认回复内容</th>
|
<th style="width: 12%">只回复一次</th>
|
||||||
|
<th style="width: 41%">默认回复内容</th>
|
||||||
<th style="width: 20%">操作</th>
|
<th style="width: 20%">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -1946,6 +1949,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" id="editReplyOnce" />
|
||||||
|
<label class="form-check-label" for="editReplyOnce">
|
||||||
|
只回复一次
|
||||||
|
</label>
|
||||||
|
<div class="form-text">
|
||||||
|
<i class="bi bi-info-circle me-1"></i>
|
||||||
|
开启后,每个对话只会触发一次默认回复,避免重复回复
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-3" id="editReplyContentGroup">
|
<div class="mb-3" id="editReplyContentGroup">
|
||||||
<label for="editReplyContent" class="form-label">默认回复内容</label>
|
<label for="editReplyContent" class="form-label">默认回复内容</label>
|
||||||
<textarea class="form-control" id="editReplyContent" rows="4"
|
<textarea class="form-control" id="editReplyContent" rows="4"
|
||||||
|
@ -1864,7 +1864,7 @@ function renderDefaultRepliesList(accounts, defaultReplies) {
|
|||||||
if (accounts.length === 0) {
|
if (accounts.length === 0) {
|
||||||
tbody.innerHTML = `
|
tbody.innerHTML = `
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="text-center py-4 text-muted">
|
<td colspan="5" class="text-center py-4 text-muted">
|
||||||
<i class="bi bi-chat-text fs-1 d-block mb-3"></i>
|
<i class="bi bi-chat-text fs-1 d-block mb-3"></i>
|
||||||
<h5>暂无账号数据</h5>
|
<h5>暂无账号数据</h5>
|
||||||
<p class="mb-0">请先添加账号</p>
|
<p class="mb-0">请先添加账号</p>
|
||||||
@ -1875,7 +1875,7 @@ function renderDefaultRepliesList(accounts, defaultReplies) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
accounts.forEach(accountId => {
|
accounts.forEach(accountId => {
|
||||||
const replySettings = defaultReplies[accountId] || { enabled: false, reply_content: '' };
|
const replySettings = defaultReplies[accountId] || { enabled: false, reply_content: '', reply_once: false };
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
|
|
||||||
// 状态标签
|
// 状态标签
|
||||||
@ -1883,6 +1883,11 @@ function renderDefaultRepliesList(accounts, defaultReplies) {
|
|||||||
'<span class="badge bg-success">启用</span>' :
|
'<span class="badge bg-success">启用</span>' :
|
||||||
'<span class="badge bg-secondary">禁用</span>';
|
'<span class="badge bg-secondary">禁用</span>';
|
||||||
|
|
||||||
|
// 只回复一次标签
|
||||||
|
const replyOnceBadge = replySettings.reply_once ?
|
||||||
|
'<span class="badge bg-warning">是</span>' :
|
||||||
|
'<span class="badge bg-light text-dark">否</span>';
|
||||||
|
|
||||||
// 回复内容预览
|
// 回复内容预览
|
||||||
let contentPreview = replySettings.reply_content || '未设置';
|
let contentPreview = replySettings.reply_content || '未设置';
|
||||||
if (contentPreview.length > 50) {
|
if (contentPreview.length > 50) {
|
||||||
@ -1894,6 +1899,7 @@ function renderDefaultRepliesList(accounts, defaultReplies) {
|
|||||||
<strong class="text-primary">${accountId}</strong>
|
<strong class="text-primary">${accountId}</strong>
|
||||||
</td>
|
</td>
|
||||||
<td>${statusBadge}</td>
|
<td>${statusBadge}</td>
|
||||||
|
<td>${replyOnceBadge}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="text-truncate" style="max-width: 300px;" title="${replySettings.reply_content || ''}">
|
<div class="text-truncate" style="max-width: 300px;" title="${replySettings.reply_content || ''}">
|
||||||
${contentPreview}
|
${contentPreview}
|
||||||
@ -1907,6 +1913,11 @@ function renderDefaultRepliesList(accounts, defaultReplies) {
|
|||||||
<button class="btn btn-sm btn-outline-info" onclick="testDefaultReply('${accountId}')" title="测试">
|
<button class="btn btn-sm btn-outline-info" onclick="testDefaultReply('${accountId}')" title="测试">
|
||||||
<i class="bi bi-play"></i>
|
<i class="bi bi-play"></i>
|
||||||
</button>
|
</button>
|
||||||
|
${replySettings.reply_once ? `
|
||||||
|
<button class="btn btn-sm btn-outline-warning" onclick="clearDefaultReplyRecords('${accountId}')" title="清空记录">
|
||||||
|
<i class="bi bi-arrow-clockwise"></i>
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
@ -1925,7 +1936,7 @@ async function editDefaultReply(accountId) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let settings = { enabled: false, reply_content: '' };
|
let settings = { enabled: false, reply_content: '', reply_once: false };
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
settings = await response.json();
|
settings = await response.json();
|
||||||
}
|
}
|
||||||
@ -1935,6 +1946,7 @@ async function editDefaultReply(accountId) {
|
|||||||
document.getElementById('editAccountIdDisplay').value = accountId;
|
document.getElementById('editAccountIdDisplay').value = accountId;
|
||||||
document.getElementById('editDefaultReplyEnabled').checked = settings.enabled;
|
document.getElementById('editDefaultReplyEnabled').checked = settings.enabled;
|
||||||
document.getElementById('editReplyContent').value = settings.reply_content || '';
|
document.getElementById('editReplyContent').value = settings.reply_content || '';
|
||||||
|
document.getElementById('editReplyOnce').checked = settings.reply_once || false;
|
||||||
|
|
||||||
// 根据启用状态显示/隐藏内容输入框
|
// 根据启用状态显示/隐藏内容输入框
|
||||||
toggleReplyContentVisibility();
|
toggleReplyContentVisibility();
|
||||||
@ -1961,6 +1973,7 @@ async function saveDefaultReply() {
|
|||||||
const accountId = document.getElementById('editAccountId').value;
|
const accountId = document.getElementById('editAccountId').value;
|
||||||
const enabled = document.getElementById('editDefaultReplyEnabled').checked;
|
const enabled = document.getElementById('editDefaultReplyEnabled').checked;
|
||||||
const replyContent = document.getElementById('editReplyContent').value;
|
const replyContent = document.getElementById('editReplyContent').value;
|
||||||
|
const replyOnce = document.getElementById('editReplyOnce').checked;
|
||||||
|
|
||||||
if (enabled && !replyContent.trim()) {
|
if (enabled && !replyContent.trim()) {
|
||||||
showToast('启用默认回复时必须设置回复内容', 'warning');
|
showToast('启用默认回复时必须设置回复内容', 'warning');
|
||||||
@ -1969,7 +1982,8 @@ async function saveDefaultReply() {
|
|||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
reply_content: enabled ? replyContent : null
|
reply_content: enabled ? replyContent : null,
|
||||||
|
reply_once: replyOnce
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${apiBase}/default-replies/${accountId}`, {
|
const response = await fetch(`${apiBase}/default-replies/${accountId}`, {
|
||||||
@ -2001,6 +2015,34 @@ function testDefaultReply(accountId) {
|
|||||||
showToast('测试功能开发中...', 'info');
|
showToast('测试功能开发中...', 'info');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空默认回复记录
|
||||||
|
async function clearDefaultReplyRecords(accountId) {
|
||||||
|
if (!confirm(`确定要清空账号 "${accountId}" 的默认回复记录吗?\n\n清空后,该账号将可以重新对之前回复过的对话进行默认回复。`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${apiBase}/default-replies/${accountId}/clear-records`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${authToken}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
showToast(`账号 "${accountId}" 的默认回复记录已清空`, 'success');
|
||||||
|
loadDefaultReplies(); // 刷新列表
|
||||||
|
} else {
|
||||||
|
const error = await response.text();
|
||||||
|
showToast(`清空失败: ${error}`, 'danger');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清空默认回复记录失败:', error);
|
||||||
|
showToast('清空默认回复记录失败', 'danger');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== AI回复配置相关函数 ====================
|
// ==================== AI回复配置相关函数 ====================
|
||||||
|
|
||||||
// 配置AI回复
|
// 配置AI回复
|
||||||
|
Loading…
x
Reference in New Issue
Block a user