修复求和数据统计的问题

This commit is contained in:
2026-07-23 14:57:29 +08:00
parent 03098a553e
commit fa884ae782
11 changed files with 550 additions and 184 deletions

View File

@@ -57,6 +57,10 @@ def create_config():
custom_service_fee_name = data.get('custom_service_fee_name')
show_custom_service_fee = 1 if data.get('show_custom_service_fee') else 0
show_total_amount = 1 if data.get('show_total_amount') else 0
total_amount_name = data.get('total_amount_name')
if not config_name or not split_type or not split_value:
log_warning('[配置API] 创建配置失败:缺少必填字段', 'api')
return jsonify({'success': False, 'message': '缺少必填字段'}), 400
@@ -76,8 +80,10 @@ def create_config():
INSERT INTO t_daily_report_config
(id, config_name, split_type, split_value, split_name, selected_fields,
sum_fields, time_periods, merge_telecom, telecom_vehicle_no, field_custom_names,
show_monthly_total, custom_service_fee_price, custom_service_fee_name, is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 1, %s, NOW(), NOW())
show_monthly_total, custom_service_fee_price, custom_service_fee_name,
show_custom_service_fee, show_total_amount, total_amount_name,
is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 1, %s, NOW(), NOW())
"""
params = (
@@ -95,6 +101,9 @@ def create_config():
show_monthly_total,
custom_service_fee_price,
custom_service_fee_name if custom_service_fee_name else None,
show_custom_service_fee,
show_total_amount,
total_amount_name if total_amount_name else None,
sort_order
)
@@ -136,6 +145,10 @@ def update_config(config_id):
custom_service_fee_name = data.get('custom_service_fee_name')
show_custom_service_fee = 1 if data.get('show_custom_service_fee') else 0
show_total_amount = 1 if data.get('show_total_amount') else 0
total_amount_name = data.get('total_amount_name')
# 查询原配置,检查拆分是否变化
old_configs = execute_query('SELECT * FROM t_daily_report_config WHERE id = %s', (config_id,))
if not old_configs:
@@ -148,6 +161,7 @@ def update_config(config_id):
selected_fields = %s, sum_fields = %s, time_periods = %s,
merge_telecom = %s, telecom_vehicle_no = %s, field_custom_names = %s,
show_monthly_total = %s, custom_service_fee_price = %s, custom_service_fee_name = %s,
show_custom_service_fee = %s, show_total_amount = %s, total_amount_name = %s,
update_time = NOW()
WHERE id = %s
"""
@@ -166,6 +180,9 @@ def update_config(config_id):
show_monthly_total,
custom_service_fee_price,
custom_service_fee_name if custom_service_fee_name else None,
show_custom_service_fee,
show_total_amount,
total_amount_name if total_amount_name else None,
config_id
)
@@ -240,8 +257,8 @@ def copy_config(config_id):
# 插入新配置
execute_insert(
'''INSERT INTO t_daily_report_config
(id, config_name, split_type, split_value, split_name, selected_fields, sum_fields, time_periods, merge_telecom, telecom_vehicle_no, field_custom_names, show_monthly_total, custom_service_fee_price, custom_service_fee_name, is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())''',
(id, config_name, split_type, split_value, split_name, selected_fields, sum_fields, time_periods, merge_telecom, telecom_vehicle_no, field_custom_names, show_monthly_total, custom_service_fee_price, custom_service_fee_name, show_custom_service_fee, show_total_amount, total_amount_name, is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())''',
(
new_id,
new_name,
@@ -257,6 +274,9 @@ def copy_config(config_id):
original.get('show_monthly_total', 0),
original.get('custom_service_fee_price'),
original.get('custom_service_fee_name'),
original.get('show_custom_service_fee', 0),
original.get('show_total_amount', 0),
original.get('total_amount_name'),
original['is_active'],
sort_order
)

View File

@@ -93,12 +93,13 @@ def update_sum_data_api(sum_data_id):
"""更新求和数据"""
try:
data = request.json
log_info(f'[求和数据API] 更新求和数据,ID: {sum_data_id}', 'api')
log_info(f'[求和数据API] 更新求和数据,ID: {sum_data_id}, 请求数据: {data}', 'api')
result = update_sum_data(sum_data_id, data)
if result['success']:
log_info(f'[求和数据API] 更新成功,ID: {sum_data_id}', 'api')
return jsonify(result)
else:
log_warning(f'[求和数据API] 更新失败,ID: {sum_data_id}, 原因: {result["message"]}', 'api')
return jsonify(result), 400
except Exception as e:
log_error(f'[求和数据API] 更新求和数据失败: {e}', 'api')
@@ -143,6 +144,57 @@ def batch_delete_sum_data_api():
return jsonify({'success': False, 'message': str(e)}), 500
@sum_data_bp.route('/sum-data/batch-query', methods=['POST'])
def batch_query_sum_data():
"""根据ID列表批量查询求和数据"""
try:
data = request.json
ids = data.get('ids', [])
log_info(f'[求和数据API] 批量查询求和数据,ID数量: {len(ids)}', 'api')
if not ids:
return jsonify({'success': False, 'message': '请提供ID列表'}), 400
from lib.db import execute_query
placeholders = ','.join(['%s'] * len(ids))
sql = f'SELECT * FROM t_daily_report_sum_data WHERE id IN ({placeholders})'
result = execute_query(sql, tuple(ids))
return jsonify({
'success': True,
'data': result
})
except Exception as e:
log_error(f'[求和数据API] 批量查询求和数据失败: {e}', 'api')
return jsonify({'success': False, 'message': str(e)}), 500
@sum_data_bp.route('/sum-data/batch-add', methods=['POST'])
def batch_add_sum_data():
"""批量添加求和数据"""
try:
data = request.json
fields = data.get('fields', [])
log_info(f'[求和数据API] 批量添加求和数据,字段数量: {len(fields)}', 'api')
if not fields:
return jsonify({'success': False, 'message': '请至少添加一个字段'}), 400
from lib.sum_data_collector import batch_add_sum_data
result = batch_add_sum_data(data)
if result['success']:
log_info(f'[求和数据API] 批量添加成功,添加{result["count"]}条记录', 'api')
return jsonify(result)
else:
return jsonify(result), 400
except Exception as e:
log_error(f'[求和数据API] 批量添加求和数据失败: {e}', 'api')
return jsonify({'success': False, 'message': str(e)}), 500
@sum_data_bp.route('/sum-data/monthly-total', methods=['GET'])
def monthly_charge_degree_total():
"""获取指定配置当月充电电量累计(从sum_data表查询,对账后的数据)

View File

@@ -18,8 +18,8 @@ def get_db_config():
'cursorclass': pymysql.cursors.DictCursor,
'autocommit': True,
'connect_timeout': 30,
'read_timeout': 60,
'write_timeout': 60
'read_timeout': 120,
'write_timeout': 120
}
DB_CONFIG = get_db_config()
@@ -41,39 +41,72 @@ def get_connection():
pass
def execute_query(sql, params=None):
def execute_query(sql, params=None, retry=2):
"""执行查询并返回结果"""
try:
with get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(sql, params)
result = cursor.fetchall()
return result
except Exception as e:
log_error(f'查询失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
for attempt in range(retry + 1):
try:
with get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(sql, params)
result = cursor.fetchall()
if attempt > 0:
log_info(f'[数据库] 查询重试成功,第{attempt+1}次尝试', 'db')
return result
except pymysql.err.OperationalError as e:
if attempt < retry and (e.args[0] == 2013 or e.args[0] == 2006):
log_warning(f'[数据库] 查询连接断开,正在重试(第{attempt+1}次): {e}', 'db')
import time
time.sleep(1)
continue
log_error(f'查询失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
except Exception as e:
log_error(f'查询失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
def execute_update(sql, params=None):
def execute_update(sql, params=None, retry=2):
"""执行更新操作"""
try:
with get_connection() as conn:
with conn.cursor() as cursor:
affected = cursor.execute(sql, params)
return cursor.rowcount
except Exception as e:
log_error(f'更新失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
for attempt in range(retry + 1):
try:
with get_connection() as conn:
with conn.cursor() as cursor:
affected = cursor.execute(sql, params)
if attempt > 0:
log_info(f'[数据库] 更新重试成功,第{attempt+1}次尝试', 'db')
return cursor.rowcount
except pymysql.err.OperationalError as e:
if attempt < retry and (e.args[0] == 2013 or e.args[0] == 2006):
log_warning(f'[数据库] 更新连接断开,正在重试(第{attempt+1}次): {e}', 'db')
import time
time.sleep(1)
continue
log_error(f'更新失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
except Exception as e:
log_error(f'更新失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
def execute_insert(sql, params=None):
def execute_insert(sql, params=None, retry=2):
"""执行插入操作并返回插入ID"""
try:
with get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(sql, params)
last_id = cursor.lastrowid
return last_id
except Exception as e:
log_error(f'插入失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
for attempt in range(retry + 1):
try:
with get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(sql, params)
last_id = cursor.lastrowid
if attempt > 0:
log_info(f'[数据库] 插入重试成功,第{attempt+1}次尝试', 'db')
return last_id
except pymysql.err.OperationalError as e:
if attempt < retry and (e.args[0] == 2013 or e.args[0] == 2006):
log_warning(f'[数据库] 插入连接断开,正在重试(第{attempt+1}次): {e}', 'db')
import time
time.sleep(1)
continue
log_error(f'插入失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise
except Exception as e:
log_error(f'插入失败: {e}\nSQL: {sql}\nParams: {params}', 'db', exc_info=True)
raise

View File

@@ -161,6 +161,27 @@ def init_database_tables():
"custom_service_fee_name VARCHAR(100) NULL COMMENT '自定义服务费报表表头名称'",
'custom_service_fee_name'
)
# 给配置表增加 show_custom_service_fee 字段(是否显示自定义服务费列)
_add_column_if_not_exists(
't_daily_report_config',
"show_custom_service_fee TINYINT NULL COMMENT '是否显示自定义服务费列(0=不显示,1=显示)'",
'show_custom_service_fee'
)
# 给配置表增加 show_total_amount 字段(是否显示实收金额列)
_add_column_if_not_exists(
't_daily_report_config',
"show_total_amount TINYINT NULL COMMENT '是否显示实收金额列(0=不显示,1=显示)'",
'show_total_amount'
)
# 给配置表增加 total_amount_name 字段(实收金额表头名称)
_add_column_if_not_exists(
't_daily_report_config',
"total_amount_name VARCHAR(100) NULL COMMENT '实收金额报表表头名称'",
'total_amount_name'
)
# 数据迁移:给 sort_order 为 NULL 的配置记录按 id 顺序赋值
try:

View File

@@ -169,6 +169,10 @@ FIELD_MAPPING = {
# 数据来源
'data_source': '数据来源',
# 自定义计算字段(虚拟字段)
'custom_service_fee': '自定义服务费(元)',
'total_amount': '实收金额(元)',
}
# 获取字段中文名称

View File

@@ -340,10 +340,14 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
report_date = start_time.strftime('%Y-%m-%d')
delete_old_history(config_id, report_date, config['split_type'], config['split_value'])
# 构建查询SQL - 过滤掉虚拟字段(时段电量等)
# 构建查询SQL - 过滤掉虚拟字段(时段电量、自定义服务费、实收金额等)
# 虚拟字段不是数据库表中的实际字段,需要动态计算
TIME_PERIOD_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity'}
db_fields = [f for f in selected_fields if f not in TIME_PERIOD_FIELDS]
VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'total_amount'}
db_fields = [f for f in selected_fields if f not in VIRTUAL_FIELDS]
# 如果选择了实收金额字段,需要确保查询 charge_elecfee_amount(电费金额)
if 'total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
db_fields.append('charge_elecfee_amount')
# 确保至少有 order_no 字段用于关联分时数据
if 'order_no' not in db_fields:
@@ -501,7 +505,10 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
split_type=config.get('split_type'),
split_value=config.get('split_value'),
custom_service_fee_price=config.get('custom_service_fee_price'),
custom_service_fee_name=config.get('custom_service_fee_name')
custom_service_fee_name=config.get('custom_service_fee_name'),
show_custom_service_fee=config.get('show_custom_service_fee', 0) == 1,
show_total_amount=config.get('show_total_amount', 0) == 1,
total_amount_name=config.get('total_amount_name')
)
log_info(f"[日报生成] Excel文件已生成: {file_path}", 'report')
@@ -591,7 +598,8 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
id_name_maps=None, field_custom_names=None, has_supplement=False,
show_monthly_total=False, config_id=None, report_date=None, sort_order=None,
split_type=None, split_value=None,
custom_service_fee_price=None, custom_service_fee_name=None):
custom_service_fee_price=None, custom_service_fee_name=None,
show_custom_service_fee=False, show_total_amount=False, total_amount_name=None):
"""
生成Excel文件
@@ -711,35 +719,36 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell.alignment = header_alignment
cell.border = thin_border
has_custom_service_fee = custom_service_fee_price is not None and custom_service_fee_price != ''
for col_idx, field in enumerate(selected_fields, 2):
cell = ws.cell(row=header_row, column=col_idx)
if field in field_custom_names and field_custom_names[field]:
if field == 'custom_service_fee':
if custom_service_fee_name and str(custom_service_fee_name).strip():
display_name = str(custom_service_fee_name).strip()
elif has_custom_service_fee:
display_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
else:
display_name = '自定义服务费'
elif field == 'total_amount':
if total_amount_name and str(total_amount_name).strip():
display_name = str(total_amount_name).strip()
else:
display_name = '实收金额'
elif field in field_custom_names and field_custom_names[field]:
display_name = field_custom_names[field]
elif field in id_name_maps and id_name_maps[field]:
display_name = get_field_display_name(field).replace('ID', '')
else:
display_name = get_field_display_name(field)
cell.value = display_name
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_alignment
cell.border = thin_border
# 自定义服务费列表头(如果设置了单价)
has_custom_service_fee = custom_service_fee_price is not None and custom_service_fee_price != ''
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
cell = ws.cell(row=header_row, column=custom_fee_col)
if custom_service_fee_name and str(custom_service_fee_name).strip():
header_name = str(custom_service_fee_name).strip()
else:
header_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
cell.value = header_name
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_alignment
cell.border = thin_border
ws.row_dimensions[header_row].height = 25
# 写入数据
@@ -758,29 +767,44 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
for col_idx, field in enumerate(selected_fields, 2):
cell = ws.cell(row=row_idx, column=col_idx)
value = order.get(field, '')
# 格式化时间字段
if field in ['report_time', 'start_time', 'end_time', 'create_time', 'update_time', 'pay_time']:
if isinstance(value, datetime):
value = value.strftime('%Y-%m-%d %H:%M:%S')
# 将ID转换为名称
if field in id_name_maps and value is not None and value != '':
name_map = id_name_maps[field]
name_value = name_map.get(str(value))
if name_value:
value = name_value
if field == 'custom_service_fee':
if has_custom_service_fee:
charge_degree = float(order.get('charge_degree', 0) or 0)
value = round(charge_degree * float(custom_service_fee_price), 2)
else:
value = ''
elif field == 'total_amount':
actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
if has_custom_service_fee:
charge_degree = float(order.get('charge_degree', 0) or 0)
custom_fee = round(charge_degree * float(custom_service_fee_price), 2)
value = round(actual_money + custom_fee, 2)
else:
value = round(actual_money, 2)
else:
value = order.get(field, '')
# 格式化时间字段
if field in ['report_time', 'start_time', 'end_time', 'create_time', 'update_time', 'pay_time']:
if isinstance(value, datetime):
value = value.strftime('%Y-%m-%d %H:%M:%S')
# 将ID转换为名称
if field in id_name_maps and value is not None and value != '':
name_map = id_name_maps[field]
name_value = name_map.get(str(value))
if name_value:
value = name_value
cell.value = value
cell.border = thin_border
# 数字字段靠右对齐,其他居中或靠左
if field in numeric_fields:
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
cell.alignment = Alignment(horizontal='right', vertical='center')
if isinstance(value, (int, float)):
if field in decimal3_fields:
cell.number_format = '0.000'
cell.number_format = '0.00'
elif field in ['order_no', 'vehicle_no', 'gun_no', 'connector_no']:
cell.alignment = Alignment(horizontal='center', vertical='center')
else:
@@ -790,19 +814,6 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
if is_even:
cell.fill = even_row_fill
# 自定义服务费列(如果设置了单价)
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
cell = ws.cell(row=row_idx, column=custom_fee_col)
charge_degree = float(order.get('charge_degree', 0) or 0)
custom_fee = round(charge_degree * float(custom_service_fee_price), 2)
cell.value = custom_fee
cell.border = thin_border
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
if is_even:
cell.fill = even_row_fill
ws.row_dimensions[row_idx].height = 22
# 写入求和行
@@ -819,25 +830,33 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell = ws.cell(row=sum_row, column=col_idx)
cell.fill = sum_fill
cell.border = thin_border
if field in sum_fields and field in sum_results:
if field == 'custom_service_fee':
if has_custom_service_fee:
total_charge_degree = sum_results.get('charge_degree', 0)
value = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
cell.value = value
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
elif field == 'total_amount':
total_actual_money = sum_results.get('charge_elecfee_amount', 0)
if has_custom_service_fee:
total_charge_degree = sum_results.get('charge_degree', 0)
total_custom_fee = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
value = round(float(total_actual_money) + total_custom_fee, 2)
else:
value = round(float(total_actual_money), 2)
cell.value = value
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
elif field in sum_fields and field in sum_results:
cell.value = sum_results[field]
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.000'
# 自定义服务费合计
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
cell = ws.cell(row=sum_row, column=custom_fee_col)
cell.fill = sum_fill
cell.border = thin_border
total_charge_degree = sum_results.get('charge_degree', 0)
total_custom_fee = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
cell.value = total_custom_fee
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
ws.row_dimensions[sum_row].height = 25
# 写入当月充电量累计总计行(从求和采集表查询,对账后数据)
@@ -881,8 +900,6 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
# 总列数
total_cols = len(selected_fields) + 2
if has_custom_service_fee:
total_cols += 1
# 标题文字
title_text = f'当月累计充电量(共{total_days}天,截止{report_date})'
@@ -935,10 +952,15 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
log_error(f"[日报生成] 写入月度总计时出错: {e}", 'report')
# 调整列宽(中文按2个字符宽度计算)
# 序号列固定宽度
from openpyxl.utils import get_column_letter
# 序号列固定宽度
ws.column_dimensions['A'].width = 8
# 计算所有字段的宽度
col_widths = {}
numeric_cols = []
for col_idx, field in enumerate(selected_fields, 2):
header_name = get_field_display_name(field)
if field in field_custom_names and field_custom_names[field]:
@@ -955,21 +977,25 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell_len = len(cell_str) + cn_count
max_length = max(max_length, cell_len)
from openpyxl.utils import get_column_letter
col_letter = get_column_letter(col_idx)
ws.column_dimensions[col_letter].width = min(max_length + 2, 50)
col_widths[col_idx] = min(max_length + 2, 50)
# 标记数值类型字段(求和类列)
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
numeric_cols.append(col_idx)
# 自定义服务费列宽度
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
if custom_service_fee_name and str(custom_service_fee_name).strip():
header_name = str(custom_service_fee_name).strip()
else:
header_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
cn_count = sum(1 for c in str(header_name) if '\u4e00' <= c <= '\u9fff')
max_length = len(str(header_name)) + cn_count
col_letter = get_column_letter(custom_fee_col)
ws.column_dimensions[col_letter].width = min(max_length + 2, 50)
# 计算数值类型列的最大宽度,使所有求和类列宽度一致
if numeric_cols:
max_numeric_width = max(col_widths[col] for col in numeric_cols)
for col_idx in numeric_cols:
col_letter = get_column_letter(col_idx)
ws.column_dimensions[col_letter].width = max_numeric_width
# 设置非数值类型列的宽度
for col_idx, width in col_widths.items():
if col_idx not in numeric_cols:
col_letter = get_column_letter(col_idx)
ws.column_dimensions[col_letter].width = width
# 冻结首行
ws.freeze_panes = 'A2'

View File

@@ -373,6 +373,72 @@ def add_sum_data(data):
return {'success': False, 'message': str(e)}
def batch_add_sum_data(data):
"""
批量添加求和数据
Args:
data: 求和数据字典,包含 fields 列表
Returns:
dict: 操作结果
"""
try:
fields = data.get('fields', [])
if not fields:
return {'success': False, 'message': '请至少添加一个字段'}
# 获取配置的排序号
sort_order = None
config_id = data.get('config_id')
if config_id:
try:
cfg_result = execute_query(
'SELECT sort_order FROM t_daily_report_config WHERE id = %s LIMIT 1',
(config_id,)
)
if cfg_result and cfg_result[0]['sort_order'] is not None:
sort_order = cfg_result[0]['sort_order']
except Exception:
pass
sql = '''
INSERT INTO t_daily_report_sum_data
(id, report_date, config_id, config_name, split_type, split_value, split_name,
sum_field_key, sum_field_name, sum_value, total_orders, sort_order, data_source, remark,
create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
'''
count = 0
for field in fields:
sum_data_id = int(datetime.now().timestamp() * 1000) + count
params = (
sum_data_id,
data.get('report_date', ''),
data.get('config_id'),
data.get('config_name', ''),
data.get('split_type', ''),
data.get('split_value', ''),
data.get('split_name', ''),
field.get('sum_field_key', ''),
field.get('sum_field_name', ''),
float(field.get('sum_value', 0)),
data.get('total_orders', 0),
sort_order,
'manual',
data.get('remark', '')
)
execute_insert(sql, params)
count += 1
return {'success': True, 'message': f'添加成功,共{count}条记录', 'count': count}
except Exception as e:
import traceback
traceback.print_exc()
return {'success': False, 'message': str(e)}
def update_sum_data(sum_data_id, data):
"""
更新求和数据
@@ -549,16 +615,30 @@ def export_sum_data_to_excel(start_date=None, end_date=None, config_id=None, dat
if where_clauses:
where_sql = 'WHERE ' + ' AND '.join(where_clauses)
# 查询数据(不分页,全量导出)
sql = f'''
SELECT id, report_date, config_id, config_name, split_type, split_value, split_name,
sum_field_key, sum_field_name, sum_value, total_orders, sort_order, data_source, remark,
create_time, update_time
FROM t_daily_report_sum_data
{where_sql}
ORDER BY report_date DESC, sort_order ASC, config_id ASC, sum_field_key ASC
'''
rows = execute_query(sql, tuple(params) if params else ())
# 使用分页查询避免大数据量超时
rows = []
page_size = 500
page = 1
while True:
offset = (page - 1) * page_size
sql = f'''
SELECT id, report_date, config_id, config_name, split_type, split_value, split_name,
sum_field_key, sum_field_name, sum_value, total_orders, sort_order, data_source, remark,
create_time, update_time
FROM t_daily_report_sum_data
{where_sql}
ORDER BY report_date DESC, sort_order ASC, config_id ASC, sum_field_key ASC
LIMIT %s OFFSET %s
'''
query_params = tuple(params) + (page_size, offset)
page_rows = execute_query(sql, query_params)
if not page_rows:
break
rows.extend(page_rows)
if len(page_rows) < page_size:
break
page += 1
# 创建Excel
wb = Workbook()
@@ -723,21 +803,22 @@ def get_monthly_charge_degree_total(config_id=None, month=None, split_type=None,
next_month = month[:5] + str(int(month[5:7]) + 1).zfill(2)
end_date_str = (datetime.strptime(next_month + '-01', '%Y-%m-%d') - timedelta(days=1)).strftime('%Y-%m-%d')
# 构建查询SQL
# 构建查询SQL - 查询所有字段,按日期统计(包括手动添加的数据)
# 使用 MAX(total_orders) 避免同一天多个字段重复计算订单数
sql = """
SELECT
report_date,
SUM(sum_value) as total_degree,
SUM(total_orders) as total_orders
SUM(CASE WHEN sum_field_key = 'charge_degree' THEN sum_value ELSE 0 END) as total_degree,
MAX(total_orders) as total_orders
FROM t_daily_report_sum_data
WHERE sum_field_key = 'charge_degree'
AND report_date LIKE %s
WHERE report_date LIKE %s
AND report_date <= %s
"""
params = [date_prefix + '%', end_date_str]
# 按配置过滤(包含手动添加的数据,手动添加的config_id为NULL)
if config_id:
sql += ' AND config_id = %s'
sql += ' AND (config_id = %s OR config_id IS NULL)'
params.append(config_id)
# 按拆分值过滤(以配置当前拆分为准)