mirror of
https://github.com/zhinianboke/xianyu-auto-reply.git
synced 2025-08-30 01:27:35 +08:00
支持多数量发货
This commit is contained in:
parent
042c09329c
commit
d5ae0488b5
@ -522,10 +522,56 @@ class XianyuLive:
|
||||
|
||||
logger.info(f"【{self.cookie_id}】准备自动发货: item_id={item_id}, item_title={item_title}")
|
||||
|
||||
# 调用自动发货方法(包含自动确认发货)
|
||||
delivery_content = await self._auto_delivery(item_id, item_title, order_id, send_user_id)
|
||||
# 检查是否需要多数量发货
|
||||
from db_manager import db_manager
|
||||
quantity_to_send = 1 # 默认发送1个
|
||||
|
||||
# 检查商品是否开启了多数量发货
|
||||
multi_quantity_delivery = db_manager.get_item_multi_quantity_delivery_status(self.cookie_id, item_id)
|
||||
|
||||
if multi_quantity_delivery and order_id:
|
||||
logger.info(f"商品 {item_id} 开启了多数量发货,获取订单详情...")
|
||||
try:
|
||||
# 使用现有方法获取订单详情
|
||||
order_detail = await self.fetch_order_detail_info(order_id, item_id, send_user_id)
|
||||
if order_detail and order_detail.get('quantity'):
|
||||
try:
|
||||
order_quantity = int(order_detail['quantity'])
|
||||
if order_quantity > 1:
|
||||
quantity_to_send = order_quantity
|
||||
logger.info(f"从订单详情获取数量: {order_quantity},将发送 {quantity_to_send} 个卡券")
|
||||
else:
|
||||
logger.info(f"订单数量为 {order_quantity},发送单个卡券")
|
||||
except (ValueError, TypeError):
|
||||
logger.warning(f"订单数量格式无效: {order_detail.get('quantity')},发送单个卡券")
|
||||
else:
|
||||
logger.info(f"未获取到订单数量信息,发送单个卡券")
|
||||
except Exception as e:
|
||||
logger.error(f"获取订单详情失败: {self._safe_str(e)},发送单个卡券")
|
||||
elif not multi_quantity_delivery:
|
||||
logger.info(f"商品 {item_id} 未开启多数量发货,发送单个卡券")
|
||||
else:
|
||||
logger.info(f"无订单ID,发送单个卡券")
|
||||
|
||||
# 多次调用自动发货方法,每次获取不同的内容
|
||||
delivery_contents = []
|
||||
success_count = 0
|
||||
|
||||
for i in range(quantity_to_send):
|
||||
try:
|
||||
# 每次调用都可能获取不同的内容(API卡券、批量数据等)
|
||||
delivery_content = await self._auto_delivery(item_id, item_title, order_id, send_user_id)
|
||||
if delivery_content:
|
||||
delivery_contents.append(delivery_content)
|
||||
success_count += 1
|
||||
if quantity_to_send > 1:
|
||||
logger.info(f"第 {i+1}/{quantity_to_send} 个卡券内容获取成功")
|
||||
else:
|
||||
logger.warning(f"第 {i+1}/{quantity_to_send} 个卡券内容获取失败")
|
||||
except Exception as e:
|
||||
logger.error(f"第 {i+1}/{quantity_to_send} 个卡券获取异常: {self._safe_str(e)}")
|
||||
|
||||
if delivery_contents:
|
||||
# 标记已发货(防重复)- 基于订单ID
|
||||
self.mark_delivery_sent(order_id)
|
||||
|
||||
@ -541,6 +587,9 @@ class XianyuLive:
|
||||
delay_task = asyncio.create_task(self._delayed_lock_release(lock_key, delay_minutes=10))
|
||||
self._lock_hold_info[lock_key]['task'] = delay_task
|
||||
|
||||
# 发送所有获取到的发货内容
|
||||
for i, delivery_content in enumerate(delivery_contents):
|
||||
try:
|
||||
# 检查是否是图片发送标记
|
||||
if delivery_content.startswith("__IMAGE_SEND__"):
|
||||
# 提取卡券ID和图片URL
|
||||
@ -558,18 +607,35 @@ class XianyuLive:
|
||||
image_url = image_data
|
||||
|
||||
# 发送图片消息
|
||||
try:
|
||||
await self.send_image_msg(websocket, chat_id, send_user_id, image_url, card_id=card_id)
|
||||
if len(delivery_contents) > 1:
|
||||
logger.info(f'[{msg_time}] 【多数量自动发货图片】第 {i+1}/{len(delivery_contents)} 张已向 {user_url} 发送图片: {image_url}')
|
||||
else:
|
||||
logger.info(f'[{msg_time}] 【自动发货图片】已向 {user_url} 发送图片: {image_url}')
|
||||
await self.send_delivery_failure_notification(send_user_name, send_user_id, item_id, "发货成功")
|
||||
except Exception as e:
|
||||
logger.error(f"自动发货图片失败: {self._safe_str(e)}")
|
||||
await self.send_msg(websocket, chat_id, send_user_id, "抱歉,图片发送失败,请联系客服。")
|
||||
await self.send_delivery_failure_notification(send_user_name, send_user_id, item_id, "图片发送失败")
|
||||
|
||||
# 多数量发货时,消息间隔1秒
|
||||
if len(delivery_contents) > 1 and i < len(delivery_contents) - 1:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
else:
|
||||
# 普通文本发货内容
|
||||
await self.send_msg(websocket, chat_id, send_user_id, delivery_content)
|
||||
if len(delivery_contents) > 1:
|
||||
logger.info(f'[{msg_time}] 【多数量自动发货】第 {i+1}/{len(delivery_contents)} 条已向 {user_url} 发送发货内容')
|
||||
else:
|
||||
logger.info(f'[{msg_time}] 【自动发货】已向 {user_url} 发送发货内容')
|
||||
|
||||
# 多数量发货时,消息间隔1秒
|
||||
if len(delivery_contents) > 1 and i < len(delivery_contents) - 1:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"发送第 {i+1} 条消息失败: {self._safe_str(e)}")
|
||||
|
||||
# 发送成功通知
|
||||
if len(delivery_contents) > 1:
|
||||
await self.send_delivery_failure_notification(send_user_name, send_user_id, item_id, f"多数量发货成功,共发送 {len(delivery_contents)} 个卡券")
|
||||
else:
|
||||
await self.send_delivery_failure_notification(send_user_name, send_user_id, item_id, "发货成功")
|
||||
else:
|
||||
logger.warning(f'[{msg_time}] 【自动发货】未找到匹配的发货规则或获取发货内容失败')
|
||||
@ -2530,6 +2596,8 @@ class XianyuLive:
|
||||
logger.error(f"自动发货失败: {self._safe_str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def _process_delivery_content_with_description(self, delivery_content: str, card_description: str) -> str:
|
||||
"""处理发货内容和备注信息,实现变量替换"""
|
||||
try:
|
||||
|
@ -660,6 +660,14 @@ class DBManager:
|
||||
self._execute_sql(cursor, "ALTER TABLE item_info ADD COLUMN is_multi_spec BOOLEAN DEFAULT FALSE")
|
||||
logger.info("为item_info表添加多规格字段")
|
||||
|
||||
# 为item_info表添加多数量发货字段(如果不存在)
|
||||
try:
|
||||
self._execute_sql(cursor, "SELECT multi_quantity_delivery FROM item_info LIMIT 1")
|
||||
except sqlite3.OperationalError:
|
||||
# 多数量发货字段不存在,需要添加
|
||||
self._execute_sql(cursor, "ALTER TABLE item_info ADD COLUMN multi_quantity_delivery BOOLEAN DEFAULT FALSE")
|
||||
logger.info("为item_info表添加多数量发货字段")
|
||||
|
||||
# 处理keywords表的唯一约束问题
|
||||
# 由于SQLite不支持直接修改约束,我们需要重建表
|
||||
self._migrate_keywords_table_constraints(cursor)
|
||||
@ -3613,6 +3621,49 @@ class DBManager:
|
||||
logger.error(f"获取商品多规格状态失败: {e}")
|
||||
return False
|
||||
|
||||
def update_item_multi_quantity_delivery_status(self, cookie_id: str, item_id: str, multi_quantity_delivery: bool) -> bool:
|
||||
"""更新商品的多数量发货状态"""
|
||||
try:
|
||||
with self.lock:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute('''
|
||||
UPDATE item_info
|
||||
SET multi_quantity_delivery = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE cookie_id = ? AND item_id = ?
|
||||
''', (multi_quantity_delivery, cookie_id, item_id))
|
||||
|
||||
if cursor.rowcount > 0:
|
||||
self.conn.commit()
|
||||
logger.info(f"更新商品多数量发货状态成功: {item_id} -> {multi_quantity_delivery}")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"未找到要更新的商品: {item_id}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"更新商品多数量发货状态失败: {e}")
|
||||
self.conn.rollback()
|
||||
return False
|
||||
|
||||
def get_item_multi_quantity_delivery_status(self, cookie_id: str, item_id: str) -> bool:
|
||||
"""获取商品的多数量发货状态"""
|
||||
try:
|
||||
with self.lock:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute('''
|
||||
SELECT multi_quantity_delivery FROM item_info
|
||||
WHERE cookie_id = ? AND item_id = ?
|
||||
''', (cookie_id, item_id))
|
||||
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
return bool(row[0]) if row[0] is not None else False
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取商品多数量发货状态失败: {e}")
|
||||
return False
|
||||
|
||||
def get_items_by_cookie(self, cookie_id: str) -> List[Dict]:
|
||||
"""获取指定Cookie的所有商品信息
|
||||
|
||||
|
@ -4041,6 +4041,26 @@ def update_item_multi_spec(cookie_id: str, item_id: str, spec_data: dict, _: Non
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
# 商品多数量发货管理API
|
||||
@app.put("/items/{cookie_id}/{item_id}/multi-quantity-delivery")
|
||||
def update_item_multi_quantity_delivery(cookie_id: str, item_id: str, delivery_data: dict, _: None = Depends(require_auth)):
|
||||
"""更新商品的多数量发货状态"""
|
||||
try:
|
||||
from db_manager import db_manager
|
||||
|
||||
multi_quantity_delivery = delivery_data.get('multi_quantity_delivery', False)
|
||||
|
||||
success = db_manager.update_item_multi_quantity_delivery_status(cookie_id, item_id, multi_quantity_delivery)
|
||||
|
||||
if success:
|
||||
return {"message": f"商品多数量发货状态已{'开启' if multi_quantity_delivery else '关闭'}"}
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="商品不存在")
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
# 移除自动启动,由Start.py或手动启动
|
||||
# if __name__ == "__main__":
|
||||
# uvicorn.run(app, host="0.0.0.0", port=8080)
|
@ -399,19 +399,20 @@
|
||||
<th style="width: 5%">
|
||||
<input type="checkbox" id="selectAllItems" onchange="toggleSelectAll(this)">
|
||||
</th>
|
||||
<th style="width: 12%">账号ID</th>
|
||||
<th style="width: 12%">商品ID</th>
|
||||
<th style="width: 18%">商品标题</th>
|
||||
<th style="width: 20%">商品详情</th>
|
||||
<th style="width: 20%">商品价格</th>
|
||||
<th style="width: 10%">账号ID</th>
|
||||
<th style="width: 10%">商品ID</th>
|
||||
<th style="width: 16%">商品标题</th>
|
||||
<th style="width: 18%">商品详情</th>
|
||||
<th style="width: 18%">商品价格</th>
|
||||
<th style="width: 8%">多规格</th>
|
||||
<th style="width: 8%">多数量发货</th>
|
||||
<th style="width: 10%">更新时间</th>
|
||||
<th style="width: 15%">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="itemsTableBody">
|
||||
<tr>
|
||||
<td colspan="9" class="text-center text-muted">加载中...</td>
|
||||
<td colspan="10" class="text-center text-muted">加载中...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -4966,6 +4966,34 @@ async function toggleItemMultiSpec(cookieId, itemId, isMultiSpec) {
|
||||
}
|
||||
}
|
||||
|
||||
// 切换商品多数量发货状态
|
||||
async function toggleItemMultiQuantityDelivery(cookieId, itemId, multiQuantityDelivery) {
|
||||
try {
|
||||
const response = await fetch(`${apiBase}/items/${encodeURIComponent(cookieId)}/${encodeURIComponent(itemId)}/multi-quantity-delivery`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${authToken}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
multi_quantity_delivery: multiQuantityDelivery
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showToast(`${multiQuantityDelivery ? '开启' : '关闭'}多数量发货成功`, 'success');
|
||||
// 刷新商品列表
|
||||
await refreshItemsData();
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.error || '操作失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('切换多数量发货状态失败:', error);
|
||||
showToast(`切换多数量发货状态失败: ${error.message}`, 'danger');
|
||||
}
|
||||
}
|
||||
|
||||
// 加载商品列表
|
||||
async function loadItems() {
|
||||
try {
|
||||
@ -5181,7 +5209,7 @@ function displayCurrentPageItems() {
|
||||
const tbody = document.getElementById('itemsTableBody');
|
||||
|
||||
if (!filteredItemsData || filteredItemsData.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="9" class="text-center text-muted">暂无商品数据</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="10" class="text-center text-muted">暂无商品数据</td></tr>';
|
||||
resetItemsSelection();
|
||||
return;
|
||||
}
|
||||
@ -5211,6 +5239,12 @@ function displayCurrentPageItems() {
|
||||
'<span class="badge bg-success">多规格</span>' :
|
||||
'<span class="badge bg-secondary">普通</span>';
|
||||
|
||||
// 多数量发货状态显示
|
||||
const isMultiQuantityDelivery = item.multi_quantity_delivery;
|
||||
const multiQuantityDeliveryDisplay = isMultiQuantityDelivery ?
|
||||
'<span class="badge bg-success">已开启</span>' :
|
||||
'<span class="badge bg-secondary">已关闭</span>';
|
||||
|
||||
return `
|
||||
<tr>
|
||||
<td>
|
||||
@ -5225,6 +5259,7 @@ function displayCurrentPageItems() {
|
||||
<td title="${escapeHtml(getItemDetailText(item.item_detail || ''))}">${escapeHtml(itemDetailDisplay)}</td>
|
||||
<td>${escapeHtml(item.item_price || '未设置')}</td>
|
||||
<td>${multiSpecDisplay}</td>
|
||||
<td>${multiQuantityDeliveryDisplay}</td>
|
||||
<td>${formatDateTime(item.updated_at)}</td>
|
||||
<td>
|
||||
<div class="btn-group" role="group">
|
||||
@ -5237,6 +5272,9 @@ function displayCurrentPageItems() {
|
||||
<button class="btn btn-sm ${isMultiSpec ? 'btn-warning' : 'btn-success'}" onclick="toggleItemMultiSpec('${escapeHtml(item.cookie_id)}', '${escapeHtml(item.item_id)}', ${!isMultiSpec})" title="${isMultiSpec ? '关闭多规格' : '开启多规格'}">
|
||||
<i class="bi ${isMultiSpec ? 'bi-toggle-on' : 'bi-toggle-off'}"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm ${isMultiQuantityDelivery ? 'btn-warning' : 'btn-success'}" onclick="toggleItemMultiQuantityDelivery('${escapeHtml(item.cookie_id)}', '${escapeHtml(item.item_id)}', ${!isMultiQuantityDelivery})" title="${isMultiQuantityDelivery ? '关闭多数量发货' : '开启多数量发货'}">
|
||||
<i class="bi ${isMultiQuantityDelivery ? 'bi-box-arrow-down' : 'bi-box-arrow-up'}"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
Loading…
x
Reference in New Issue
Block a user