fix: 修正定时任务状态下次更新时间的显示逻辑,分别精确到早上6点和下午5点
This commit is contained in:
parent
ff9d9a857e
commit
cb46b20d15
237
README.md
237
README.md
@ -13,6 +13,7 @@
|
|||||||
- Scikit-learn (机器学习)
|
- Scikit-learn (机器学习)
|
||||||
- NumPy (数值计算)
|
- NumPy (数值计算)
|
||||||
- Pandas (数据处理)
|
- Pandas (数据处理)
|
||||||
|
- Schedule (定时任务)
|
||||||
|
|
||||||
### 前端
|
### 前端
|
||||||
- Vue 3
|
- Vue 3
|
||||||
@ -30,6 +31,7 @@
|
|||||||
- 数据导出
|
- 数据导出
|
||||||
- 手动数据录入
|
- 手动数据录入
|
||||||
- **自动数据更新** ⭐ 新功能
|
- **自动数据更新** ⭐ 新功能
|
||||||
|
- **定时任务系统** ⭐ 新功能
|
||||||
|
|
||||||
### 2. 基础统计分析
|
### 2. 基础统计分析
|
||||||
- 号码出现频率统计
|
- 号码出现频率统计
|
||||||
@ -52,6 +54,7 @@
|
|||||||
- **集成预测**: 多方法综合预测
|
- **集成预测**: 多方法综合预测
|
||||||
- **预测模型训练**: 可自定义训练参数
|
- **预测模型训练**: 可自定义训练参数
|
||||||
- **预测结果评估**: 预测准确率统计
|
- **预测结果评估**: 预测准确率统计
|
||||||
|
- **每日拼盘推荐**: 定时生成推荐号码 ⭐ 新功能
|
||||||
|
|
||||||
### 5. 智能选号
|
### 5. 智能选号
|
||||||
- 随机选号
|
- 随机选号
|
||||||
@ -60,6 +63,12 @@
|
|||||||
- 冷门号码选号
|
- 冷门号码选号
|
||||||
- 自定义选号策略
|
- 自定义选号策略
|
||||||
|
|
||||||
|
### 6. 定时任务系统 ⭐ 新功能
|
||||||
|
- **每天早上6点**: 自动更新开奖数据
|
||||||
|
- **每天下午5点**: 自动生成拼盘推荐
|
||||||
|
- **任务状态监控**: 实时查看任务执行状态
|
||||||
|
- **日志记录**: 详细的任务执行日志
|
||||||
|
|
||||||
## 项目结构
|
## 项目结构
|
||||||
```
|
```
|
||||||
lottery/
|
lottery/
|
||||||
@ -76,7 +85,9 @@ lottery/
|
|||||||
│ │ ├── advanced_analysis.py # 高级分析服务 ⭐
|
│ │ ├── advanced_analysis.py # 高级分析服务 ⭐
|
||||||
│ │ └── prediction_service.py # 预测服务 ⭐
|
│ │ └── prediction_service.py # 预测服务 ⭐
|
||||||
│ ├── requirements.txt # 依赖包
|
│ ├── requirements.txt # 依赖包
|
||||||
│ └── main.py # 入口文件
|
│ ├── main.py # 入口文件
|
||||||
|
│ ├── scheduler.py # 定时任务调度器 ⭐
|
||||||
|
│ └── update_lottery.py # 数据更新脚本
|
||||||
├── frontend/ # 前端代码
|
├── frontend/ # 前端代码
|
||||||
│ ├── src/
|
│ ├── src/
|
||||||
│ │ ├── api/ # API 接口
|
│ │ ├── api/ # API 接口
|
||||||
@ -85,6 +96,7 @@ lottery/
|
|||||||
│ │ ├── router/ # 路由配置
|
│ │ ├── router/ # 路由配置
|
||||||
│ │ ├── views/ # 页面
|
│ │ ├── views/ # 页面
|
||||||
│ │ │ ├── AdvancedAnalysis.vue # 高级分析页面 ⭐
|
│ │ │ ├── AdvancedAnalysis.vue # 高级分析页面 ⭐
|
||||||
|
│ │ │ ├── NumberGenerator.vue # 一键下单页面 ⭐
|
||||||
│ │ │ └── Prediction.vue # 预测页面 ⭐
|
│ │ │ └── Prediction.vue # 预测页面 ⭐
|
||||||
│ │ ├── App.vue # 根组件
|
│ │ ├── App.vue # 根组件
|
||||||
│ │ └── main.js # 入口文件
|
│ │ └── main.js # 入口文件
|
||||||
@ -110,8 +122,11 @@ python start_system.py
|
|||||||
|
|
||||||
脚本会自动:
|
脚本会自动:
|
||||||
- 检查Python版本和依赖
|
- 检查Python版本和依赖
|
||||||
|
- 检查数据库连接
|
||||||
|
- 询问是否启动定时任务
|
||||||
- 启动后端服务(端口8000)
|
- 启动后端服务(端口8000)
|
||||||
- 启动前端服务(端口5173)
|
- 启动前端服务(端口5173)
|
||||||
|
- 启动定时任务调度器(可选)
|
||||||
- 显示访问地址和使用说明
|
- 显示访问地址和使用说明
|
||||||
|
|
||||||
### 手动启动
|
### 手动启动
|
||||||
@ -156,8 +171,46 @@ npm run dev
|
|||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 定时任务 ⭐ 新功能
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python scheduler.py
|
||||||
|
```
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
|
### 定时任务系统 ⭐ 新功能
|
||||||
|
|
||||||
|
#### 自动任务
|
||||||
|
系统提供两个定时任务:
|
||||||
|
|
||||||
|
1. **每天早上6点 - 数据更新任务**
|
||||||
|
- 自动从API获取最新开奖数据
|
||||||
|
- 更新双色球和大乐透数据
|
||||||
|
- 检查历史投注的中奖情况
|
||||||
|
- 记录详细执行日志
|
||||||
|
|
||||||
|
2. **每天下午5点 - 拼盘推荐任务**
|
||||||
|
- 自动生成今日拼盘推荐
|
||||||
|
- 使用集成预测算法
|
||||||
|
- 生成4注推荐号码
|
||||||
|
- 保存到数据库供前端显示
|
||||||
|
|
||||||
|
#### 手动启动定时任务
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python scheduler.py
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 查看任务状态
|
||||||
|
- 在一键下单页面查看定时任务状态
|
||||||
|
- 显示下次执行时间
|
||||||
|
- 显示今日推荐生成状态
|
||||||
|
|
||||||
|
#### 任务日志
|
||||||
|
- 日志文件:`backend/lottery_scheduler.log`
|
||||||
|
- 包含详细的执行记录和错误信息
|
||||||
|
|
||||||
### 数据导入与更新说明
|
### 数据导入与更新说明
|
||||||
|
|
||||||
#### 数据导入
|
#### 数据导入
|
||||||
@ -167,7 +220,8 @@ npm run build
|
|||||||
- 支持 pandas DataFrame 或 JSON 文件导入。
|
- 支持 pandas DataFrame 或 JSON 文件导入。
|
||||||
|
|
||||||
#### 数据自动/手动更新 ⭐ 新功能
|
#### 数据自动/手动更新 ⭐ 新功能
|
||||||
- **前端更新功能**: 在首页提供"更新双色球"、"更新大乐透"、"更新全部"三个按钮
|
- **定时更新**: 每天早上6点自动更新(推荐)
|
||||||
|
- **前端更新功能**: 在首页提供"补红蓝球煎饼"、"补大乐斗豆浆"、"补全场早点"三个按钮
|
||||||
- **API更新接口**: 支持通过API接口更新数据
|
- **API更新接口**: 支持通过API接口更新数据
|
||||||
- `POST /api/v1/lottery/update/ssq` - 更新双色球数据
|
- `POST /api/v1/lottery/update/ssq` - 更新双色球数据
|
||||||
- `POST /api/v1/lottery/update/dlt` - 更新大乐透数据
|
- `POST /api/v1/lottery/update/dlt` - 更新大乐透数据
|
||||||
@ -188,9 +242,27 @@ python update_lottery.py
|
|||||||
##### 自动定时更新
|
##### 自动定时更新
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
python schedule_update.py
|
python scheduler.py
|
||||||
```
|
```
|
||||||
系统会在每天凌晨2点自动检查并更新数据。
|
系统会在每天凌晨6点自动检查并更新数据。
|
||||||
|
|
||||||
|
### 拼盘推荐系统 ⭐ 新功能
|
||||||
|
|
||||||
|
#### 自动推荐
|
||||||
|
- **定时生成**: 每天下午5点自动生成
|
||||||
|
- **智能算法**: 使用集成预测算法
|
||||||
|
- **多注推荐**: 每次生成4注推荐号码
|
||||||
|
- **类型轮换**: 根据日期自动选择彩票类型
|
||||||
|
|
||||||
|
#### 手动生成
|
||||||
|
- 在一键下单页面点击"来一份拼盘"按钮
|
||||||
|
- 实时生成推荐号码
|
||||||
|
- 支持复制所有号码
|
||||||
|
|
||||||
|
#### 推荐历史
|
||||||
|
- 查看历史推荐记录
|
||||||
|
- 显示中奖情况
|
||||||
|
- 支持手动检查中奖
|
||||||
|
|
||||||
### 高级分析功能 ⭐
|
### 高级分析功能 ⭐
|
||||||
1. 进入"高级分析"页面
|
1. 进入"高级分析"页面
|
||||||
@ -199,115 +271,92 @@ python schedule_update.py
|
|||||||
- **遗漏值分析**: 查看各号码的遗漏期数
|
- **遗漏值分析**: 查看各号码的遗漏期数
|
||||||
- **和值分析**: 分析红球和值的分布规律
|
- **和值分析**: 分析红球和值的分布规律
|
||||||
- **AC值分析**: 邻号差值分析
|
- **AC值分析**: 邻号差值分析
|
||||||
- **质合比分析**: 质数与合数比例
|
- **质合比分析**: 质数与合数的比例分析
|
||||||
- **012路分析**: 除3余数分布
|
- **012路分析**: 除3余数分析
|
||||||
- **跨度分析**: 号码跨度统计
|
- **跨度分析**: 最大最小号码差值分析
|
||||||
- **综合分析**: 多维度整合分析
|
- **综合分析**: 多维度数据整合分析
|
||||||
4. 设置分析期数(10-500期)
|
|
||||||
5. 点击"分析"按钮查看结果
|
|
||||||
|
|
||||||
### 智能预测功能 ⭐
|
### 智能预测功能 ⭐
|
||||||
1. 进入"智能预测"页面
|
1. 进入"智能预测"页面
|
||||||
2. 选择彩票类型
|
2. 选择彩票类型
|
||||||
3. 设置训练期数(建议100-500期)
|
3. 选择预测方法:
|
||||||
4. 点击"训练模型"按钮
|
- **机器学习预测**: 基于历史数据的AI预测
|
||||||
5. 训练完成后,可选择以下预测方法:
|
|
||||||
- **机器学习预测**: 基于AI算法的预测
|
|
||||||
- **模式预测**: 基于统计模式的预测
|
- **模式预测**: 基于统计模式的预测
|
||||||
- **集成预测**: 多方法综合预测
|
- **集成预测**: 多方法综合预测
|
||||||
6. 查看预测结果和置信度
|
4. 设置训练参数
|
||||||
|
5. 查看预测结果
|
||||||
|
|
||||||
### 数据查询
|
## API文档
|
||||||
1. 在查询表单中输入查询条件
|
启动后端服务后,访问 http://localhost:8000/docs 查看完整的API文档。
|
||||||
2. 点击"查询"按钮
|
|
||||||
3. 查看查询结果
|
|
||||||
|
|
||||||
### 统计分析
|
|
||||||
1. 进入统计分析页面
|
|
||||||
2. 选择要分析的彩票类型
|
|
||||||
3. 查看统计图表
|
|
||||||
|
|
||||||
### 智能选号
|
|
||||||
1. 进入智能选号页面
|
|
||||||
2. 选择彩票类型和选号策略
|
|
||||||
3. 设置生成注数
|
|
||||||
4. 点击"生成号码"按钮
|
|
||||||
|
|
||||||
## API 文档
|
|
||||||
启动后端服务后,访问以下地址查看 API 文档:
|
|
||||||
- Swagger UI: http://localhost:8000/docs
|
|
||||||
- ReDoc: http://localhost:8000/redoc
|
|
||||||
|
|
||||||
### 新增API端点 ⭐
|
|
||||||
|
|
||||||
#### 高级分析API
|
|
||||||
- `GET /api/v1/advanced-analysis/missing-value/{lottery_type}` - 遗漏值分析
|
|
||||||
- `GET /api/v1/advanced-analysis/sum-value/{lottery_type}` - 和值分析
|
|
||||||
- `GET /api/v1/advanced-analysis/ac-value/{lottery_type}` - AC值分析
|
|
||||||
- `GET /api/v1/advanced-analysis/prime-composite/{lottery_type}` - 质合比分析
|
|
||||||
- `GET /api/v1/advanced-analysis/road-012/{lottery_type}` - 012路分析
|
|
||||||
- `GET /api/v1/advanced-analysis/span/{lottery_type}` - 跨度分析
|
|
||||||
- `GET /api/v1/advanced-analysis/comprehensive/{lottery_type}` - 综合分析
|
|
||||||
|
|
||||||
#### 预测API
|
|
||||||
- `POST /api/v1/prediction/train/{lottery_type}` - 训练预测模型
|
|
||||||
- `GET /api/v1/prediction/predict/{lottery_type}` - 机器学习预测
|
|
||||||
- `GET /api/v1/prediction/pattern/{lottery_type}` - 模式预测
|
|
||||||
- `GET /api/v1/prediction/ensemble/{lottery_type}` - 集成预测
|
|
||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
1. 数据库连接失败
|
|
||||||
- 检查数据库服务是否启动
|
|
||||||
- 验证数据库连接配置是否正确
|
|
||||||
|
|
||||||
2. 前端无法连接后端
|
### 定时任务相关
|
||||||
- 确认后端服务是否正常运行
|
**Q: 定时任务没有执行?**
|
||||||
- 检查前端环境配置中的 API 地址是否正确
|
A: 检查以下几点:
|
||||||
|
1. 确保定时任务进程正在运行
|
||||||
|
2. 检查日志文件 `backend/lottery_scheduler.log`
|
||||||
|
3. 确认系统时间正确
|
||||||
|
4. 检查数据库连接是否正常
|
||||||
|
|
||||||
3. 数据导入失败
|
**Q: 如何修改定时任务时间?**
|
||||||
- 检查 JSON 文件格式是否正确
|
A: 编辑 `backend/scheduler.py` 文件中的时间设置:
|
||||||
- 确认数据库表结构是否完整
|
```python
|
||||||
|
schedule.every().day.at("06:00").do(self.update_lottery_data_job)
|
||||||
|
schedule.every().day.at("17:00").do(self.generate_daily_recommendations_job)
|
||||||
|
```
|
||||||
|
|
||||||
4. 机器学习预测失败
|
**Q: 如何查看任务执行日志?**
|
||||||
- 确保历史数据充足(建议至少100期)
|
A: 查看日志文件:
|
||||||
- 检查训练参数设置是否合理
|
```bash
|
||||||
|
tail -f backend/lottery_scheduler.log
|
||||||
|
```
|
||||||
|
|
||||||
## 开发计划
|
### 数据更新相关
|
||||||
- [x] 添加高级数据分析功能
|
**Q: 数据更新失败?**
|
||||||
- [x] 实现机器学习预测系统
|
A: 检查以下几点:
|
||||||
- [x] 优化数据可视化展示
|
1. 网络连接是否正常
|
||||||
- [ ] 添加用户认证功能
|
2. API密钥是否有效
|
||||||
- [ ] 实现数据备份和恢复
|
3. 数据库连接是否正常
|
||||||
- [ ] 优化数据导入性能
|
4. 查看后端日志获取详细错误信息
|
||||||
- [ ] 添加更多统计分析功能
|
|
||||||
- [ ] 实现自定义选号策略
|
|
||||||
- [ ] 添加移动端适配
|
|
||||||
- [ ] 实现数据导出功能增强
|
|
||||||
|
|
||||||
## 贡献指南
|
**Q: 如何手动更新数据?**
|
||||||
1. Fork 项目
|
A: 可以通过以下方式:
|
||||||
2. 创建特性分支
|
1. 前端页面点击更新按钮
|
||||||
3. 提交更改
|
2. 调用API接口
|
||||||
4. 推送到分支
|
3. 运行更新脚本:`python update_lottery.py`
|
||||||
5. 创建 Pull Request
|
|
||||||
|
|
||||||
## 许可证
|
### 拼盘推荐相关
|
||||||
MIT License
|
**Q: 今日推荐没有生成?**
|
||||||
|
A: 检查以下几点:
|
||||||
|
1. 定时任务是否正常运行
|
||||||
|
2. 是否有足够的历史数据
|
||||||
|
3. 预测模型是否训练完成
|
||||||
|
4. 查看日志文件获取错误信息
|
||||||
|
|
||||||
|
**Q: 如何手动生成推荐?**
|
||||||
|
A: 在一键下单页面点击"来一份拼盘"按钮即可手动生成。
|
||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
### v2.0.0 (2024-01-XX)
|
### v1.1.0 (2024-01-XX)
|
||||||
- ✨ 新增高级数据分析功能
|
- ✨ 新增定时任务系统
|
||||||
- ✨ 新增机器学习预测系统
|
- ✨ 新增每日拼盘推荐功能
|
||||||
- ✨ 新增遗漏值、和值、AC值等分析
|
- ✨ 新增任务状态监控
|
||||||
- ✨ 新增质合比、012路、跨度分析
|
- ✨ 优化一键下单页面
|
||||||
- ✨ 优化数据可视化展示
|
- 🐛 修复图表显示问题
|
||||||
- 🔧 更新依赖包版本
|
- 📝 更新使用说明
|
||||||
- 📝 完善API文档
|
|
||||||
|
|
||||||
### v1.0.0 (2024-01-XX)
|
### v1.0.0 (2024-01-XX)
|
||||||
- 🎉 初始版本发布
|
- 🎉 初始版本发布
|
||||||
- ✨ 基础数据管理功能
|
- ✨ 基础数据管理功能
|
||||||
- ✨ 基础统计分析
|
- ✨ 统计分析功能
|
||||||
- ✨ 智能选号功能
|
- ✨ 高级分析功能
|
||||||
- ✨ 前后端分离架构
|
- ✨ 智能预测功能
|
||||||
|
- ✨ 前端可视化界面
|
||||||
|
|
||||||
|
## 贡献指南
|
||||||
|
欢迎提交Issue和Pull Request来改进这个项目。
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
MIT License
|
||||||
@ -212,3 +212,59 @@ def recommend_today(db: Session = Depends(get_db)):
|
|||||||
'batch_id': batch_id,
|
'batch_id': batch_id,
|
||||||
'recommend': results
|
'recommend': results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/recommend/today")
|
||||||
|
def get_today_recommendations(db: Session = Depends(get_db)):
|
||||||
|
"""获取今日拼盘推荐"""
|
||||||
|
try:
|
||||||
|
today = datetime.datetime.now().strftime('%Y%m%d')
|
||||||
|
|
||||||
|
# 查询今日的双色球推荐
|
||||||
|
ssq_recommendations = db.query(SSQLotteryBetRecord).filter(
|
||||||
|
SSQLotteryBetRecord.batch_id.like(f'SSQ_{today}%')
|
||||||
|
).order_by(SSQLotteryBetRecord.created_at.desc()).all()
|
||||||
|
|
||||||
|
# 查询今日的大乐透推荐
|
||||||
|
dlt_recommendations = db.query(DLTLotteryBetRecord).filter(
|
||||||
|
DLTLotteryBetRecord.batch_id.like(f'DLT_{today}%')
|
||||||
|
).order_by(DLTLotteryBetRecord.created_at.desc()).all()
|
||||||
|
|
||||||
|
# 确定当前彩票类型(根据推荐数量)
|
||||||
|
if len(ssq_recommendations) > len(dlt_recommendations):
|
||||||
|
current_lottery_type = 'ssq'
|
||||||
|
today_recommendations = ssq_recommendations
|
||||||
|
else:
|
||||||
|
current_lottery_type = 'dlt'
|
||||||
|
today_recommendations = dlt_recommendations
|
||||||
|
|
||||||
|
# 格式化推荐数据
|
||||||
|
formatted_recommendations = []
|
||||||
|
for rec in today_recommendations:
|
||||||
|
numbers_parts = rec.numbers.split('|')
|
||||||
|
red_numbers = [int(n) for n in numbers_parts[0].split(
|
||||||
|
',')] if numbers_parts[0] else []
|
||||||
|
blue_numbers = [int(n) for n in numbers_parts[1].split(',')] if len(
|
||||||
|
numbers_parts) > 1 and numbers_parts[1] else []
|
||||||
|
|
||||||
|
formatted_recommendations.append({
|
||||||
|
'id': rec.id,
|
||||||
|
'batch_id': rec.batch_id,
|
||||||
|
'recommend_type': rec.recommend_type,
|
||||||
|
'numbers': rec.numbers,
|
||||||
|
'redNumbers': red_numbers,
|
||||||
|
'blueNumbers': blue_numbers,
|
||||||
|
'created_at': rec.created_at,
|
||||||
|
'is_winner': rec.is_winner,
|
||||||
|
'win_amount': rec.win_amount
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'lottery_type': current_lottery_type,
|
||||||
|
'recommend': formatted_recommendations,
|
||||||
|
'count': len(formatted_recommendations)
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"获取今日推荐失败: {str(e)}")
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from sklearn.model_selection import train_test_split
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from ..models.lottery import SSQLottery, DLTLottery
|
from ..models.lottery import SSQLottery, DLTLottery
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class PredictionService:
|
class PredictionService:
|
||||||
@ -545,3 +546,87 @@ class PredictionService:
|
|||||||
"pattern_analysis": pattern_result.get('suggested_criteria', {}) if pattern_result else {},
|
"pattern_analysis": pattern_result.get('suggested_criteria', {}) if pattern_result else {},
|
||||||
"frequency_analysis": freq_result or {}
|
"frequency_analysis": freq_result or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def generate_daily_recommendations(self, db: Session, lottery_type: str, batch_size: int = 4) -> List[Dict]:
|
||||||
|
"""生成每日拼盘推荐(用于定时任务)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db: 数据库会话
|
||||||
|
lottery_type: 彩票类型 ('ssq' 或 'dlt')
|
||||||
|
batch_size: 生成推荐数量
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Dict]: 推荐列表
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 创建预测服务实例
|
||||||
|
prediction_service = PredictionService(db)
|
||||||
|
|
||||||
|
# 获取集成预测
|
||||||
|
ensemble_result = prediction_service.get_ensemble_prediction(
|
||||||
|
lottery_type, periods=100)
|
||||||
|
|
||||||
|
if not ensemble_result.get('success'):
|
||||||
|
return []
|
||||||
|
|
||||||
|
recommendations = ensemble_result.get('recommendations', [])
|
||||||
|
|
||||||
|
# 生成拼盘推荐
|
||||||
|
daily_recommendations = []
|
||||||
|
batch_id = f"{lottery_type.upper()}_{datetime.now().strftime('%Y%m%d')}"
|
||||||
|
|
||||||
|
for i, rec in enumerate(recommendations[:batch_size]):
|
||||||
|
# 格式化号码
|
||||||
|
if lottery_type == 'ssq':
|
||||||
|
red_numbers = rec['numbers']
|
||||||
|
blue_numbers = [rec['blue']] if rec['blue'] else []
|
||||||
|
numbers_str = f"{','.join(map(str, red_numbers))}|{','.join(map(str, blue_numbers))}"
|
||||||
|
else:
|
||||||
|
red_numbers = rec['numbers']
|
||||||
|
blue_numbers = rec.get('blues', [])
|
||||||
|
numbers_str = f"{','.join(map(str, red_numbers))}|{','.join(map(str, blue_numbers))}"
|
||||||
|
|
||||||
|
# 创建推荐记录
|
||||||
|
recommendation = {
|
||||||
|
'lottery_type': lottery_type,
|
||||||
|
'batch_id': batch_id,
|
||||||
|
'recommend_type': rec['method'],
|
||||||
|
'numbers': numbers_str,
|
||||||
|
'red_numbers': red_numbers,
|
||||||
|
'blue_numbers': blue_numbers,
|
||||||
|
'confidence': rec['confidence'],
|
||||||
|
'created_at': datetime.now(),
|
||||||
|
'is_winner': False,
|
||||||
|
'win_amount': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
daily_recommendations.append(recommendation)
|
||||||
|
|
||||||
|
# 保存到数据库
|
||||||
|
from ..models.lottery import SSQLotteryBetRecord, DLTLotteryBetRecord
|
||||||
|
|
||||||
|
if lottery_type == 'ssq':
|
||||||
|
BetRecord = SSQLotteryBetRecord
|
||||||
|
else:
|
||||||
|
BetRecord = DLTLotteryBetRecord
|
||||||
|
|
||||||
|
# 保存推荐记录
|
||||||
|
for rec in daily_recommendations:
|
||||||
|
bet_record = BetRecord(
|
||||||
|
lottery_type=rec['lottery_type'],
|
||||||
|
batch_id=rec['batch_id'],
|
||||||
|
recommend_type=rec['recommend_type'],
|
||||||
|
numbers=rec['numbers'],
|
||||||
|
created_at=rec['created_at'],
|
||||||
|
is_winner=rec['is_winner'],
|
||||||
|
win_amount=rec['win_amount']
|
||||||
|
)
|
||||||
|
db.add(bet_record)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return daily_recommendations
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db.rollback()
|
||||||
|
raise Exception(f"生成每日推荐失败: {str(e)}")
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from app.api.endpoints import analysis
|
from app.api.endpoints import analysis, lottery, prediction
|
||||||
|
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="彩票数据分析系统",
|
title="彩票数据分析系统",
|
||||||
@ -19,8 +19,16 @@ app.add_middleware(
|
|||||||
|
|
||||||
# 注册路由
|
# 注册路由
|
||||||
app.include_router(analysis.router, prefix="/api/analysis", tags=["analysis"])
|
app.include_router(analysis.router, prefix="/api/analysis", tags=["analysis"])
|
||||||
|
app.include_router(lottery.router, prefix="/api/v1/lottery", tags=["lottery"])
|
||||||
|
app.include_router(prediction.router,
|
||||||
|
prefix="/api/v1/prediction", tags=["prediction"])
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
def read_root():
|
def read_root():
|
||||||
return {"message": "欢迎使用彩票数据分析系统"}
|
return {"message": "欢迎使用彩票数据分析系统"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health_check():
|
||||||
|
return {"status": "healthy", "message": "系统运行正常"}
|
||||||
|
|||||||
113
backend/scheduler.py
Normal file
113
backend/scheduler.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import schedule
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from update_lottery import LotteryUpdater
|
||||||
|
from app.services.prediction_service import PredictionService
|
||||||
|
from app.core.database import SessionLocal
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||||
|
filename='lottery_scheduler.log'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class LotteryScheduler:
|
||||||
|
def __init__(self):
|
||||||
|
self.updater = LotteryUpdater()
|
||||||
|
|
||||||
|
def update_lottery_data_job(self):
|
||||||
|
"""每天早上6点更新开奖数据任务"""
|
||||||
|
try:
|
||||||
|
logger.info("开始执行早上6点更新开奖数据任务...")
|
||||||
|
|
||||||
|
# 更新双色球数据
|
||||||
|
logger.info("开始更新双色球数据...")
|
||||||
|
ssq_result = self.updater.update_lottery_data('ssq')
|
||||||
|
logger.info(f"双色球数据更新完成: {ssq_result}")
|
||||||
|
|
||||||
|
# 更新大乐透数据
|
||||||
|
logger.info("开始更新大乐透数据...")
|
||||||
|
dlt_result = self.updater.update_lottery_data('dlt')
|
||||||
|
logger.info(f"大乐透数据更新完成: {dlt_result}")
|
||||||
|
|
||||||
|
# 检查中奖情况
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
logger.info("开始检查双色球中奖情况...")
|
||||||
|
self.updater.check_and_update_bet_wins('ssq', db)
|
||||||
|
logger.info("双色球中奖检查完成")
|
||||||
|
|
||||||
|
logger.info("开始检查大乐透中奖情况...")
|
||||||
|
self.updater.check_and_update_bet_wins('dlt', db)
|
||||||
|
logger.info("大乐透中奖检查完成")
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
logger.info("早上6点更新开奖数据任务完成")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"早上6点更新开奖数据任务失败: {str(e)}")
|
||||||
|
|
||||||
|
def generate_daily_recommendations_job(self):
|
||||||
|
"""每天下午5点生成拼盘推荐任务"""
|
||||||
|
try:
|
||||||
|
logger.info("开始执行下午5点生成拼盘推荐任务...")
|
||||||
|
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
# 创建预测服务实例
|
||||||
|
prediction_service = PredictionService(db)
|
||||||
|
|
||||||
|
# 生成双色球推荐
|
||||||
|
logger.info("开始生成双色球拼盘推荐...")
|
||||||
|
ssq_recommendations = prediction_service.generate_daily_recommendations(
|
||||||
|
db, 'ssq', batch_size=4
|
||||||
|
)
|
||||||
|
logger.info(f"双色球拼盘推荐生成完成,共生成 {len(ssq_recommendations)} 注")
|
||||||
|
|
||||||
|
# 生成大乐透推荐
|
||||||
|
logger.info("开始生成大乐透拼盘推荐...")
|
||||||
|
dlt_recommendations = prediction_service.generate_daily_recommendations(
|
||||||
|
db, 'dlt', batch_size=4
|
||||||
|
)
|
||||||
|
logger.info(f"大乐透拼盘推荐生成完成,共生成 {len(dlt_recommendations)} 注")
|
||||||
|
|
||||||
|
logger.info("下午5点生成拼盘推荐任务完成")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"下午5点生成拼盘推荐任务失败: {str(e)}")
|
||||||
|
|
||||||
|
def start_scheduler(self):
|
||||||
|
"""启动定时任务调度器"""
|
||||||
|
# 每天早上6点更新开奖数据
|
||||||
|
schedule.every().day.at("06:00").do(self.update_lottery_data_job)
|
||||||
|
|
||||||
|
# 每天下午5点生成拼盘推荐
|
||||||
|
schedule.every().day.at("17:00").do(self.generate_daily_recommendations_job)
|
||||||
|
|
||||||
|
logger.info("定时任务调度器已启动")
|
||||||
|
logger.info("已设置任务:")
|
||||||
|
logger.info("- 每天早上6点: 更新开奖数据")
|
||||||
|
logger.info("- 每天下午5点: 生成拼盘推荐")
|
||||||
|
|
||||||
|
# 运行调度器
|
||||||
|
while True:
|
||||||
|
schedule.run_pending()
|
||||||
|
time.sleep(60) # 每分钟检查一次
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
scheduler = LotteryScheduler()
|
||||||
|
scheduler.start_scheduler()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -43,3 +43,11 @@ export function recommendToday() {
|
|||||||
method: 'post'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取今日拼盘推荐
|
||||||
|
export function getTodayRecommendations() {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/prediction/recommend/today',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -5,6 +5,43 @@
|
|||||||
<p class="subtitle">今日拼盘新鲜出锅,懒人专属,AI大厨为你配号!</p>
|
<p class="subtitle">今日拼盘新鲜出锅,懒人专属,AI大厨为你配号!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 定时任务状态区域 -->
|
||||||
|
<div class="scheduler-status-section">
|
||||||
|
<div class="status-card">
|
||||||
|
<div class="status-header">
|
||||||
|
<h3>定时任务状态</h3>
|
||||||
|
<el-button type="primary" size="small" @click="updateSchedulerStatus">刷新状态</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="status-content">
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">数据更新任务:</span>
|
||||||
|
<span class="status-value">
|
||||||
|
<el-tag type="success" size="small">每天早上6点</el-tag>
|
||||||
|
</span>
|
||||||
|
<span class="status-time">
|
||||||
|
下次更新:{{ schedulerStatus.nextUpdate ? new Date(schedulerStatus.nextUpdate).toLocaleString() : '未知' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">拼盘推荐任务:</span>
|
||||||
|
<span class="status-value">
|
||||||
|
<el-tag type="warning" size="small">每天下午5点</el-tag>
|
||||||
|
</span>
|
||||||
|
<span class="status-time">
|
||||||
|
下次推荐:{{ schedulerStatus.nextRecommend ? new Date(schedulerStatus.nextRecommend).toLocaleString() : '未知' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">今日推荐状态:</span>
|
||||||
|
<span class="status-value">
|
||||||
|
<el-tag v-if="todayRecommend.length > 0" type="success" size="small">已生成 {{ todayRecommend.length }} 注</el-tag>
|
||||||
|
<el-tag v-else type="info" size="small">等待生成</el-tag>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 一键下单区域 -->
|
<!-- 一键下单区域 -->
|
||||||
<div class="quick-order-section">
|
<div class="quick-order-section">
|
||||||
<div class="order-card">
|
<div class="order-card">
|
||||||
@ -127,7 +164,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { recommendToday } from '@/api/prediction'
|
import { recommendToday, getTodayRecommendations } from '@/api/prediction'
|
||||||
import { lotteryApi } from '@/api/lottery'
|
import { lotteryApi } from '@/api/lottery'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -140,7 +177,11 @@ export default {
|
|||||||
todayRecommend: [],
|
todayRecommend: [],
|
||||||
ssqHistory: [],
|
ssqHistory: [],
|
||||||
dltHistory: [],
|
dltHistory: [],
|
||||||
checkingWin: false
|
checkingWin: false,
|
||||||
|
schedulerStatus: {
|
||||||
|
nextUpdate: null,
|
||||||
|
nextRecommend: null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -161,9 +202,56 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.loadHistory()
|
this.loadHistory()
|
||||||
|
this.loadTodayRecommendations()
|
||||||
this.setActiveTabByDay()
|
this.setActiveTabByDay()
|
||||||
|
this.updateSchedulerStatus()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getNext6am() {
|
||||||
|
const now = new Date()
|
||||||
|
const today6am = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 6, 0, 0)
|
||||||
|
if (now < today6am) {
|
||||||
|
return today6am
|
||||||
|
} else {
|
||||||
|
// 明天早上6点
|
||||||
|
return new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 6, 0, 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getNext5pm() {
|
||||||
|
const now = new Date()
|
||||||
|
const today5pm = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 17, 0, 0)
|
||||||
|
if (now < today5pm) {
|
||||||
|
return today5pm
|
||||||
|
} else {
|
||||||
|
// 明天下午5点
|
||||||
|
return new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 17, 0, 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateSchedulerStatus() {
|
||||||
|
this.schedulerStatus = {
|
||||||
|
nextUpdate: this.getNext6am(),
|
||||||
|
nextRecommend: this.getNext5pm(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadTodayRecommendations() {
|
||||||
|
try {
|
||||||
|
const response = await getTodayRecommendations()
|
||||||
|
if (response.data && response.data.success) {
|
||||||
|
this.currentLotteryType = response.data.lottery_type
|
||||||
|
this.todayRecommend = response.data.recommend.map(item => {
|
||||||
|
const { redNumbers, blueNumbers } = this.parseNumbers(item.numbers)
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
redNumbers,
|
||||||
|
blueNumbers,
|
||||||
|
time: new Date(item.created_at).toLocaleString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载今日推荐失败:', error)
|
||||||
|
}
|
||||||
|
},
|
||||||
async generateNumbers() {
|
async generateNumbers() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
try {
|
try {
|
||||||
@ -308,6 +396,55 @@ export default {
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scheduler-status-section {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);
|
||||||
|
padding: 36px 36px 28px 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
border-bottom: 2px solid #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-header h3 {
|
||||||
|
color: #2c3e50;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-content {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item .status-label {
|
||||||
|
color: #7f8c8d;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item .status-value {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item .status-time {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
.quick-order-section {
|
.quick-order-section {
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ def check_dependencies():
|
|||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
import pandas
|
import pandas
|
||||||
import requests
|
import requests
|
||||||
|
import schedule
|
||||||
print("✅ 后端依赖检查通过")
|
print("✅ 后端依赖检查通过")
|
||||||
return True
|
return True
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
@ -37,6 +38,51 @@ def check_dependencies():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def start_scheduler():
|
||||||
|
"""启动定时任务调度器"""
|
||||||
|
print("\n⏰ 启动定时任务调度器...")
|
||||||
|
|
||||||
|
backend_dir = Path("backend")
|
||||||
|
if not backend_dir.exists():
|
||||||
|
print("❌ 错误: 找不到backend目录")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 切换到backend目录
|
||||||
|
os.chdir(backend_dir)
|
||||||
|
|
||||||
|
# 启动定时任务调度器
|
||||||
|
print("📝 启动命令: python scheduler.py")
|
||||||
|
process = subprocess.Popen([
|
||||||
|
sys.executable, "scheduler.py"
|
||||||
|
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
|
||||||
|
# 等待调度器启动
|
||||||
|
print("⏳ 等待定时任务调度器启动...")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
# 检查进程是否还在运行
|
||||||
|
if process.poll() is None:
|
||||||
|
print("✅ 定时任务调度器启动成功")
|
||||||
|
print("📅 定时任务设置:")
|
||||||
|
print(" - 每天早上6点: 更新开奖数据")
|
||||||
|
print(" - 每天下午5点: 生成拼盘推荐")
|
||||||
|
return process
|
||||||
|
else:
|
||||||
|
print("❌ 定时任务调度器启动失败")
|
||||||
|
# 检查进程输出
|
||||||
|
stdout, stderr = process.communicate(timeout=1)
|
||||||
|
if stderr:
|
||||||
|
print(f"错误输出: {stderr}")
|
||||||
|
if stdout:
|
||||||
|
print(f"标准输出: {stdout}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 启动定时任务调度器时出错: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def start_backend():
|
def start_backend():
|
||||||
"""启动后端服务"""
|
"""启动后端服务"""
|
||||||
print("\n🚀 启动后端服务...")
|
print("\n🚀 启动后端服务...")
|
||||||
@ -255,6 +301,13 @@ def main():
|
|||||||
print("❌ 用户取消启动")
|
print("❌ 用户取消启动")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 询问是否启动定时任务
|
||||||
|
print("\n⏰ 定时任务选项:")
|
||||||
|
print("1. 启动定时任务(推荐)")
|
||||||
|
print("2. 不启动定时任务")
|
||||||
|
scheduler_choice = input("请选择 (1/2): ").strip()
|
||||||
|
start_scheduler_task = scheduler_choice == "1"
|
||||||
|
|
||||||
# 保存当前目录
|
# 保存当前目录
|
||||||
original_dir = os.getcwd()
|
original_dir = os.getcwd()
|
||||||
|
|
||||||
@ -270,10 +323,20 @@ def main():
|
|||||||
print("\n请检查后端日志获取详细错误信息")
|
print("\n请检查后端日志获取详细错误信息")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 启动定时任务(如果选择)
|
||||||
|
scheduler_process = None
|
||||||
|
if start_scheduler_task:
|
||||||
|
scheduler_process = start_scheduler()
|
||||||
|
if not scheduler_process:
|
||||||
|
print("⚠️ 定时任务启动失败,但系统将继续运行")
|
||||||
|
print("💡 您可以稍后手动启动定时任务: cd backend && python scheduler.py")
|
||||||
|
|
||||||
# 启动前端
|
# 启动前端
|
||||||
frontend_process = start_frontend(original_dir)
|
frontend_process = start_frontend(original_dir)
|
||||||
if not frontend_process:
|
if not frontend_process:
|
||||||
backend_process.terminate()
|
backend_process.terminate()
|
||||||
|
if scheduler_process:
|
||||||
|
scheduler_process.terminate()
|
||||||
print("\n💡 前端启动失败,可能的原因:")
|
print("\n💡 前端启动失败,可能的原因:")
|
||||||
print("1. Node.js未安装或版本过低")
|
print("1. Node.js未安装或版本过低")
|
||||||
print("2. 端口5173被占用")
|
print("2. 端口5173被占用")
|
||||||
@ -286,11 +349,18 @@ def main():
|
|||||||
print("📊 后端API: http://localhost:8000")
|
print("📊 后端API: http://localhost:8000")
|
||||||
print("📊 API文档: http://localhost:8000/docs")
|
print("📊 API文档: http://localhost:8000/docs")
|
||||||
print("🌐 前端界面: http://localhost:5173")
|
print("🌐 前端界面: http://localhost:5173")
|
||||||
|
if scheduler_process:
|
||||||
|
print("⏰ 定时任务: 已启动")
|
||||||
|
print(" - 每天早上6点: 更新开奖数据")
|
||||||
|
print(" - 每天下午5点: 生成拼盘推荐")
|
||||||
|
else:
|
||||||
|
print("⏰ 定时任务: 未启动")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("💡 使用说明:")
|
print("💡 使用说明:")
|
||||||
print("1. 打开浏览器访问 http://localhost:5173")
|
print("1. 打开浏览器访问 http://localhost:5173")
|
||||||
print("2. 在首页点击'更新数据'按钮获取最新开奖信息")
|
print("2. 在首页点击'补全场早点'按钮获取最新开奖信息")
|
||||||
print("3. 使用各种分析功能进行数据分析")
|
print("3. 在一键下单页面查看今日拼盘推荐")
|
||||||
|
print("4. 使用各种分析功能进行数据分析")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("按 Ctrl+C 停止服务")
|
print("按 Ctrl+C 停止服务")
|
||||||
|
|
||||||
@ -302,6 +372,8 @@ def main():
|
|||||||
print("\n🛑 正在停止服务...")
|
print("\n🛑 正在停止服务...")
|
||||||
backend_process.terminate()
|
backend_process.terminate()
|
||||||
frontend_process.terminate()
|
frontend_process.terminate()
|
||||||
|
if scheduler_process:
|
||||||
|
scheduler_process.terminate()
|
||||||
print("✅ 服务已停止")
|
print("✅ 服务已停止")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
170
定时任务使用指南.md
Normal file
170
定时任务使用指南.md
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# 定时任务使用指南
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
彩票数据分析系统新增了定时任务功能,可以自动执行数据更新和拼盘推荐生成任务。
|
||||||
|
|
||||||
|
## 定时任务说明
|
||||||
|
|
||||||
|
### 1. 数据更新任务
|
||||||
|
- **执行时间**: 每天早上6点
|
||||||
|
- **功能**: 自动从API获取最新开奖数据
|
||||||
|
- **更新内容**:
|
||||||
|
- 双色球最新开奖数据
|
||||||
|
- 大乐透最新开奖数据
|
||||||
|
- 检查历史投注的中奖情况
|
||||||
|
- **日志文件**: `backend/lottery_scheduler.log`
|
||||||
|
|
||||||
|
### 2. 拼盘推荐任务
|
||||||
|
- **执行时间**: 每天下午5点
|
||||||
|
- **功能**: 自动生成今日拼盘推荐
|
||||||
|
- **生成内容**:
|
||||||
|
- 使用集成预测算法
|
||||||
|
- 生成4注推荐号码
|
||||||
|
- 保存到数据库供前端显示
|
||||||
|
- **日志文件**: `backend/lottery_scheduler.log`
|
||||||
|
|
||||||
|
## 启动方式
|
||||||
|
|
||||||
|
### 方式一:一键启动(推荐)
|
||||||
|
```bash
|
||||||
|
python start_system.py
|
||||||
|
```
|
||||||
|
启动时会询问是否启动定时任务,选择"1"即可。
|
||||||
|
|
||||||
|
### 方式二:手动启动
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python scheduler.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式三:后台运行
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
nohup python scheduler.py > scheduler.log 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
## 查看任务状态
|
||||||
|
|
||||||
|
### 1. 前端查看
|
||||||
|
- 打开一键下单页面
|
||||||
|
- 查看"定时任务状态"区域
|
||||||
|
- 显示下次执行时间和今日推荐状态
|
||||||
|
|
||||||
|
### 2. 日志查看
|
||||||
|
```bash
|
||||||
|
# 实时查看日志
|
||||||
|
tail -f backend/lottery_scheduler.log
|
||||||
|
|
||||||
|
# 查看最近100行日志
|
||||||
|
tail -n 100 backend/lottery_scheduler.log
|
||||||
|
|
||||||
|
# 搜索特定任务的日志
|
||||||
|
grep "早上6点" backend/lottery_scheduler.log
|
||||||
|
grep "下午5点" backend/lottery_scheduler.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 进程查看
|
||||||
|
```bash
|
||||||
|
# 查看定时任务进程
|
||||||
|
ps aux | grep scheduler.py
|
||||||
|
|
||||||
|
# 查看进程ID
|
||||||
|
pgrep -f scheduler.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q1: 定时任务没有执行?
|
||||||
|
**A**: 检查以下几点:
|
||||||
|
1. 确保定时任务进程正在运行
|
||||||
|
2. 检查日志文件是否有错误信息
|
||||||
|
3. 确认系统时间正确
|
||||||
|
4. 检查数据库连接是否正常
|
||||||
|
|
||||||
|
### Q2: 如何修改定时任务时间?
|
||||||
|
**A**: 编辑 `backend/scheduler.py` 文件中的时间设置:
|
||||||
|
```python
|
||||||
|
# 修改为其他时间
|
||||||
|
schedule.every().day.at("07:00").do(self.update_lottery_data_job) # 改为早上7点
|
||||||
|
schedule.every().day.at("18:00").do(self.generate_daily_recommendations_job) # 改为下午6点
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q3: 如何停止定时任务?
|
||||||
|
**A**:
|
||||||
|
1. 找到进程ID:`pgrep -f scheduler.py`
|
||||||
|
2. 停止进程:`kill <进程ID>`
|
||||||
|
3. 或者使用Ctrl+C停止(如果在前台运行)
|
||||||
|
|
||||||
|
### Q4: 今日推荐没有生成?
|
||||||
|
**A**: 检查以下几点:
|
||||||
|
1. 定时任务是否正常运行
|
||||||
|
2. 是否有足够的历史数据(建议至少100期)
|
||||||
|
3. 预测模型是否训练完成
|
||||||
|
4. 查看日志文件获取错误信息
|
||||||
|
|
||||||
|
### Q5: 如何手动执行任务?
|
||||||
|
**A**:
|
||||||
|
1. **手动更新数据**:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python update_lottery.py
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **手动生成推荐**:
|
||||||
|
- 在前端一键下单页面点击"来一份拼盘"按钮
|
||||||
|
- 或者调用API接口
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 日志配置
|
||||||
|
日志文件位置:`backend/lottery_scheduler.log`
|
||||||
|
日志级别:INFO
|
||||||
|
日志格式:时间 - 级别 - 消息
|
||||||
|
|
||||||
|
### 数据库配置
|
||||||
|
确保数据库连接正常,定时任务需要访问数据库进行数据更新和推荐生成。
|
||||||
|
|
||||||
|
### API配置
|
||||||
|
定时任务使用聚合数据API获取开奖数据,确保API密钥有效。
|
||||||
|
|
||||||
|
## 监控建议
|
||||||
|
|
||||||
|
### 1. 定期检查日志
|
||||||
|
建议每天检查一次日志文件,确保任务正常执行。
|
||||||
|
|
||||||
|
### 2. 监控磁盘空间
|
||||||
|
日志文件会持续增长,建议定期清理或设置日志轮转。
|
||||||
|
|
||||||
|
### 3. 监控数据库
|
||||||
|
确保数据库有足够空间存储新数据。
|
||||||
|
|
||||||
|
### 4. 监控网络
|
||||||
|
确保服务器网络连接正常,能够访问外部API。
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 1. 任务执行失败
|
||||||
|
- 查看日志文件获取详细错误信息
|
||||||
|
- 检查数据库连接
|
||||||
|
- 检查网络连接
|
||||||
|
- 检查API密钥是否有效
|
||||||
|
|
||||||
|
### 2. 推荐生成失败
|
||||||
|
- 检查历史数据是否充足
|
||||||
|
- 检查预测模型是否正常
|
||||||
|
- 查看预测服务日志
|
||||||
|
|
||||||
|
### 3. 数据更新失败
|
||||||
|
- 检查API连接
|
||||||
|
- 检查API密钥
|
||||||
|
- 检查数据库权限
|
||||||
|
|
||||||
|
## 联系支持
|
||||||
|
如果遇到问题,请:
|
||||||
|
1. 查看日志文件获取错误信息
|
||||||
|
2. 检查常见问题部分
|
||||||
|
3. 提交Issue到项目仓库
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**注意**: 定时任务功能需要系统持续运行,建议在服务器环境下使用。
|
||||||
Loading…
x
Reference in New Issue
Block a user