fix: 修正定时任务状态下次更新时间的显示逻辑,分别精确到早上6点和下午5点
This commit is contained in:
parent
ff9d9a857e
commit
cb46b20d15
237
README.md
237
README.md
@ -13,6 +13,7 @@
|
||||
- Scikit-learn (机器学习)
|
||||
- NumPy (数值计算)
|
||||
- Pandas (数据处理)
|
||||
- Schedule (定时任务)
|
||||
|
||||
### 前端
|
||||
- Vue 3
|
||||
@ -30,6 +31,7 @@
|
||||
- 数据导出
|
||||
- 手动数据录入
|
||||
- **自动数据更新** ⭐ 新功能
|
||||
- **定时任务系统** ⭐ 新功能
|
||||
|
||||
### 2. 基础统计分析
|
||||
- 号码出现频率统计
|
||||
@ -52,6 +54,7 @@
|
||||
- **集成预测**: 多方法综合预测
|
||||
- **预测模型训练**: 可自定义训练参数
|
||||
- **预测结果评估**: 预测准确率统计
|
||||
- **每日拼盘推荐**: 定时生成推荐号码 ⭐ 新功能
|
||||
|
||||
### 5. 智能选号
|
||||
- 随机选号
|
||||
@ -60,6 +63,12 @@
|
||||
- 冷门号码选号
|
||||
- 自定义选号策略
|
||||
|
||||
### 6. 定时任务系统 ⭐ 新功能
|
||||
- **每天早上6点**: 自动更新开奖数据
|
||||
- **每天下午5点**: 自动生成拼盘推荐
|
||||
- **任务状态监控**: 实时查看任务执行状态
|
||||
- **日志记录**: 详细的任务执行日志
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
lottery/
|
||||
@ -76,7 +85,9 @@ lottery/
|
||||
│ │ ├── advanced_analysis.py # 高级分析服务 ⭐
|
||||
│ │ └── prediction_service.py # 预测服务 ⭐
|
||||
│ ├── requirements.txt # 依赖包
|
||||
│ └── main.py # 入口文件
|
||||
│ ├── main.py # 入口文件
|
||||
│ ├── scheduler.py # 定时任务调度器 ⭐
|
||||
│ └── update_lottery.py # 数据更新脚本
|
||||
├── frontend/ # 前端代码
|
||||
│ ├── src/
|
||||
│ │ ├── api/ # API 接口
|
||||
@ -85,6 +96,7 @@ lottery/
|
||||
│ │ ├── router/ # 路由配置
|
||||
│ │ ├── views/ # 页面
|
||||
│ │ │ ├── AdvancedAnalysis.vue # 高级分析页面 ⭐
|
||||
│ │ │ ├── NumberGenerator.vue # 一键下单页面 ⭐
|
||||
│ │ │ └── Prediction.vue # 预测页面 ⭐
|
||||
│ │ ├── App.vue # 根组件
|
||||
│ │ └── main.js # 入口文件
|
||||
@ -110,8 +122,11 @@ python start_system.py
|
||||
|
||||
脚本会自动:
|
||||
- 检查Python版本和依赖
|
||||
- 检查数据库连接
|
||||
- 询问是否启动定时任务
|
||||
- 启动后端服务(端口8000)
|
||||
- 启动前端服务(端口5173)
|
||||
- 启动定时任务调度器(可选)
|
||||
- 显示访问地址和使用说明
|
||||
|
||||
### 手动启动
|
||||
@ -156,8 +171,46 @@ npm run dev
|
||||
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 文件导入。
|
||||
|
||||
#### 数据自动/手动更新 ⭐ 新功能
|
||||
- **前端更新功能**: 在首页提供"更新双色球"、"更新大乐透"、"更新全部"三个按钮
|
||||
- **定时更新**: 每天早上6点自动更新(推荐)
|
||||
- **前端更新功能**: 在首页提供"补红蓝球煎饼"、"补大乐斗豆浆"、"补全场早点"三个按钮
|
||||
- **API更新接口**: 支持通过API接口更新数据
|
||||
- `POST /api/v1/lottery/update/ssq` - 更新双色球数据
|
||||
- `POST /api/v1/lottery/update/dlt` - 更新大乐透数据
|
||||
@ -188,9 +242,27 @@ python update_lottery.py
|
||||
##### 自动定时更新
|
||||
```bash
|
||||
cd backend
|
||||
python schedule_update.py
|
||||
python scheduler.py
|
||||
```
|
||||
系统会在每天凌晨2点自动检查并更新数据。
|
||||
系统会在每天凌晨6点自动检查并更新数据。
|
||||
|
||||
### 拼盘推荐系统 ⭐ 新功能
|
||||
|
||||
#### 自动推荐
|
||||
- **定时生成**: 每天下午5点自动生成
|
||||
- **智能算法**: 使用集成预测算法
|
||||
- **多注推荐**: 每次生成4注推荐号码
|
||||
- **类型轮换**: 根据日期自动选择彩票类型
|
||||
|
||||
#### 手动生成
|
||||
- 在一键下单页面点击"来一份拼盘"按钮
|
||||
- 实时生成推荐号码
|
||||
- 支持复制所有号码
|
||||
|
||||
#### 推荐历史
|
||||
- 查看历史推荐记录
|
||||
- 显示中奖情况
|
||||
- 支持手动检查中奖
|
||||
|
||||
### 高级分析功能 ⭐
|
||||
1. 进入"高级分析"页面
|
||||
@ -199,115 +271,92 @@ python schedule_update.py
|
||||
- **遗漏值分析**: 查看各号码的遗漏期数
|
||||
- **和值分析**: 分析红球和值的分布规律
|
||||
- **AC值分析**: 邻号差值分析
|
||||
- **质合比分析**: 质数与合数比例
|
||||
- **012路分析**: 除3余数分布
|
||||
- **跨度分析**: 号码跨度统计
|
||||
- **综合分析**: 多维度整合分析
|
||||
4. 设置分析期数(10-500期)
|
||||
5. 点击"分析"按钮查看结果
|
||||
- **质合比分析**: 质数与合数的比例分析
|
||||
- **012路分析**: 除3余数分析
|
||||
- **跨度分析**: 最大最小号码差值分析
|
||||
- **综合分析**: 多维度数据整合分析
|
||||
|
||||
### 智能预测功能 ⭐
|
||||
1. 进入"智能预测"页面
|
||||
2. 选择彩票类型
|
||||
3. 设置训练期数(建议100-500期)
|
||||
4. 点击"训练模型"按钮
|
||||
5. 训练完成后,可选择以下预测方法:
|
||||
- **机器学习预测**: 基于AI算法的预测
|
||||
3. 选择预测方法:
|
||||
- **机器学习预测**: 基于历史数据的AI预测
|
||||
- **模式预测**: 基于统计模式的预测
|
||||
- **集成预测**: 多方法综合预测
|
||||
6. 查看预测结果和置信度
|
||||
4. 设置训练参数
|
||||
5. 查看预测结果
|
||||
|
||||
### 数据查询
|
||||
1. 在查询表单中输入查询条件
|
||||
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}` - 集成预测
|
||||
## API文档
|
||||
启动后端服务后,访问 http://localhost:8000/docs 查看完整的API文档。
|
||||
|
||||
## 常见问题
|
||||
1. 数据库连接失败
|
||||
- 检查数据库服务是否启动
|
||||
- 验证数据库连接配置是否正确
|
||||
|
||||
2. 前端无法连接后端
|
||||
- 确认后端服务是否正常运行
|
||||
- 检查前端环境配置中的 API 地址是否正确
|
||||
### 定时任务相关
|
||||
**Q: 定时任务没有执行?**
|
||||
A: 检查以下几点:
|
||||
1. 确保定时任务进程正在运行
|
||||
2. 检查日志文件 `backend/lottery_scheduler.log`
|
||||
3. 确认系统时间正确
|
||||
4. 检查数据库连接是否正常
|
||||
|
||||
3. 数据导入失败
|
||||
- 检查 JSON 文件格式是否正确
|
||||
- 确认数据库表结构是否完整
|
||||
**Q: 如何修改定时任务时间?**
|
||||
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. 机器学习预测失败
|
||||
- 确保历史数据充足(建议至少100期)
|
||||
- 检查训练参数设置是否合理
|
||||
**Q: 如何查看任务执行日志?**
|
||||
A: 查看日志文件:
|
||||
```bash
|
||||
tail -f backend/lottery_scheduler.log
|
||||
```
|
||||
|
||||
## 开发计划
|
||||
- [x] 添加高级数据分析功能
|
||||
- [x] 实现机器学习预测系统
|
||||
- [x] 优化数据可视化展示
|
||||
- [ ] 添加用户认证功能
|
||||
- [ ] 实现数据备份和恢复
|
||||
- [ ] 优化数据导入性能
|
||||
- [ ] 添加更多统计分析功能
|
||||
- [ ] 实现自定义选号策略
|
||||
- [ ] 添加移动端适配
|
||||
- [ ] 实现数据导出功能增强
|
||||
### 数据更新相关
|
||||
**Q: 数据更新失败?**
|
||||
A: 检查以下几点:
|
||||
1. 网络连接是否正常
|
||||
2. API密钥是否有效
|
||||
3. 数据库连接是否正常
|
||||
4. 查看后端日志获取详细错误信息
|
||||
|
||||
## 贡献指南
|
||||
1. Fork 项目
|
||||
2. 创建特性分支
|
||||
3. 提交更改
|
||||
4. 推送到分支
|
||||
5. 创建 Pull Request
|
||||
**Q: 如何手动更新数据?**
|
||||
A: 可以通过以下方式:
|
||||
1. 前端页面点击更新按钮
|
||||
2. 调用API接口
|
||||
3. 运行更新脚本:`python update_lottery.py`
|
||||
|
||||
## 许可证
|
||||
MIT License
|
||||
### 拼盘推荐相关
|
||||
**Q: 今日推荐没有生成?**
|
||||
A: 检查以下几点:
|
||||
1. 定时任务是否正常运行
|
||||
2. 是否有足够的历史数据
|
||||
3. 预测模型是否训练完成
|
||||
4. 查看日志文件获取错误信息
|
||||
|
||||
**Q: 如何手动生成推荐?**
|
||||
A: 在一键下单页面点击"来一份拼盘"按钮即可手动生成。
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v2.0.0 (2024-01-XX)
|
||||
- ✨ 新增高级数据分析功能
|
||||
- ✨ 新增机器学习预测系统
|
||||
- ✨ 新增遗漏值、和值、AC值等分析
|
||||
- ✨ 新增质合比、012路、跨度分析
|
||||
- ✨ 优化数据可视化展示
|
||||
- 🔧 更新依赖包版本
|
||||
- 📝 完善API文档
|
||||
### v1.1.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,
|
||||
'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 sqlalchemy.orm import Session
|
||||
from ..models.lottery import SSQLottery, DLTLottery
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class PredictionService:
|
||||
@ -545,3 +546,87 @@ class PredictionService:
|
||||
"pattern_analysis": pattern_result.get('suggested_criteria', {}) if pattern_result else {},
|
||||
"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.middleware.cors import CORSMiddleware
|
||||
from app.api.endpoints import analysis
|
||||
from app.api.endpoints import analysis, lottery, prediction
|
||||
|
||||
app = FastAPI(
|
||||
title="彩票数据分析系统",
|
||||
@ -19,8 +19,16 @@ app.add_middleware(
|
||||
|
||||
# 注册路由
|
||||
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("/")
|
||||
def read_root():
|
||||
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()
|
||||
@ -42,4 +42,12 @@ export function recommendToday() {
|
||||
url: '/api/v1/prediction/recommend/today',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取今日拼盘推荐
|
||||
export function getTodayRecommendations() {
|
||||
return request({
|
||||
url: '/api/v1/prediction/recommend/today',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@ -5,6 +5,43 @@
|
||||
<p class="subtitle">今日拼盘新鲜出锅,懒人专属,AI大厨为你配号!</p>
|
||||
</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="order-card">
|
||||
@ -127,7 +164,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { recommendToday } from '@/api/prediction'
|
||||
import { recommendToday, getTodayRecommendations } from '@/api/prediction'
|
||||
import { lotteryApi } from '@/api/lottery'
|
||||
|
||||
export default {
|
||||
@ -140,7 +177,11 @@ export default {
|
||||
todayRecommend: [],
|
||||
ssqHistory: [],
|
||||
dltHistory: [],
|
||||
checkingWin: false
|
||||
checkingWin: false,
|
||||
schedulerStatus: {
|
||||
nextUpdate: null,
|
||||
nextRecommend: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -161,9 +202,56 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.loadHistory()
|
||||
this.loadTodayRecommendations()
|
||||
this.setActiveTabByDay()
|
||||
this.updateSchedulerStatus()
|
||||
},
|
||||
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() {
|
||||
this.loading = true
|
||||
try {
|
||||
@ -308,6 +396,55 @@ export default {
|
||||
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 {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ def check_dependencies():
|
||||
import sqlalchemy
|
||||
import pandas
|
||||
import requests
|
||||
import schedule
|
||||
print("✅ 后端依赖检查通过")
|
||||
return True
|
||||
except ImportError as e:
|
||||
@ -37,6 +38,51 @@ def check_dependencies():
|
||||
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():
|
||||
"""启动后端服务"""
|
||||
print("\n🚀 启动后端服务...")
|
||||
@ -255,6 +301,13 @@ def main():
|
||||
print("❌ 用户取消启动")
|
||||
return
|
||||
|
||||
# 询问是否启动定时任务
|
||||
print("\n⏰ 定时任务选项:")
|
||||
print("1. 启动定时任务(推荐)")
|
||||
print("2. 不启动定时任务")
|
||||
scheduler_choice = input("请选择 (1/2): ").strip()
|
||||
start_scheduler_task = scheduler_choice == "1"
|
||||
|
||||
# 保存当前目录
|
||||
original_dir = os.getcwd()
|
||||
|
||||
@ -270,10 +323,20 @@ def main():
|
||||
print("\n请检查后端日志获取详细错误信息")
|
||||
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)
|
||||
if not frontend_process:
|
||||
backend_process.terminate()
|
||||
if scheduler_process:
|
||||
scheduler_process.terminate()
|
||||
print("\n💡 前端启动失败,可能的原因:")
|
||||
print("1. Node.js未安装或版本过低")
|
||||
print("2. 端口5173被占用")
|
||||
@ -286,11 +349,18 @@ def main():
|
||||
print("📊 后端API: http://localhost:8000")
|
||||
print("📊 API文档: http://localhost:8000/docs")
|
||||
print("🌐 前端界面: http://localhost:5173")
|
||||
if scheduler_process:
|
||||
print("⏰ 定时任务: 已启动")
|
||||
print(" - 每天早上6点: 更新开奖数据")
|
||||
print(" - 每天下午5点: 生成拼盘推荐")
|
||||
else:
|
||||
print("⏰ 定时任务: 未启动")
|
||||
print("=" * 50)
|
||||
print("💡 使用说明:")
|
||||
print("1. 打开浏览器访问 http://localhost:5173")
|
||||
print("2. 在首页点击'更新数据'按钮获取最新开奖信息")
|
||||
print("3. 使用各种分析功能进行数据分析")
|
||||
print("2. 在首页点击'补全场早点'按钮获取最新开奖信息")
|
||||
print("3. 在一键下单页面查看今日拼盘推荐")
|
||||
print("4. 使用各种分析功能进行数据分析")
|
||||
print("=" * 50)
|
||||
print("按 Ctrl+C 停止服务")
|
||||
|
||||
@ -302,6 +372,8 @@ def main():
|
||||
print("\n🛑 正在停止服务...")
|
||||
backend_process.terminate()
|
||||
frontend_process.terminate()
|
||||
if scheduler_process:
|
||||
scheduler_process.terminate()
|
||||
print("✅ 服务已停止")
|
||||
|
||||
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