fix: 修正定时任务状态下次更新时间的显示逻辑,分别精确到早上6点和下午5点

This commit is contained in:
Mars 2025-06-26 15:02:03 +08:00
parent ff9d9a857e
commit cb46b20d15
9 changed files with 797 additions and 99 deletions

237
README.md
View File

@ -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

View File

@ -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)}")

View File

@ -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)}")

View File

@ -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
View 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()

View File

@ -43,3 +43,11 @@ export function recommendToday() {
method: 'post'
})
}
// 获取今日拼盘推荐
export function getTodayRecommendations() {
return request({
url: '/api/v1/prediction/recommend/today',
method: 'get'
})
}

View File

@ -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;
}

View File

@ -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
View 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到项目仓库
---
**注意**: 定时任务功能需要系统持续运行,建议在服务器环境下使用。