修复求和数据统计的问题
This commit is contained in:
35
check_data.py
Normal file
35
check_data.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import sys
|
||||
sys.path.insert(0, '.')
|
||||
from lib.db import execute_query
|
||||
|
||||
print('=== 检查最近的340路历史记录 ===')
|
||||
history = execute_query('SELECT id, report_date, start_time, end_time, total_orders, sum_results, status FROM t_daily_report_history WHERE config_id = %s ORDER BY report_date DESC LIMIT 5', (1784534746013,))
|
||||
for h in history:
|
||||
print(f"ID: {h['id']}")
|
||||
print(f" 报表日期: {h['report_date']}")
|
||||
print(f" 开始时间: {h['start_time']}")
|
||||
print(f" 结束时间: {h['end_time']}")
|
||||
print(f" 订单数: {h['total_orders']}")
|
||||
print(f" 状态: {h['status']}")
|
||||
print(f" 求和结果: {h['sum_results'][:100]}...")
|
||||
print()
|
||||
|
||||
print('=== 检查7月23日是否有报表生成 ===')
|
||||
history_23 = execute_query('SELECT id, report_date, start_time, end_time, total_orders, status FROM t_daily_report_history WHERE config_id = %s AND report_date = %s', (1784534746013, '2026-07-23'))
|
||||
for h in history_23:
|
||||
print(f"ID: {h['id']}, 报表日期: {h['report_date']}, 状态: {h['status']}, 订单数: {h['total_orders']}")
|
||||
print(f" 开始时间: {h['start_time']}, 结束时间: {h['end_time']}")
|
||||
|
||||
print('\n=== 检查7月14日是否有自动采集的数据 ===')
|
||||
auto_14 = execute_query('SELECT * FROM t_daily_report_sum_data WHERE report_date = %s AND split_value = %s AND data_source = %s', ('2026-07-14', '163425', 'auto'))
|
||||
print(f"7月14日自动采集数据: {len(auto_14)}条")
|
||||
|
||||
print('\n=== 检查7月15日是否有自动采集的数据 ===')
|
||||
auto_15 = execute_query('SELECT * FROM t_daily_report_sum_data WHERE report_date = %s AND split_value = %s AND data_source = %s', ('2026-07-15', '163425', 'auto'))
|
||||
print(f"7月15日自动采集数据: {len(auto_15)}条")
|
||||
|
||||
print('\n=== 查询7月23日的求和数据 ===')
|
||||
sum_23 = execute_query('SELECT * FROM t_daily_report_sum_data WHERE report_date = %s AND split_value = %s', ('2026-07-23', '163425'))
|
||||
print(f"7月23日求和数据: {len(sum_23)}条")
|
||||
for s in sum_23:
|
||||
print(f" ID: {s['id']}, 字段: {s['sum_field_key']}, 值: {s['sum_value']}, 来源: {s['data_source']}")
|
||||
29
check_history.py
Normal file
29
check_history.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from lib.db import execute_query
|
||||
|
||||
# 查询开启特来电合并的配置的历史记录
|
||||
h = execute_query("""
|
||||
SELECT id, config_name, report_date, start_time, end_time, total_orders, status, create_time
|
||||
FROM t_daily_report_history
|
||||
WHERE config_name IN ('华辉121路', '华辉188路', '248路', '华辉251路')
|
||||
AND report_date >= '2026-07-22'
|
||||
ORDER BY create_time DESC
|
||||
""")
|
||||
|
||||
print("===== 特来电合并配置的历史记录 =====")
|
||||
for h_ in h:
|
||||
print(f"{h_['config_name']} | {h_['report_date']} | {h_['start_time']} ~ {h_['end_time']} | {h_['total_orders']}条 | status={h_['status']} | {h_['create_time']}")
|
||||
|
||||
print("\n===== 检查配置的selected_fields是否包含车牌号和VIN =====")
|
||||
configs = execute_query("""
|
||||
SELECT id, config_name, selected_fields
|
||||
FROM t_daily_report_config
|
||||
WHERE config_name IN ('华辉121路', '华辉188路', '248路', '华辉251路')
|
||||
""")
|
||||
|
||||
import json
|
||||
for c in configs:
|
||||
fields = json.loads(c['selected_fields'])
|
||||
has_plate = 'charge_plate_no' in fields
|
||||
has_vin = 'charge_vin' in fields
|
||||
print(f"{c['config_name']}: 车牌号={has_plate}, VIN码={has_vin}")
|
||||
print(f" 字段列表: {fields}")
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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表查询,对账后的数据)
|
||||
|
||||
95
lib/db.py
95
lib/db.py
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -169,6 +169,10 @@ FIELD_MAPPING = {
|
||||
|
||||
# 数据来源
|
||||
'data_source': '数据来源',
|
||||
|
||||
# 自定义计算字段(虚拟字段)
|
||||
'custom_service_fee': '自定义服务费(元)',
|
||||
'total_amount': '实收金额(元)',
|
||||
}
|
||||
|
||||
# 获取字段中文名称
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
# 按拆分值过滤(以配置当前拆分为准)
|
||||
|
||||
@@ -34,7 +34,8 @@ function renderSumDataList(rawList) {
|
||||
});
|
||||
|
||||
// 排序:峰平谷按顺序
|
||||
const fieldOrder = ['sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity'];
|
||||
const fieldOrder = ['sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity',
|
||||
'peak_degree', 'peak_time_degree', 'normal_time_degree', 'valley_time_degree'];
|
||||
sumDataDynamicFields = Object.keys(fieldMap).sort((a, b) => {
|
||||
const idxA = fieldOrder.indexOf(a);
|
||||
const idxB = fieldOrder.indexOf(b);
|
||||
@@ -188,15 +189,15 @@ async function loadSumData(page = 1) {
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', '1');
|
||||
params.append('page_size', '5000');
|
||||
params.append('page', page);
|
||||
params.append('page_size', '50');
|
||||
if (startDate) params.append('start_date', startDate);
|
||||
if (endDate) params.append('end_date', endDate);
|
||||
if (configName) params.append('config_name', configName);
|
||||
if (dataSource) params.append('data_source', dataSource);
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/sum-data?${params.toString()}`);
|
||||
const response = await fetch(`/api/sum-data?${params.toString()}&_t=${Date.now()}`);
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
renderSumDataList(result.data.list || []);
|
||||
@@ -266,9 +267,11 @@ function showAddSumDataModal() {
|
||||
document.getElementById('sum-data-split-type-input').value = 'company_id';
|
||||
document.getElementById('sum-data-split-value-input').value = '';
|
||||
document.getElementById('sum-data-split-name-input').value = '';
|
||||
document.getElementById('sum-data-field-key-input').value = '';
|
||||
document.getElementById('sum-data-field-name-input').value = '';
|
||||
document.getElementById('sum-data-value-input').value = '';
|
||||
document.getElementById('sum-data-charge-degree-input').value = '';
|
||||
document.getElementById('sum-data-peak-degree-input').value = '';
|
||||
document.getElementById('sum-data-peak-time-input').value = '';
|
||||
document.getElementById('sum-data-normal-time-input').value = '';
|
||||
document.getElementById('sum-data-valley-time-input').value = '';
|
||||
document.getElementById('sum-data-total-orders-input').value = 0;
|
||||
document.getElementById('sum-data-remark-input').value = '';
|
||||
document.getElementById('sum-data-modal').classList.add('active');
|
||||
@@ -280,8 +283,11 @@ let editingGroupData = null;
|
||||
|
||||
async function showEditSumDataGroup(ids) {
|
||||
try {
|
||||
// 获取所有选中的记录详情
|
||||
const response = await fetch(`/api/sum-data?page=1&page_size=5000`);
|
||||
const response = await fetch('/api/sum-data/batch-query', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ids: ids })
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
@@ -289,8 +295,7 @@ async function showEditSumDataGroup(ids) {
|
||||
return;
|
||||
}
|
||||
|
||||
const allList = result.data.list || [];
|
||||
const groupItems = allList.filter(item => ids.includes(item.id));
|
||||
const groupItems = result.data || [];
|
||||
|
||||
if (groupItems.length === 0) {
|
||||
alert('未找到该记录');
|
||||
@@ -300,7 +305,6 @@ async function showEditSumDataGroup(ids) {
|
||||
editingGroupIds = ids;
|
||||
editingGroupData = groupItems;
|
||||
|
||||
// 找到充电电量那条作为主记录
|
||||
const chargeItem = groupItems.find(i => i.sum_field_key === 'charge_degree') || groupItems[0];
|
||||
|
||||
document.getElementById('sum-data-modal-title').textContent = '编辑求和数据';
|
||||
@@ -311,11 +315,10 @@ async function showEditSumDataGroup(ids) {
|
||||
document.getElementById('sum-data-split-value-input').value = chargeItem.split_value || '';
|
||||
document.getElementById('sum-data-split-name-input').value = chargeItem.split_name || '';
|
||||
|
||||
// 动态生成字段输入区域
|
||||
renderEditGroupFields(groupItems);
|
||||
|
||||
document.getElementById('sum-data-total-orders-input').value = chargeItem.total_orders || 0;
|
||||
document.getElementById('sum-data-remark-input').value = '';
|
||||
document.getElementById('sum-data-remark-input').value = chargeItem.remark || '';
|
||||
document.getElementById('sum-data-modal').classList.add('active');
|
||||
} catch (error) {
|
||||
alert('加载详情失败: ' + error.message);
|
||||
@@ -324,9 +327,11 @@ async function showEditSumDataGroup(ids) {
|
||||
|
||||
// 渲染编辑分组时的动态字段输入
|
||||
function renderEditGroupFields(items) {
|
||||
const fieldKeyInput = document.getElementById('sum-data-field-key-input');
|
||||
const fieldNameInput = document.getElementById('sum-data-field-name-input');
|
||||
const valueInput = document.getElementById('sum-data-value-input');
|
||||
// 隐藏静态字段输入区域(整个求和字段值区域)
|
||||
const chargeDegreeInput = document.getElementById('sum-data-charge-degree-input');
|
||||
if (chargeDegreeInput) {
|
||||
chargeDegreeInput.parentElement.parentElement.parentElement.style.display = 'none';
|
||||
}
|
||||
|
||||
// 先构造动态字段区域
|
||||
let fieldsHtml = '<div style="margin-bottom: 15px;"><label style="display: block; margin-bottom: 8px; font-weight: 600;">求和字段值:</label>';
|
||||
@@ -363,11 +368,6 @@ function renderEditGroupFields(items) {
|
||||
|
||||
fieldsHtml += '</div></div>';
|
||||
|
||||
// 替换掉原来的单字段输入
|
||||
fieldKeyInput.parentElement.style.display = 'none';
|
||||
fieldNameInput.parentElement.style.display = 'none';
|
||||
valueInput.parentElement.style.display = 'none';
|
||||
|
||||
// 插入到订单数前面
|
||||
const totalOrdersGroup = document.getElementById('sum-data-total-orders-input').parentElement;
|
||||
|
||||
@@ -404,6 +404,8 @@ async function saveSumData() {
|
||||
const fieldId = input.getAttribute('data-field-id');
|
||||
const fieldValue = input.value;
|
||||
|
||||
console.log(`更新字段ID: ${fieldId}, 值: ${fieldValue}`);
|
||||
|
||||
const response = await fetch(`/api/sum-data/${fieldId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -414,6 +416,7 @@ async function saveSumData() {
|
||||
})
|
||||
});
|
||||
const result = await response.json();
|
||||
console.log(`更新结果: ${JSON.stringify(result)}`);
|
||||
if (result.success) successCount++;
|
||||
}
|
||||
|
||||
@@ -427,34 +430,73 @@ async function saveSumData() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 单条新增模式
|
||||
// 单条新增模式(批量添加多个字段)
|
||||
const fieldsData = [];
|
||||
|
||||
const chargeDegree = document.getElementById('sum-data-charge-degree-input').value;
|
||||
const peakDegree = document.getElementById('sum-data-peak-degree-input').value;
|
||||
const peakTime = document.getElementById('sum-data-peak-time-input').value;
|
||||
const normalTime = document.getElementById('sum-data-normal-time-input').value;
|
||||
const valleyTime = document.getElementById('sum-data-valley-time-input').value;
|
||||
|
||||
if (!chargeDegree && !peakDegree && !peakTime && !normalTime && !valleyTime) {
|
||||
alert('请至少输入一个求和字段值');
|
||||
return;
|
||||
}
|
||||
|
||||
if (chargeDegree) {
|
||||
fieldsData.push({
|
||||
sum_field_key: 'charge_degree',
|
||||
sum_field_name: '充电电量(kWh)',
|
||||
sum_value: chargeDegree
|
||||
});
|
||||
}
|
||||
if (peakDegree) {
|
||||
fieldsData.push({
|
||||
sum_field_key: 'peak_degree',
|
||||
sum_field_name: '尖时电量(kWh)',
|
||||
sum_value: peakDegree
|
||||
});
|
||||
}
|
||||
if (peakTime) {
|
||||
fieldsData.push({
|
||||
sum_field_key: 'peak_time_degree',
|
||||
sum_field_name: '峰时电量(kWh)',
|
||||
sum_value: peakTime
|
||||
});
|
||||
}
|
||||
if (normalTime) {
|
||||
fieldsData.push({
|
||||
sum_field_key: 'normal_time_degree',
|
||||
sum_field_name: '平时电量(kWh)',
|
||||
sum_value: normalTime
|
||||
});
|
||||
}
|
||||
if (valleyTime) {
|
||||
fieldsData.push({
|
||||
sum_field_key: 'valley_time_degree',
|
||||
sum_field_name: '谷时电量(kWh)',
|
||||
sum_value: valleyTime
|
||||
});
|
||||
}
|
||||
|
||||
const data = {
|
||||
report_date: document.getElementById('sum-data-report-date-input').value,
|
||||
config_name: document.getElementById('sum-data-config-name-input').value,
|
||||
split_type: document.getElementById('sum-data-split-type-input').value,
|
||||
split_value: document.getElementById('sum-data-split-value-input').value,
|
||||
split_name: document.getElementById('sum-data-split-name-input').value,
|
||||
sum_field_key: document.getElementById('sum-data-field-key-input').value,
|
||||
sum_field_name: document.getElementById('sum-data-field-name-input').value,
|
||||
sum_value: document.getElementById('sum-data-value-input').value,
|
||||
total_orders: totalOrders,
|
||||
remark: remark
|
||||
remark: remark,
|
||||
fields: fieldsData
|
||||
};
|
||||
|
||||
if (!data.report_date) {
|
||||
alert('请选择报表日期');
|
||||
return;
|
||||
}
|
||||
if (!data.sum_field_key) {
|
||||
alert('请输入求和字段键名');
|
||||
return;
|
||||
}
|
||||
if (data.sum_value === '' || data.sum_value === null) {
|
||||
alert('请输入求和值');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch('/api/sum-data', {
|
||||
const response = await fetch('/api/sum-data/batch-add', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
@@ -478,12 +520,22 @@ function closeSumDataModal() {
|
||||
document.getElementById('sum-data-modal').classList.remove('active');
|
||||
editingGroupIds = [];
|
||||
editingGroupData = null;
|
||||
// 恢复单字段输入的显示
|
||||
document.querySelector('#sum-data-field-key-input').parentElement.style.display = '';
|
||||
document.querySelector('#sum-data-field-name-input').parentElement.style.display = '';
|
||||
document.querySelector('#sum-data-value-input').parentElement.style.display = '';
|
||||
// 清空新增字段输入
|
||||
document.getElementById('sum-data-charge-degree-input').value = '';
|
||||
document.getElementById('sum-data-peak-degree-input').value = '';
|
||||
document.getElementById('sum-data-peak-time-input').value = '';
|
||||
document.getElementById('sum-data-normal-time-input').value = '';
|
||||
document.getElementById('sum-data-valley-time-input').value = '';
|
||||
// 恢复静态字段区域显示
|
||||
const chargeDegreeInput = document.getElementById('sum-data-charge-degree-input');
|
||||
if (chargeDegreeInput) {
|
||||
chargeDegreeInput.parentElement.parentElement.parentElement.style.display = '';
|
||||
}
|
||||
// 清理动态区域
|
||||
const dynamicArea = document.getElementById('sum-data-dynamic-fields');
|
||||
if (dynamicArea) dynamicArea.innerHTML = '';
|
||||
if (dynamicArea) {
|
||||
dynamicArea.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除单条(分组)
|
||||
|
||||
@@ -297,6 +297,8 @@
|
||||
<input type="text" id="custom-service-fee-name" class="form-control" placeholder="留空则使用默认名称(如:自定义服务费(0.8元/kWh))" style="width: 300px;">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label>分时段电量统计:</label>
|
||||
<div id="time-period-editor">
|
||||
@@ -364,18 +366,29 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>求和字段键名:</label>
|
||||
<input type="text" id="sum-data-field-key-input" class="form-control" placeholder="例如:charge_degree">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>求和字段名称:</label>
|
||||
<input type="text" id="sum-data-field-name-input" class="form-control" placeholder="例如:充电电量(kWh)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>求和值:</label>
|
||||
<input type="number" step="0.001" id="sum-data-value-input" class="form-control" placeholder="请输入求和值">
|
||||
<label>求和字段值:</label>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>充电电量(kWh) <span style="color: #dc3545;">*</span></label>
|
||||
<input type="number" step="0.001" id="sum-data-charge-degree-input" class="form-control" placeholder="充电电量">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>尖时电量(kWh)</label>
|
||||
<input type="number" step="0.001" id="sum-data-peak-degree-input" class="form-control" placeholder="尖时电量">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>峰时电量(kWh)</label>
|
||||
<input type="number" step="0.001" id="sum-data-peak-time-input" class="form-control" placeholder="峰时电量">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>平时电量(kWh)</label>
|
||||
<input type="number" step="0.001" id="sum-data-normal-time-input" class="form-control" placeholder="平时电量">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label>谷时电量(kWh)</label>
|
||||
<input type="number" step="0.001" id="sum-data-valley-time-input" class="form-control" placeholder="谷时电量">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
Reference in New Issue
Block a user