新增功能: 1. 报表日期格式改为数字显示 - 修改 formatDateDisplay 函数 - 格式:YYYY-MM-DD(如"2026-07-09") 2. 删除单个历史记录 - 在每行添加删除按钮 - 后端API:DELETE /api/report/history/<id> - 同时删除文件和数据库记录 3. 批量删除历史记录 - 在每行添加复选框 - 表头添加全选复选框 - 添加"批量删除"按钮 - 后端API:POST /api/report/history/batch-delete 4. 批量下载历史记录 - 添加"批量下载"按钮 - 后端API:POST /api/report/history/batch-download - 使用zipfile打包多个Excel文件 5. 按日期时间查询 - 添加日期范围选择器(开始日期、结束日期) - 添加"查询"和"重置"按钮 - 后端API:GET /api/report/history?start_date=xxx&end_date=xxx - 支持按start_time和end_time筛选 6. 根据ID下载历史记录 - 后端API:GET /api/report/history/<id>/download - 直接下载对应的Excel文件 前端修改: - 添加全选复选框和行复选框 - 添加批量操作按钮(批量删除、批量下载) - 添加日期查询表单 - 添加相关JavaScript函数 后端修改: - 修改历史记录查询API,支持日期筛选 - 添加删除单个记录API - 添加批量删除API - 添加批量下载API - 添加根据ID下载API Coze-Commit-Type: user Coze-User-ID: 3722323274763196 Coze-Conversation-ID: 9894087
592 lines
21 KiB
Python
592 lines
21 KiB
Python
"""
|
||
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))
|
||
start_date = request.args.get('start_date')
|
||
end_date = request.args.get('end_date')
|
||
offset = (page - 1) * page_size
|
||
|
||
# 构建查询条件
|
||
where_clauses = []
|
||
params = []
|
||
|
||
if start_date:
|
||
where_clauses.append('DATE(start_time) >= %s')
|
||
params.append(start_date)
|
||
|
||
if end_date:
|
||
where_clauses.append('DATE(end_time) <= %s')
|
||
params.append(end_date)
|
||
|
||
where_sql = ' AND '.join(where_clauses) if where_clauses else '1=1'
|
||
|
||
# 查询总数
|
||
total_result = execute_query(
|
||
f'SELECT COUNT(*) as total FROM t_daily_report_history WHERE {where_sql}',
|
||
tuple(params)
|
||
)
|
||
total = total_result[0]['total']
|
||
|
||
# 查询数据
|
||
history = execute_query(
|
||
f'SELECT * FROM t_daily_report_history WHERE {where_sql} ORDER BY create_time DESC LIMIT %s OFFSET %s',
|
||
tuple(params) + (page_size, offset)
|
||
)
|
||
|
||
# 解析JSON字段并确保file_path正确
|
||
for item in history:
|
||
item['sum_results'] = json.loads(item['sum_results']) if item['sum_results'] else {}
|
||
# 确保file_path是字符串
|
||
if item['file_path'] is None:
|
||
item['file_path'] = ''
|
||
|
||
# 调试日志
|
||
print(f"[历史记录] ID: {item['id']}, status: {item['status']}, file_path: '{item['file_path']}'")
|
||
|
||
return jsonify({
|
||
'success': True,
|
||
'data': {
|
||
'list': history,
|
||
'total': total,
|
||
'page': page,
|
||
'page_size': page_size
|
||
}
|
||
})
|
||
except Exception as e:
|
||
print(f"[历史记录API] 错误: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return jsonify({'success': False, 'message': str(e)}), 500
|
||
|
||
|
||
# ==================== 历史记录管理API ====================
|
||
|
||
@app.route('/api/report/history/<int:history_id>', methods=['DELETE'])
|
||
def delete_report_history(history_id):
|
||
"""删除单个历史记录"""
|
||
try:
|
||
# 先查询文件路径
|
||
result = execute_query(
|
||
'SELECT file_path FROM t_daily_report_history WHERE id = %s',
|
||
(history_id,)
|
||
)
|
||
|
||
if result:
|
||
file_path = result[0].get('file_path', '')
|
||
# 删除文件
|
||
if file_path and os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'public', file_path.lstrip('/'))):
|
||
os.remove(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'public', file_path.lstrip('/')))
|
||
|
||
# 删除数据库记录
|
||
execute_update('DELETE FROM t_daily_report_history WHERE id = %s', (history_id,))
|
||
|
||
return jsonify({'success': True, 'message': '删除成功'})
|
||
except Exception as e:
|
||
print(f"[删除历史记录] 错误: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return jsonify({'success': False, 'message': str(e)}), 500
|
||
|
||
|
||
@app.route('/api/report/history/batch-delete', methods=['POST'])
|
||
def batch_delete_report_history():
|
||
"""批量删除历史记录"""
|
||
try:
|
||
data = request.get_json()
|
||
ids = data.get('ids', [])
|
||
|
||
if not ids:
|
||
return jsonify({'success': False, 'message': '请选择要删除的记录'}), 400
|
||
|
||
# 查询文件路径
|
||
results = execute_query(
|
||
f'SELECT file_path FROM t_daily_report_history WHERE id IN ({",".join(["%s"] * len(ids))})',
|
||
tuple(ids)
|
||
)
|
||
|
||
# 删除文件
|
||
for result in results:
|
||
file_path = result.get('file_path', '')
|
||
if file_path and os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'public', file_path.lstrip('/'))):
|
||
os.remove(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'public', file_path.lstrip('/')))
|
||
|
||
# 删除数据库记录
|
||
execute_update(
|
||
f'DELETE FROM t_daily_report_history WHERE id IN ({",".join(["%s"] * len(ids))})',
|
||
tuple(ids)
|
||
)
|
||
|
||
return jsonify({'success': True, 'message': f'成功删除 {len(ids)} 条记录'})
|
||
except Exception as e:
|
||
print(f"[批量删除历史记录] 错误: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return jsonify({'success': False, 'message': str(e)}), 500
|
||
|
||
|
||
@app.route('/api/report/history/<int:history_id>/download', methods=['GET'])
|
||
def download_report_by_id(history_id):
|
||
"""根据ID下载历史记录"""
|
||
try:
|
||
# 查询历史记录
|
||
result = execute_query(
|
||
'SELECT file_path, split_name, report_date FROM t_daily_report_history WHERE id = %s',
|
||
(history_id,)
|
||
)
|
||
|
||
if not result:
|
||
return jsonify({'success': False, 'message': '记录不存在'}), 404
|
||
|
||
file_path = result[0]['file_path']
|
||
if not file_path:
|
||
return jsonify({'success': False, 'message': '文件不存在'}), 404
|
||
|
||
# 构建完整路径
|
||
full_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'public', file_path.lstrip('/'))
|
||
|
||
if not os.path.exists(full_path):
|
||
return jsonify({'success': False, 'message': '文件不存在'}), 404
|
||
|
||
# 返回文件
|
||
directory = os.path.dirname(full_path)
|
||
filename = os.path.basename(full_path)
|
||
return send_from_directory(directory, filename, as_attachment=True)
|
||
except Exception as e:
|
||
print(f"[下载历史记录] 错误: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
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')
|
||
print(f"[下载] 请求路径: {file_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(os.path.dirname(os.path.abspath(__file__)), 'public', 'reports')
|
||
|
||
print(f"[下载] 文件目录: {reports_dir}")
|
||
print(f"[下载] 文件名: {filename}")
|
||
print(f"[下载] 文件是否存在: {os.path.exists(os.path.join(reports_dir, filename))}")
|
||
|
||
# 列出目录中的所有文件
|
||
if os.path.exists(reports_dir):
|
||
print(f"[下载] 目录中的文件: {os.listdir(reports_dir)}")
|
||
|
||
return send_from_directory(reports_dir, filename, as_attachment=True)
|
||
except Exception as e:
|
||
print(f"[下载] 错误: {str(e)}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
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('DEPLOY_RUN_PORT', os.environ.get('PORT', 5000)))
|
||
print(f'启动服务器: http://localhost:{port}')
|
||
print(f'数据库: {os.environ.get("DB_HOST", "haoslm2.xicp.net")}:{os.environ.get("DB_PORT", "10216")}')
|
||
app.run(host='0.0.0.0', port=port, debug=True) |