2026-07-09 11:26:23 +08:00
|
|
|
|
"""
|
|
|
|
|
|
Flask主应用
|
|
|
|
|
|
订单日报系统
|
|
|
|
|
|
"""
|
|
|
|
|
|
import os
|
|
|
|
|
|
import json
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from flask import Flask, request, jsonify, send_from_directory, render_template
|
|
|
|
|
|
from flask_cors import CORS
|
|
|
|
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
|
|
|
|
import pytz
|
|
|
|
|
|
|
|
|
|
|
|
from lib.db import execute_query, execute_update, execute_insert
|
|
|
|
|
|
from lib.field_mapping import get_all_fields_with_display
|
|
|
|
|
|
from lib.report_generator import generate_daily_report
|
|
|
|
|
|
|
|
|
|
|
|
# 创建Flask应用
|
|
|
|
|
|
app = Flask(__name__,
|
|
|
|
|
|
template_folder='templates',
|
|
|
|
|
|
static_folder='public')
|
|
|
|
|
|
CORS(app)
|
|
|
|
|
|
|
|
|
|
|
|
# 确保public/reports目录存在
|
|
|
|
|
|
os.makedirs(os.path.join('public', 'reports'), exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 页面路由 ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/')
|
|
|
|
|
|
def index():
|
|
|
|
|
|
"""主页"""
|
|
|
|
|
|
return render_template('index.html')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 配置管理API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/config', methods=['GET'])
|
|
|
|
|
|
def get_configs():
|
|
|
|
|
|
"""获取所有配置"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
configs = execute_query(
|
|
|
|
|
|
'SELECT * FROM t_daily_report_config ORDER BY sort_order ASC, id DESC'
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 解析JSON字段
|
|
|
|
|
|
for config in configs:
|
|
|
|
|
|
config['selected_fields'] = json.loads(config['selected_fields'])
|
|
|
|
|
|
config['sum_fields'] = json.loads(config['sum_fields']) if config['sum_fields'] else []
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({'success': True, 'data': configs})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/config', methods=['POST'])
|
|
|
|
|
|
def create_config():
|
|
|
|
|
|
"""创建配置"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
data = request.json
|
|
|
|
|
|
config_name = data.get('config_name')
|
|
|
|
|
|
split_type = data.get('split_type')
|
|
|
|
|
|
split_value = data.get('split_value')
|
|
|
|
|
|
split_name = data.get('split_name', '')
|
|
|
|
|
|
selected_fields = data.get('selected_fields', [])
|
|
|
|
|
|
sum_fields = data.get('sum_fields', [])
|
|
|
|
|
|
|
|
|
|
|
|
if not config_name or not split_type or not split_value:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '缺少必填字段'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
if not selected_fields:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '请至少选择一个字段'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 生成ID
|
|
|
|
|
|
config_id = int(datetime.now().timestamp() * 1000)
|
|
|
|
|
|
|
|
|
|
|
|
# 获取最大排序值
|
|
|
|
|
|
max_sort = execute_query('SELECT MAX(sort_order) as max_sort FROM t_daily_report_config')
|
|
|
|
|
|
sort_order = (max_sort[0]['max_sort'] or 0) + 1
|
|
|
|
|
|
|
|
|
|
|
|
sql = """
|
|
|
|
|
|
INSERT INTO t_daily_report_config
|
|
|
|
|
|
(id, config_name, split_type, split_value, split_name, selected_fields,
|
|
|
|
|
|
sum_fields, is_active, sort_order, create_time, update_time)
|
|
|
|
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, 1, %s, NOW(), NOW())
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
params = (
|
|
|
|
|
|
config_id,
|
|
|
|
|
|
config_name,
|
|
|
|
|
|
split_type,
|
|
|
|
|
|
split_value,
|
|
|
|
|
|
split_name,
|
|
|
|
|
|
json.dumps(selected_fields, ensure_ascii=False),
|
|
|
|
|
|
json.dumps(sum_fields, ensure_ascii=False),
|
|
|
|
|
|
sort_order
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
execute_insert(sql, params)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'message': '配置创建成功',
|
|
|
|
|
|
'data': {'id': config_id}
|
|
|
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/config/<int:config_id>', methods=['PUT'])
|
|
|
|
|
|
def update_config(config_id):
|
|
|
|
|
|
"""更新配置"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
data = request.json
|
|
|
|
|
|
config_name = data.get('config_name')
|
|
|
|
|
|
split_type = data.get('split_type')
|
|
|
|
|
|
split_value = data.get('split_value')
|
|
|
|
|
|
split_name = data.get('split_name', '')
|
|
|
|
|
|
selected_fields = data.get('selected_fields', [])
|
|
|
|
|
|
sum_fields = data.get('sum_fields', [])
|
|
|
|
|
|
|
|
|
|
|
|
sql = """
|
|
|
|
|
|
UPDATE t_daily_report_config
|
|
|
|
|
|
SET config_name = %s, split_type = %s, split_value = %s, split_name = %s,
|
|
|
|
|
|
selected_fields = %s, sum_fields = %s, update_time = NOW()
|
|
|
|
|
|
WHERE id = %s
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
params = (
|
|
|
|
|
|
config_name,
|
|
|
|
|
|
split_type,
|
|
|
|
|
|
split_value,
|
|
|
|
|
|
split_name,
|
|
|
|
|
|
json.dumps(selected_fields, ensure_ascii=False),
|
|
|
|
|
|
json.dumps(sum_fields, ensure_ascii=False),
|
|
|
|
|
|
config_id
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
execute_update(sql, params)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({'success': True, 'message': '配置更新成功'})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/config/<int:config_id>', methods=['DELETE'])
|
|
|
|
|
|
def delete_config(config_id):
|
|
|
|
|
|
"""删除配置"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
execute_update('DELETE FROM t_daily_report_config WHERE id = %s', (config_id,))
|
|
|
|
|
|
return jsonify({'success': True, 'message': '配置删除成功'})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/config/<int:config_id>/toggle', methods=['POST'])
|
|
|
|
|
|
def toggle_config(config_id):
|
|
|
|
|
|
"""启用/禁用配置"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
execute_update(
|
|
|
|
|
|
'UPDATE t_daily_report_config SET is_active = NOT is_active, update_time = NOW() WHERE id = %s',
|
|
|
|
|
|
(config_id,)
|
|
|
|
|
|
)
|
|
|
|
|
|
return jsonify({'success': True, 'message': '操作成功'})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/config/<int:config_id>/move', methods=['POST'])
|
|
|
|
|
|
def move_config(config_id):
|
|
|
|
|
|
"""移动配置排序"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
direction = request.json.get('direction') # up 或 down
|
|
|
|
|
|
|
|
|
|
|
|
# 获取当前配置
|
|
|
|
|
|
current = execute_query(
|
|
|
|
|
|
'SELECT sort_order FROM t_daily_report_config WHERE id = %s',
|
|
|
|
|
|
(config_id,)
|
|
|
|
|
|
)
|
|
|
|
|
|
if not current:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '配置不存在'}), 404
|
|
|
|
|
|
|
|
|
|
|
|
current_order = current[0]['sort_order']
|
|
|
|
|
|
|
|
|
|
|
|
if direction == 'up':
|
|
|
|
|
|
# 找到上一个配置
|
|
|
|
|
|
prev = execute_query(
|
|
|
|
|
|
'SELECT id, sort_order FROM t_daily_report_config WHERE sort_order < %s ORDER BY sort_order DESC LIMIT 1',
|
|
|
|
|
|
(current_order,)
|
|
|
|
|
|
)
|
|
|
|
|
|
if prev:
|
|
|
|
|
|
# 交换排序
|
|
|
|
|
|
execute_update(
|
|
|
|
|
|
'UPDATE t_daily_report_config SET sort_order = %s WHERE id = %s',
|
|
|
|
|
|
(prev[0]['sort_order'], config_id)
|
|
|
|
|
|
)
|
|
|
|
|
|
execute_update(
|
|
|
|
|
|
'UPDATE t_daily_report_config SET sort_order = %s WHERE id = %s',
|
|
|
|
|
|
(current_order, prev[0]['id'])
|
|
|
|
|
|
)
|
|
|
|
|
|
elif direction == 'down':
|
|
|
|
|
|
# 找到下一个配置
|
|
|
|
|
|
next_config = execute_query(
|
|
|
|
|
|
'SELECT id, sort_order FROM t_daily_report_config WHERE sort_order > %s ORDER BY sort_order ASC LIMIT 1',
|
|
|
|
|
|
(current_order,)
|
|
|
|
|
|
)
|
|
|
|
|
|
if next_config:
|
|
|
|
|
|
# 交换排序
|
|
|
|
|
|
execute_update(
|
|
|
|
|
|
'UPDATE t_daily_report_config SET sort_order = %s WHERE id = %s',
|
|
|
|
|
|
(next_config[0]['sort_order'], config_id)
|
|
|
|
|
|
)
|
|
|
|
|
|
execute_update(
|
|
|
|
|
|
'UPDATE t_daily_report_config SET sort_order = %s WHERE id = %s',
|
|
|
|
|
|
(current_order, next_config[0]['id'])
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({'success': True, 'message': '移动成功'})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 企业和用户列表API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/entities', methods=['GET'])
|
|
|
|
|
|
def get_entities():
|
|
|
|
|
|
"""获取企业或用户列表"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
entity_type = request.args.get('type', 'company')
|
|
|
|
|
|
|
|
|
|
|
|
if entity_type == 'company':
|
|
|
|
|
|
# 获取企业列表
|
|
|
|
|
|
companies = execute_query(
|
|
|
|
|
|
'SELECT DISTINCT company_id, company_name FROM t_company ORDER BY company_name'
|
|
|
|
|
|
)
|
|
|
|
|
|
return jsonify({'success': True, 'data': companies})
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 获取用户列表
|
|
|
|
|
|
users = execute_query(
|
|
|
|
|
|
'SELECT DISTINCT user_id, user_name, order_type FROM t_equipment_charge_order WHERE user_id IS NOT NULL ORDER BY user_name'
|
|
|
|
|
|
)
|
|
|
|
|
|
return jsonify({'success': True, 'data': users})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 字段列表API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/fields', methods=['GET'])
|
|
|
|
|
|
def get_fields():
|
|
|
|
|
|
"""获取所有可用字段"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
fields = get_all_fields_with_display()
|
|
|
|
|
|
return jsonify({'success': True, 'data': fields})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 日报生成API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/report/generate', methods=['POST'])
|
|
|
|
|
|
def generate_report():
|
|
|
|
|
|
"""生成日报"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
data = request.json
|
|
|
|
|
|
config_id = data.get('config_id')
|
|
|
|
|
|
|
|
|
|
|
|
if not config_id:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '请选择配置'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 解析时间参数
|
|
|
|
|
|
start_time = None
|
|
|
|
|
|
end_time = None
|
|
|
|
|
|
|
|
|
|
|
|
if data.get('start_time'):
|
|
|
|
|
|
start_time = datetime.strptime(data['start_time'], '%Y-%m-%d %H:%M:%S')
|
|
|
|
|
|
if data.get('end_time'):
|
|
|
|
|
|
end_time = datetime.strptime(data['end_time'], '%Y-%m-%d %H:%M:%S')
|
|
|
|
|
|
|
|
|
|
|
|
result = generate_daily_report(config_id, start_time, end_time)
|
|
|
|
|
|
|
|
|
|
|
|
if result['success']:
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
else:
|
|
|
|
|
|
return jsonify(result), 400
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 历史记录API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/report/history', methods=['GET'])
|
|
|
|
|
|
def get_report_history():
|
|
|
|
|
|
"""获取日报生成历史"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
page = int(request.args.get('page', 1))
|
|
|
|
|
|
page_size = int(request.args.get('page_size', 20))
|
|
|
|
|
|
offset = (page - 1) * page_size
|
|
|
|
|
|
|
|
|
|
|
|
# 查询总数
|
|
|
|
|
|
total_result = execute_query('SELECT COUNT(*) as total FROM t_daily_report_history')
|
|
|
|
|
|
total = total_result[0]['total']
|
|
|
|
|
|
|
|
|
|
|
|
# 查询数据
|
|
|
|
|
|
history = execute_query(
|
|
|
|
|
|
'SELECT * FROM t_daily_report_history ORDER BY create_time DESC LIMIT %s OFFSET %s',
|
|
|
|
|
|
(page_size, offset)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-07-09 12:59:40 +08:00
|
|
|
|
# 解析JSON字段并确保file_path正确
|
2026-07-09 11:26:23 +08:00
|
|
|
|
for item in history:
|
|
|
|
|
|
item['sum_results'] = json.loads(item['sum_results']) if item['sum_results'] else {}
|
2026-07-09 12:59:40 +08:00
|
|
|
|
# 确保file_path是字符串
|
|
|
|
|
|
if item['file_path'] is None:
|
|
|
|
|
|
item['file_path'] = ''
|
|
|
|
|
|
|
|
|
|
|
|
# 调试日志
|
|
|
|
|
|
print(f"[历史记录] ID: {item['id']}, status: {item['status']}, file_path: '{item['file_path']}'")
|
2026-07-09 11:26:23 +08:00
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': True,
|
|
|
|
|
|
'data': {
|
|
|
|
|
|
'list': history,
|
|
|
|
|
|
'total': total,
|
|
|
|
|
|
'page': page,
|
|
|
|
|
|
'page_size': page_size
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
2026-07-09 12:59:40 +08:00
|
|
|
|
print(f"[历史记录API] 错误: {e}")
|
|
|
|
|
|
import traceback
|
|
|
|
|
|
traceback.print_exc()
|
2026-07-09 11:26:23 +08:00
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 数据库初始化API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/init-tables', methods=['POST'])
|
|
|
|
|
|
def init_tables():
|
|
|
|
|
|
"""初始化数据库表"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 创建配置表
|
|
|
|
|
|
create_config_table = """
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS t_daily_report_config (
|
|
|
|
|
|
id BIGINT NOT NULL COMMENT '配置ID',
|
|
|
|
|
|
config_name VARCHAR(100) NOT NULL COMMENT '配置名称',
|
|
|
|
|
|
split_type VARCHAR(20) NOT NULL COMMENT '拆分方式',
|
|
|
|
|
|
split_value VARCHAR(100) NOT NULL COMMENT '拆分值',
|
|
|
|
|
|
split_name VARCHAR(200) NULL COMMENT '拆分显示名称',
|
|
|
|
|
|
selected_fields VARCHAR(3000) NOT NULL COMMENT '选择的字段列表',
|
|
|
|
|
|
sum_fields VARCHAR(3000) NULL COMMENT '求和字段列表',
|
|
|
|
|
|
is_active TINYINT NULL COMMENT '是否启用',
|
|
|
|
|
|
sort_order INT NULL COMMENT '排序顺序',
|
|
|
|
|
|
create_time DATETIME NULL COMMENT '创建时间',
|
|
|
|
|
|
update_time DATETIME NULL COMMENT '更新时间'
|
|
|
|
|
|
)
|
|
|
|
|
|
UNIQUE KEY(id)
|
|
|
|
|
|
DISTRIBUTED BY HASH(id) BUCKETS 1
|
|
|
|
|
|
PROPERTIES("replication_num" = "1")
|
|
|
|
|
|
"""
|
|
|
|
|
|
execute_update(create_config_table)
|
|
|
|
|
|
|
|
|
|
|
|
# 创建历史表
|
|
|
|
|
|
create_history_table = """
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS t_daily_report_history (
|
|
|
|
|
|
id BIGINT NOT NULL COMMENT '历史ID',
|
|
|
|
|
|
report_date VARCHAR(20) NULL COMMENT '报表日期',
|
|
|
|
|
|
start_time VARCHAR(50) NULL COMMENT '开始时间',
|
|
|
|
|
|
end_time VARCHAR(50) NULL COMMENT '结束时间',
|
|
|
|
|
|
split_type VARCHAR(20) NULL COMMENT '拆分方式',
|
|
|
|
|
|
split_value VARCHAR(100) NULL COMMENT '拆分值',
|
|
|
|
|
|
split_name VARCHAR(200) NULL COMMENT '拆分显示名称',
|
|
|
|
|
|
config_id BIGINT NULL COMMENT '配置ID',
|
|
|
|
|
|
total_orders INT NULL COMMENT '订单总数',
|
|
|
|
|
|
total_amount DECIMAL(10,2) NULL COMMENT '总金额',
|
|
|
|
|
|
sum_results VARCHAR(2000) NULL COMMENT '求和结果',
|
|
|
|
|
|
file_path VARCHAR(500) NULL COMMENT '文件路径',
|
|
|
|
|
|
status TINYINT NULL COMMENT '状态',
|
|
|
|
|
|
create_time DATETIME NULL COMMENT '创建时间'
|
|
|
|
|
|
)
|
|
|
|
|
|
UNIQUE KEY(id)
|
|
|
|
|
|
DISTRIBUTED BY HASH(id) BUCKETS 1
|
|
|
|
|
|
PROPERTIES("replication_num" = "1")
|
|
|
|
|
|
"""
|
|
|
|
|
|
execute_update(create_history_table)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({'success': True, 'message': '数据库表初始化成功'})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 文件下载API ====================
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/download', methods=['GET'])
|
|
|
|
|
|
def download_file():
|
|
|
|
|
|
"""下载文件"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
file_path = request.args.get('path')
|
|
|
|
|
|
if not file_path:
|
|
|
|
|
|
return jsonify({'success': False, 'message': '文件路径不能为空'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 安全检查:确保路径在public目录下
|
|
|
|
|
|
if not file_path.startswith('/reports/'):
|
|
|
|
|
|
return jsonify({'success': False, 'message': '无效的文件路径'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
filename = file_path.replace('/reports/', '')
|
|
|
|
|
|
reports_dir = os.path.join('public', 'reports')
|
|
|
|
|
|
|
|
|
|
|
|
return send_from_directory(reports_dir, filename, as_attachment=True)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 定时任务 ====================
|
|
|
|
|
|
|
|
|
|
|
|
def scheduled_job():
|
|
|
|
|
|
"""定时任务:每天8:01自动生成日报"""
|
|
|
|
|
|
print(f'[{datetime.now()}] 开始执行定时任务...')
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 获取所有启用的配置
|
|
|
|
|
|
configs = execute_query(
|
|
|
|
|
|
'SELECT id, config_name FROM t_daily_report_config WHERE is_active = 1'
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if not configs:
|
|
|
|
|
|
print('没有启用的配置,跳过生成')
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
print(f'找到 {len(configs)} 个启用的配置')
|
|
|
|
|
|
|
|
|
|
|
|
# 为每个配置生成日报
|
|
|
|
|
|
for config in configs:
|
|
|
|
|
|
print(f'正在生成: {config["config_name"]}')
|
|
|
|
|
|
result = generate_daily_report(config['id'])
|
|
|
|
|
|
|
|
|
|
|
|
if result['success']:
|
|
|
|
|
|
print(f' ✓ 成功: {result["total_orders"]} 条订单, 金额: {result["total_amount"]}')
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f' ✗ 失败: {result["message"]}')
|
|
|
|
|
|
|
|
|
|
|
|
print('定时任务执行完成')
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f'定时任务执行失败: {e}')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 启动定时任务
|
|
|
|
|
|
scheduler = BackgroundScheduler(timezone='Asia/Shanghai')
|
|
|
|
|
|
scheduler.add_job(scheduled_job, 'cron', hour=8, minute=1)
|
|
|
|
|
|
scheduler.start()
|
|
|
|
|
|
print('定时任务已启动:每天 08:01 执行')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 启动应用 ====================
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
port = int(os.environ.get('PORT', 5000))
|
|
|
|
|
|
print(f'启动服务器: http://localhost:{port}')
|
|
|
|
|
|
app.run(host='0.0.0.0', port=port, debug=True)
|