修复多规格发货的bug
This commit is contained in:
parent
9bb740d13d
commit
fe324c14ea
236
.github/workflows/README.md
vendored
236
.github/workflows/README.md
vendored
@ -1,236 +0,0 @@
|
||||
# 🔄 GitHub Actions 工作流说明
|
||||
|
||||
## 📋 工作流列表
|
||||
|
||||
### 1. docker-build.yml - Docker多架构镜像构建
|
||||
|
||||
**功能**: 自动构建并推送AMD64和ARM64双架构Docker镜像
|
||||
|
||||
**触发方式**:
|
||||
- 🏷️ **Tag推送**: 创建版本tag自动触发
|
||||
- 🖱️ **手动触发**: 在Actions页面手动运行
|
||||
- 📝 **代码修改**: Dockerfile等文件修改时触发
|
||||
|
||||
**支持的架构**:
|
||||
- ✅ linux/amd64 (x86_64)
|
||||
- ✅ linux/arm64 (aarch64)
|
||||
|
||||
**推送目标**:
|
||||
- Docker Hub: `zhinianboke/xianyu-auto-reply`
|
||||
- 阿里云: `registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply`
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 方式1: 通过Git Tag触发
|
||||
|
||||
```bash
|
||||
# 1. 提交代码
|
||||
git add .
|
||||
git commit -m "feat: 新功能"
|
||||
|
||||
# 2. 创建版本tag
|
||||
git tag -a v1.0.5 -m "版本 1.0.5"
|
||||
|
||||
# 3. 推送tag(自动触发构建)
|
||||
git push origin v1.0.5
|
||||
```
|
||||
|
||||
**构建时间**: 约15-25分钟(AMD64 + ARM64同时构建)
|
||||
|
||||
### 方式2: 手动触发
|
||||
|
||||
1. 访问仓库的 **Actions** 标签页
|
||||
2. 选择 **🐳 Build and Push Multi-Arch Docker Image**
|
||||
3. 点击 **Run workflow**
|
||||
4. 输入版本号(例如: 1.0.5)
|
||||
5. 点击 **Run workflow** 确认
|
||||
|
||||
## 🔐 必需的Secrets配置
|
||||
|
||||
在仓库的 **Settings → Secrets and variables → Actions** 中配置:
|
||||
|
||||
### Docker Hub (国际版)
|
||||
```
|
||||
DOCKERHUB_USERNAME=你的Docker Hub用户名
|
||||
DOCKERHUB_TOKEN=你的Docker Hub访问令牌
|
||||
```
|
||||
|
||||
### 阿里云镜像仓库 (国内版)
|
||||
```
|
||||
ALIYUN_USERNAME=你的阿里云账号
|
||||
ALIYUN_TOKEN=你的阿里云镜像仓库密码
|
||||
```
|
||||
|
||||
## 📦 获取访问令牌
|
||||
|
||||
### Docker Hub Token
|
||||
|
||||
1. 访问 https://hub.docker.com/settings/security
|
||||
2. 点击 **New Access Token**
|
||||
3. 输入Token名称(如: github-actions)
|
||||
4. 选择权限: **Read, Write, Delete**
|
||||
5. 复制生成的Token
|
||||
|
||||
### 阿里云Token
|
||||
|
||||
1. 访问 https://cr.console.aliyun.com/
|
||||
2. 进入 **访问凭证**
|
||||
3. 设置或重置密码
|
||||
4. 使用账号和密码作为Secrets
|
||||
|
||||
## 🏗️ 构建流程
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[触发构建] --> B[设置QEMU]
|
||||
B --> C[设置Buildx]
|
||||
C --> D[登录镜像仓库]
|
||||
D --> E[构建AMD64镜像]
|
||||
D --> F[构建ARM64镜像]
|
||||
E --> G[推送到仓库]
|
||||
F --> G
|
||||
G --> H[测试镜像]
|
||||
H --> I[创建Release]
|
||||
```
|
||||
|
||||
## 🧪 测试多架构镜像
|
||||
|
||||
构建完成后,工作流会自动测试两个架构的镜像:
|
||||
|
||||
```bash
|
||||
# AMD64测试
|
||||
docker run --rm --platform linux/amd64 \
|
||||
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest \
|
||||
python --version
|
||||
|
||||
# ARM64测试
|
||||
docker run --rm --platform linux/arm64 \
|
||||
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest \
|
||||
python --version
|
||||
```
|
||||
|
||||
## 📊 查看镜像信息
|
||||
|
||||
```bash
|
||||
# 查看镜像支持的架构
|
||||
docker manifest inspect registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
|
||||
|
||||
# 输出示例:
|
||||
# - linux/amd64
|
||||
# - linux/arm64
|
||||
```
|
||||
|
||||
## ⚡ 性能优化
|
||||
|
||||
### 构建缓存
|
||||
- ✅ 使用GitHub Actions缓存
|
||||
- ✅ 多层构建缓存复用
|
||||
- ✅ 依赖层缓存
|
||||
|
||||
### 并行构建
|
||||
- ✅ AMD64和ARM64并行构建
|
||||
- ✅ 国际版和国内版并行推送
|
||||
|
||||
## 🔍 故障排查
|
||||
|
||||
### 构建失败
|
||||
|
||||
**问题**: 构建超时或失败
|
||||
**解决**:
|
||||
1. 检查Dockerfile语法
|
||||
2. 查看Actions日志
|
||||
3. 重新运行工作流
|
||||
|
||||
### 推送失败
|
||||
|
||||
**问题**: 无法推送到镜像仓库
|
||||
**解决**:
|
||||
1. 检查Secrets配置是否正确
|
||||
2. 验证访问令牌是否有效
|
||||
3. 检查镜像仓库权限
|
||||
|
||||
### ARM64构建慢
|
||||
|
||||
**问题**: ARM64构建时间长
|
||||
**说明**: 这是正常现象,因为使用QEMU模拟ARM架构
|
||||
|
||||
## 💡 最佳实践
|
||||
|
||||
### 版本号规范
|
||||
|
||||
遵循语义化版本:`v主版本.次版本.修订号`
|
||||
|
||||
```bash
|
||||
v1.0.0 # 初始稳定版本
|
||||
v1.0.1 # Bug修复
|
||||
v1.1.0 # 新增功能
|
||||
v2.0.0 # 重大更新
|
||||
```
|
||||
|
||||
### 提交信息规范
|
||||
|
||||
```bash
|
||||
feat: 新功能
|
||||
fix: Bug修复
|
||||
docs: 文档更新
|
||||
perf: 性能优化
|
||||
chore: 构建/工具
|
||||
|
||||
示例:
|
||||
git commit -m "feat: 添加ARM64架构支持"
|
||||
git commit -m "fix: 修复Docker容器内存泄漏"
|
||||
```
|
||||
|
||||
### 发布检查清单
|
||||
|
||||
- [ ] 代码已测试通过
|
||||
- [ ] Dockerfile已更新
|
||||
- [ ] requirements.txt已更新
|
||||
- [ ] README版本号已更新
|
||||
- [ ] Secrets配置正确
|
||||
- [ ] 本地Docker构建测试通过
|
||||
|
||||
## 📞 常见问题
|
||||
|
||||
**Q: 如何只构建AMD64镜像?**
|
||||
A: 修改workflow中的platforms参数:
|
||||
```yaml
|
||||
platforms: linux/amd64
|
||||
```
|
||||
|
||||
**Q: 如何添加更多架构?**
|
||||
A: 在platforms中添加,例如:
|
||||
```yaml
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
```
|
||||
|
||||
**Q: 构建时间太长怎么办?**
|
||||
A:
|
||||
1. 优化Dockerfile减少层数
|
||||
2. 使用构建缓存
|
||||
3. 考虑只构建AMD64(ARM64可选)
|
||||
|
||||
**Q: 如何验证多架构镜像?**
|
||||
A:
|
||||
```bash
|
||||
# 查看manifest
|
||||
docker manifest inspect <镜像名>:latest
|
||||
|
||||
# 在不同平台测试
|
||||
docker run --platform linux/amd64 <镜像名>:latest
|
||||
docker run --platform linux/arm64 <镜像名>:latest
|
||||
```
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### 2025-01
|
||||
- ✅ 添加多架构Docker镜像构建支持
|
||||
- ✅ 支持AMD64和ARM64架构
|
||||
- ✅ 自动推送到Docker Hub和阿里云
|
||||
- ✅ 自动创建Release说明
|
||||
|
||||
---
|
||||
|
||||
**维护者**: zhinianboke
|
||||
**最后更新**: 2025-01
|
||||
|
||||
253
.github/workflows/docker-build.yml
vendored
253
.github/workflows/docker-build.yml
vendored
@ -1,253 +0,0 @@
|
||||
name: 🐳 Build and Push Multi-Arch Docker Image
|
||||
|
||||
on:
|
||||
# 手动触发
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: '镜像版本号 (例如: latest)'
|
||||
required: true
|
||||
default: 'latest'
|
||||
|
||||
# 自动触发
|
||||
push:
|
||||
# 当创建tag时触发
|
||||
tags:
|
||||
- 'v*'
|
||||
# 当有代码推送到主分支时触发
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
# 排除不需要构建的文件
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- '*.md'
|
||||
- 'docs/**'
|
||||
- '.gitignore'
|
||||
- 'LICENSE'
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: 🏗️ Build Multi-Arch Docker Images
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
# 国际版 (Docker Hub)
|
||||
- dockerfile: Dockerfile
|
||||
registry: docker.io
|
||||
image_name: zhinianblog/xianyu-auto-reply
|
||||
tag_suffix: ''
|
||||
|
||||
# 国内版 (阿里云)
|
||||
- dockerfile: Dockerfile
|
||||
registry: registry.cn-shanghai.aliyuncs.com
|
||||
image_name: zhinian-software/xianyu-auto-reply
|
||||
tag_suffix: ''
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🔧 设置QEMU (ARM模拟)
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: 🔧 设置Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
install: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: 🔐 登录Docker Hub
|
||||
if: matrix.registry == 'docker.io'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: 🔐 登录阿里云镜像仓库
|
||||
if: matrix.registry == 'registry.cn-shanghai.aliyuncs.com'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-shanghai.aliyuncs.com
|
||||
username: ${{ secrets.ALIYUN_USERNAME }}
|
||||
password: ${{ secrets.ALIYUN_TOKEN }}
|
||||
|
||||
- name: 📝 提取元数据
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ matrix.registry }}/${{ matrix.image_name }}
|
||||
tags: |
|
||||
# 从tag提取版本号: v1.0.5 -> 1.0.5
|
||||
type=semver,pattern={{version}}
|
||||
# 从手动输入提取
|
||||
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }}
|
||||
# latest标签
|
||||
type=raw,value=latest
|
||||
|
||||
- name: 🏗️ 构建并推送多架构镜像
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
BUILDTIME=${{ github.event.head_commit.timestamp }}
|
||||
VERSION=${{ steps.meta.outputs.version }}
|
||||
|
||||
- name: 📊 输出镜像信息
|
||||
run: |
|
||||
echo "========================================="
|
||||
echo "✅ 镜像构建成功!"
|
||||
echo "========================================="
|
||||
echo "镜像仓库: ${{ matrix.registry }}"
|
||||
echo "镜像名称: ${{ matrix.image_name }}"
|
||||
echo "支持架构: linux/amd64, linux/arm64"
|
||||
echo ""
|
||||
echo "📦 镜像标签:"
|
||||
echo "${{ steps.meta.outputs.tags }}"
|
||||
echo ""
|
||||
echo "🚀 使用方法:"
|
||||
echo "docker pull ${{ matrix.registry }}/${{ matrix.image_name }}:latest"
|
||||
echo "========================================="
|
||||
|
||||
# 测试多架构镜像
|
||||
test-images:
|
||||
name: 🧪 Test Multi-Arch Images
|
||||
needs: build-and-push
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [linux/amd64, linux/arm64]
|
||||
registry:
|
||||
- registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply
|
||||
|
||||
steps:
|
||||
- name: 🔧 设置QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: ${{ matrix.platform }}
|
||||
|
||||
- name: 🧪 测试镜像
|
||||
run: |
|
||||
echo "测试平台: ${{ matrix.platform }}"
|
||||
docker run --rm --platform ${{ matrix.platform }} \
|
||||
${{ matrix.registry }}:latest \
|
||||
python --version || true
|
||||
|
||||
docker run --rm --platform ${{ matrix.platform }} \
|
||||
${{ matrix.registry }}:latest \
|
||||
python -c "import sys; print(f'Python {sys.version}')" || true
|
||||
|
||||
# 创建Release说明
|
||||
create-release-notes:
|
||||
name: 📝 Create Release Notes
|
||||
needs: [build-and-push, test-images]
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 📝 生成Release说明
|
||||
id: release_notes
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/v}
|
||||
cat > release_notes.md << EOF
|
||||
# 🐳 Docker镜像发布 - v${VERSION}
|
||||
|
||||
## 📦 镜像信息
|
||||
|
||||
### 国际版 (Docker Hub)
|
||||
\`\`\`bash
|
||||
docker pull zhinianboke/xianyu-auto-reply:${VERSION}
|
||||
docker pull zhinianboke/xianyu-auto-reply:latest
|
||||
\`\`\`
|
||||
|
||||
### 国内版 (阿里云)
|
||||
\`\`\`bash
|
||||
docker pull registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:${VERSION}
|
||||
docker pull registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:latest
|
||||
\`\`\`
|
||||
|
||||
## 🖥️ 支持的架构
|
||||
|
||||
- ✅ **linux/amd64** - Intel/AMD处理器
|
||||
- ✅ **linux/arm64** - ARM64处理器
|
||||
|
||||
## 🚀 快速启动
|
||||
|
||||
### x86_64服务器
|
||||
\`\`\`bash
|
||||
docker run -d -p 8080:8080 --restart always \\
|
||||
-v \$PWD/xianyu-auto-reply/:/app/data/ \\
|
||||
--name xianyu-auto-reply \\
|
||||
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:${VERSION}
|
||||
\`\`\`
|
||||
|
||||
### ARM64服务器
|
||||
\`\`\`bash
|
||||
docker run -d -p 8080:8080 --restart always \\
|
||||
--platform linux/arm64 \\
|
||||
-v \$PWD/xianyu-auto-reply/:/app/data/ \\
|
||||
--name xianyu-auto-reply \\
|
||||
registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:${VERSION}
|
||||
\`\`\`
|
||||
|
||||
## 📋 更新内容
|
||||
|
||||
查看 [CHANGELOG.md](./CHANGELOG.md) 了解详细更新内容。
|
||||
|
||||
## 🔍 验证镜像
|
||||
|
||||
\`\`\`bash
|
||||
# 检查镜像架构
|
||||
docker manifest inspect registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:${VERSION}
|
||||
|
||||
# 测试运行
|
||||
docker run --rm registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:${VERSION} python --version
|
||||
\`\`\`
|
||||
|
||||
## 💡 适用场景
|
||||
|
||||
### x86_64 (amd64)
|
||||
- 传统服务器和VPS
|
||||
- 阿里云、腾讯云、华为云标准实例
|
||||
- 本地PC和虚拟机
|
||||
|
||||
### ARM64 (aarch64)
|
||||
- Oracle Cloud - Ampere A1 (永久免费)
|
||||
- AWS Graviton2/3实例
|
||||
- 阿里云倚天710实例
|
||||
- 树莓派4/5
|
||||
- Apple M系列芯片 (通过Docker Desktop)
|
||||
|
||||
---
|
||||
|
||||
**构建时间**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
**Git提交**: ${GITHUB_SHA}
|
||||
EOF
|
||||
|
||||
cat release_notes.md
|
||||
|
||||
- name: 💾 创建Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body_path: release_notes.md
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -1838,7 +1838,7 @@ class XianyuLive:
|
||||
return False
|
||||
|
||||
async def fetch_item_detail_from_api(self, item_id: str) -> str:
|
||||
"""获取商品详情(优先使用浏览器,备用外部API,支持24小时缓存)
|
||||
"""获取商品详情(使用浏览器获取,支持24小时缓存)
|
||||
|
||||
Args:
|
||||
item_id: 商品ID
|
||||
@ -1881,16 +1881,8 @@ class XianyuLive:
|
||||
logger.info(f"成功通过浏览器获取商品详情: {item_id}, 长度: {len(detail_from_browser)}")
|
||||
return detail_from_browser
|
||||
|
||||
# 3. 浏览器获取失败,使用外部API作为备用
|
||||
logger.warning(f"浏览器获取商品详情失败,尝试外部API: {item_id}")
|
||||
detail_from_api = await self._fetch_item_detail_from_external_api(item_id)
|
||||
if detail_from_api:
|
||||
# 保存到缓存(带大小限制)
|
||||
await self._add_to_item_cache(item_id, detail_from_api)
|
||||
logger.info(f"成功通过外部API获取商品详情: {item_id}, 长度: {len(detail_from_api)}")
|
||||
return detail_from_api
|
||||
|
||||
logger.warning(f"所有方式都无法获取商品详情: {item_id}")
|
||||
# 浏览器获取失败
|
||||
logger.warning(f"浏览器获取商品详情失败: {item_id}")
|
||||
return ""
|
||||
|
||||
except Exception as e:
|
||||
@ -2079,48 +2071,6 @@ class XianyuLive:
|
||||
except Exception as e:
|
||||
logger.warning(f"停止playwright时出错: {self._safe_str(e)}")
|
||||
|
||||
async def _fetch_item_detail_from_external_api(self, item_id: str) -> str:
|
||||
"""从外部API获取商品详情(备用方案)"""
|
||||
try:
|
||||
from config import config
|
||||
auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})
|
||||
|
||||
# 从配置获取API地址和超时时间
|
||||
api_base_url = auto_fetch_config.get('api_url', 'https://selfapi.zhinianboke.com/api/getItemDetail')
|
||||
timeout_seconds = auto_fetch_config.get('timeout', 10)
|
||||
|
||||
api_url = f"{api_base_url}/{item_id}"
|
||||
|
||||
logger.info(f"正在从外部API获取商品详情: {item_id}")
|
||||
|
||||
# 使用aiohttp发送异步请求
|
||||
import aiohttp
|
||||
|
||||
timeout = aiohttp.ClientTimeout(total=timeout_seconds)
|
||||
|
||||
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||
async with session.get(api_url) as response:
|
||||
if response.status == 200:
|
||||
result = await response.json()
|
||||
|
||||
# 检查返回状态
|
||||
if result.get('status') == '200' and result.get('data'):
|
||||
item_detail = result['data']
|
||||
logger.info(f"外部API成功获取商品详情: {item_id}, 长度: {len(item_detail)}")
|
||||
return item_detail
|
||||
else:
|
||||
logger.warning(f"外部API返回状态异常: {result.get('status')}, message: {result.get('message')}")
|
||||
return ""
|
||||
else:
|
||||
logger.warning(f"外部API请求失败: HTTP {response.status}")
|
||||
return ""
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning(f"外部API获取商品详情超时: {item_id}")
|
||||
return ""
|
||||
except Exception as e:
|
||||
logger.error(f"外部API获取商品详情异常: {item_id}, 错误: {self._safe_str(e)}")
|
||||
return ""
|
||||
|
||||
async def save_items_list_to_db(self, items_list):
|
||||
"""批量保存商品列表信息到数据库(并发安全)
|
||||
@ -3685,12 +3635,12 @@ class XianyuLive:
|
||||
if success and self.order_status_handler:
|
||||
logger.info(f"【{self.cookie_id}】准备调用订单状态处理器.handle_order_detail_fetched_status: {order_id}")
|
||||
try:
|
||||
result = self.order_status_handler.handle_order_detail_fetched_status(
|
||||
handler_result = self.order_status_handler.handle_order_detail_fetched_status(
|
||||
order_id=order_id,
|
||||
cookie_id=self.cookie_id,
|
||||
context="订单详情已拉取"
|
||||
)
|
||||
logger.info(f"【{self.cookie_id}】订单状态处理器.handle_order_detail_fetched_status返回结果: {result}")
|
||||
logger.info(f"【{self.cookie_id}】订单状态处理器.handle_order_detail_fetched_status返回结果: {handler_result}")
|
||||
|
||||
# 处理待处理队列
|
||||
logger.info(f"【{self.cookie_id}】准备调用订单状态处理器.on_order_details_fetched: {order_id}")
|
||||
@ -3733,91 +3683,58 @@ class XianyuLive:
|
||||
search_text = item_title # 默认使用传入的标题
|
||||
|
||||
if item_id and item_id != "未知商品":
|
||||
# 优先尝试通过API获取商品信息
|
||||
# 直接从数据库获取商品信息(发货时不再调用API)
|
||||
try:
|
||||
logger.info(f"通过API获取商品详细信息: {item_id}")
|
||||
item_info = await self.get_item_info(item_id)
|
||||
if item_info and 'data' in item_info:
|
||||
data = item_info['data']
|
||||
item_data = data['itemDO']
|
||||
shareData = item_data['shareData']
|
||||
shareInfoJsonString = shareData['shareInfoJsonString']
|
||||
logger.info(f"从数据库获取商品信息: {item_id}")
|
||||
db_item_info = db_manager.get_item_info(self.cookie_id, item_id)
|
||||
if db_item_info:
|
||||
# 拼接商品标题和详情作为搜索文本
|
||||
item_title_db = db_item_info.get('item_title', '') or ''
|
||||
item_detail_db = db_item_info.get('item_detail', '') or ''
|
||||
|
||||
# 解析 shareInfoJsonString 并提取 content 内容
|
||||
try:
|
||||
share_info = json.loads(shareInfoJsonString)
|
||||
content = share_info.get('contentParams', {}).get('mainParams', {}).get('content', '')
|
||||
if content:
|
||||
search_text = content
|
||||
logger.info(f"API成功提取商品内容作为搜索文本: {content[:100]}...")
|
||||
# 如果数据库中没有详情,尝试自动获取
|
||||
if not item_detail_db.strip():
|
||||
from config import config
|
||||
auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})
|
||||
|
||||
if auto_fetch_config.get('enabled', True):
|
||||
logger.info(f"数据库中商品详情为空,尝试自动获取: {item_id}")
|
||||
try:
|
||||
fetched_detail = await self.fetch_item_detail_from_api(item_id)
|
||||
if fetched_detail:
|
||||
# 保存获取到的详情
|
||||
await self.save_item_detail_only(item_id, fetched_detail)
|
||||
item_detail_db = fetched_detail
|
||||
logger.info(f"成功获取并保存商品详情: {item_id}")
|
||||
else:
|
||||
logger.warning(f"未能获取到商品详情: {item_id}")
|
||||
except Exception as api_e:
|
||||
logger.warning(f"获取商品详情失败: {item_id}, 错误: {self._safe_str(api_e)}")
|
||||
else:
|
||||
search_text = shareInfoJsonString
|
||||
logger.warning("未能从API商品信息中提取到content字段,使用完整JSON字符串")
|
||||
except json.JSONDecodeError as json_e:
|
||||
logger.warning(f"解析API商品信息JSON失败: {self._safe_str(json_e)},使用原始字符串")
|
||||
search_text = shareInfoJsonString
|
||||
except Exception as parse_e:
|
||||
logger.warning(f"提取API商品内容失败: {self._safe_str(parse_e)},使用原始字符串")
|
||||
search_text = shareInfoJsonString
|
||||
logger.debug(f"自动获取商品详情功能已禁用,跳过: {item_id}")
|
||||
|
||||
logger.info(f"API获取到的商品信息为: {search_text[:200]}...")
|
||||
else:
|
||||
raise Exception("API返回数据格式异常")
|
||||
# 组合搜索文本:商品标题 + 商品详情
|
||||
search_parts = []
|
||||
if item_title_db.strip():
|
||||
search_parts.append(item_title_db.strip())
|
||||
if item_detail_db.strip():
|
||||
search_parts.append(item_detail_db.strip())
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"API获取商品信息失败: {self._safe_str(e)},尝试从数据库获取")
|
||||
|
||||
# API失败时,从数据库获取商品信息
|
||||
try:
|
||||
db_item_info = db_manager.get_item_info(self.cookie_id, item_id)
|
||||
if db_item_info:
|
||||
# 拼接商品标题和详情作为搜索文本
|
||||
item_title_db = db_item_info.get('item_title', '') or ''
|
||||
item_detail_db = db_item_info.get('item_detail', '') or ''
|
||||
|
||||
# 如果数据库中没有详情,尝试从外部API获取
|
||||
if not item_detail_db.strip():
|
||||
from config import config
|
||||
auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})
|
||||
|
||||
if auto_fetch_config.get('enabled', True):
|
||||
logger.info(f"数据库中商品详情为空,尝试从外部API获取: {item_id}")
|
||||
try:
|
||||
fetched_detail = await self.fetch_item_detail_from_api(item_id)
|
||||
if fetched_detail:
|
||||
# 保存获取到的详情
|
||||
await self.save_item_detail_only(item_id, fetched_detail)
|
||||
item_detail_db = fetched_detail
|
||||
logger.info(f"成功从外部API获取并保存商品详情: {item_id}")
|
||||
else:
|
||||
logger.warning(f"外部API未能获取到商品详情: {item_id}")
|
||||
except Exception as api_e:
|
||||
logger.warning(f"从外部API获取商品详情失败: {item_id}, 错误: {self._safe_str(api_e)}")
|
||||
else:
|
||||
logger.debug(f"自动获取商品详情功能已禁用,跳过: {item_id}")
|
||||
|
||||
# 组合搜索文本:商品标题 + 商品详情
|
||||
search_parts = []
|
||||
if item_title_db.strip():
|
||||
search_parts.append(item_title_db.strip())
|
||||
if item_detail_db.strip():
|
||||
search_parts.append(item_detail_db.strip())
|
||||
|
||||
if search_parts:
|
||||
search_text = ' '.join(search_parts)
|
||||
logger.info(f"使用数据库商品标题+详情作为搜索文本: 标题='{item_title_db}', 详情长度={len(item_detail_db)}")
|
||||
logger.debug(f"完整搜索文本: {search_text[:200]}...")
|
||||
else:
|
||||
logger.warning(f"数据库中商品标题和详情都为空,且无法从API获取: {item_id}")
|
||||
search_text = item_title or item_id
|
||||
if search_parts:
|
||||
search_text = ' '.join(search_parts)
|
||||
logger.info(f"使用数据库商品标题+详情作为搜索文本: 标题='{item_title_db}', 详情长度={len(item_detail_db)}")
|
||||
logger.debug(f"完整搜索文本: {search_text[:200]}...")
|
||||
else:
|
||||
logger.debug(f"数据库中未找到商品信息: {item_id}")
|
||||
logger.warning(f"数据库中商品标题和详情都为空: {item_id}")
|
||||
search_text = item_title or item_id
|
||||
|
||||
except Exception as db_e:
|
||||
logger.debug(f"从数据库获取商品信息失败: {self._safe_str(db_e)}")
|
||||
else:
|
||||
logger.debug(f"数据库中未找到商品信息: {item_id}")
|
||||
search_text = item_title or item_id
|
||||
|
||||
except Exception as db_e:
|
||||
logger.warning(f"从数据库获取商品信息失败: {self._safe_str(db_e)}")
|
||||
search_text = item_title or item_id
|
||||
|
||||
if not search_text:
|
||||
search_text = item_id or "未知商品"
|
||||
|
||||
@ -3833,7 +3750,8 @@ class XianyuLive:
|
||||
logger.info(f"检测到多规格商品,获取订单规格信息: {order_id}")
|
||||
try:
|
||||
order_detail = await self.fetch_order_detail_info(order_id, item_id, send_user_id)
|
||||
if order_detail:
|
||||
# 确保order_detail是字典类型
|
||||
if order_detail and isinstance(order_detail, dict):
|
||||
spec_name = order_detail.get('spec_name', '')
|
||||
spec_value = order_detail.get('spec_value', '')
|
||||
if spec_name and spec_value:
|
||||
@ -3841,7 +3759,7 @@ class XianyuLive:
|
||||
else:
|
||||
logger.warning(f"未能获取到规格信息,将使用兜底匹配")
|
||||
else:
|
||||
logger.warning(f"获取订单详情失败,将使用兜底匹配")
|
||||
logger.warning(f"获取订单详情失败(返回类型: {type(order_detail).__name__}),将使用兜底匹配")
|
||||
except Exception as e:
|
||||
logger.error(f"获取订单规格信息失败: {self._safe_str(e)},将使用兜底匹配")
|
||||
|
||||
|
||||
@ -711,6 +711,32 @@ class OrderStatusHandler:
|
||||
|
||||
# 获取对应的状态(new_status已经在上面通过_check_refund_message或message_status_mapping确定了)
|
||||
|
||||
# 检查当前订单状态,避免不合理的状态回退
|
||||
from db_manager import db_manager
|
||||
current_order = db_manager.get_order_by_id(order_id)
|
||||
|
||||
# 如果订单存在,检查是否需要忽略这次状态更新
|
||||
if current_order and current_order.get('order_status'):
|
||||
current_status = current_order.get('order_status')
|
||||
|
||||
# 定义状态优先级(数字越大,状态越靠后)
|
||||
status_priority = {
|
||||
'processing': 1, # 处理中
|
||||
'pending_ship': 2, # 待发货
|
||||
'shipped': 3, # 已发货
|
||||
'completed': 4, # 已完成
|
||||
'refunding': 2, # 退款中(与待发货同级)
|
||||
'cancelled': 5, # 已取消(终态)
|
||||
}
|
||||
|
||||
current_priority = status_priority.get(current_status, 0)
|
||||
new_priority = status_priority.get(new_status, 0)
|
||||
|
||||
# 如果新状态的优先级低于当前状态,且不是特殊状态(退款、取消),则忽略
|
||||
if new_priority < current_priority and new_status not in ['refunding', 'cancelled']:
|
||||
logger.warning(f'[{msg_time}] 【{cookie_id}】{send_message},订单 {order_id} 当前状态为 {current_status},忽略回退到 {new_status}')
|
||||
return True # 返回True表示已处理,但实际上是忽略
|
||||
|
||||
# 更新订单状态
|
||||
success = self.update_order_status(
|
||||
order_id=order_id,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user