悠修复自定义实收金额和求和采集功能增强
This commit is contained in:
@@ -27,6 +27,9 @@ sum_data_bp = Blueprint('sum_data', __name__, url_prefix='/api')
|
||||
# 认证蓝图
|
||||
from .auth_api import auth_bp
|
||||
|
||||
# 全局配置蓝图
|
||||
from .global_config_api import global_config_api
|
||||
|
||||
# 导入各模块的路由
|
||||
from . import config_api, entity_api, field_api, report_api, init_api, download_api, sum_data_api
|
||||
|
||||
@@ -41,3 +44,4 @@ def register_blueprints(app):
|
||||
app.register_blueprint(download_bp)
|
||||
app.register_blueprint(sum_data_bp)
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(global_config_api)
|
||||
|
||||
36
lib/api/global_config_api.py
Normal file
36
lib/api/global_config_api.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from flask import Blueprint, jsonify, request
|
||||
from lib.db import execute_query, execute_update
|
||||
import json
|
||||
|
||||
global_config_api = Blueprint('global_config_api', __name__)
|
||||
|
||||
|
||||
@global_config_api.route('/api/global-config/sum-data-fields', methods=['GET'])
|
||||
def get_sum_data_fields():
|
||||
"""获取求和数据采集字段配置"""
|
||||
try:
|
||||
result = execute_query("SELECT sum_data_fields FROM t_daily_report_global_config WHERE id = 1")
|
||||
if result and result[0]['sum_data_fields']:
|
||||
fields = json.loads(result[0]['sum_data_fields'])
|
||||
return jsonify({'success': True, 'data': fields})
|
||||
return jsonify({'success': True, 'data': []})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@global_config_api.route('/api/global-config/sum-data-fields', methods=['POST'])
|
||||
def save_sum_data_fields():
|
||||
"""保存求和数据采集字段配置"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
fields = data.get('sum_data_fields', [])
|
||||
fields_json = json.dumps(fields)
|
||||
|
||||
execute_update(
|
||||
"UPDATE t_daily_report_global_config SET sum_data_fields = %s, update_time = NOW() WHERE id = 1",
|
||||
(fields_json,)
|
||||
)
|
||||
|
||||
return jsonify({'success': True, 'message': '配置保存成功'})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
@@ -182,6 +182,33 @@ def init_database_tables():
|
||||
"total_amount_name VARCHAR(100) NULL COMMENT '实收金额报表表头名称'",
|
||||
'total_amount_name'
|
||||
)
|
||||
|
||||
# 创建全局配置表
|
||||
create_global_config_table = """
|
||||
CREATE TABLE IF NOT EXISTS t_daily_report_global_config (
|
||||
id BIGINT NOT NULL DEFAULT 1 COMMENT '主键(固定为1)',
|
||||
sum_data_fields VARCHAR(1000) NULL COMMENT '求和数据采集和显示字段列表(JSON格式)',
|
||||
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_global_config_table)
|
||||
_set_table_comment('t_daily_report_global_config', '日报全局配置表')
|
||||
log_info("[数据库] t_daily_report_global_config 表已就绪", 'db_init')
|
||||
|
||||
# 初始化全局配置记录(如果不存在)
|
||||
try:
|
||||
exists = execute_query("SELECT COUNT(*) as cnt FROM t_daily_report_global_config WHERE id = 1")
|
||||
if not exists or exists[0]['cnt'] == 0:
|
||||
execute_update(
|
||||
"INSERT INTO t_daily_report_global_config (id, create_time, update_time) VALUES (1, NOW(), NOW())"
|
||||
)
|
||||
log_info("[数据库] 初始化全局配置记录成功", 'db_init')
|
||||
except Exception as e:
|
||||
log_warning(f"[数据库] 初始化全局配置记录失败: {e}", 'db_init')
|
||||
|
||||
# 数据迁移:给 sort_order 为 NULL 的配置记录按 id 顺序赋值
|
||||
try:
|
||||
|
||||
@@ -172,7 +172,7 @@ FIELD_MAPPING = {
|
||||
|
||||
# 自定义计算字段(虚拟字段)
|
||||
'custom_service_fee': '自定义服务费(元)',
|
||||
'total_amount': '实收金额(元)',
|
||||
'custom_total_amount': '自定义实收总金额(元)',
|
||||
|
||||
# 车辆信息(从 t_car 表关联)
|
||||
'car_bus_path': '公交线路',
|
||||
|
||||
@@ -319,6 +319,16 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
|
||||
selected_fields = json.loads(config['selected_fields'])
|
||||
sum_fields = json.loads(config['sum_fields']) if config['sum_fields'] else []
|
||||
|
||||
# 根据配置自动添加虚拟字段到选中字段列表
|
||||
show_custom_service_fee = config.get('show_custom_service_fee', 0) == 1
|
||||
show_total_amount = config.get('show_total_amount', 0) == 1
|
||||
|
||||
if show_custom_service_fee and 'custom_service_fee' not in selected_fields:
|
||||
selected_fields.append('custom_service_fee')
|
||||
|
||||
if show_total_amount and 'custom_total_amount' not in selected_fields:
|
||||
selected_fields.append('custom_total_amount')
|
||||
|
||||
# 设置时间范围
|
||||
if not start_time or not end_time:
|
||||
now = get_beijing_time()
|
||||
@@ -340,17 +350,18 @@ 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 - 过滤掉虚拟字段(时段电量、自定义服务费、自定义实收总金额、车辆信息等)
|
||||
# 虚拟字段不是数据库表中的实际字段,需要动态计算或关联查询
|
||||
VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'total_amount', 'car_bus_path', 'car_sn'}
|
||||
# 注意:total_amount 是旧版虚拟字段名,为了向后兼容也需要包含在内
|
||||
VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'custom_total_amount', 'total_amount', 'car_bus_path', 'car_sn'}
|
||||
db_fields = [f for f in selected_fields if f not in VIRTUAL_FIELDS]
|
||||
|
||||
# 确保 charge_degree 总是被查询(用于计算总电量)
|
||||
if 'charge_degree' not in db_fields:
|
||||
db_fields.append('charge_degree')
|
||||
|
||||
# 如果选择了实收金额字段,需要确保查询 charge_elecfee_amount(电费金额)
|
||||
if 'total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
|
||||
# 如果选择了自定义实收总金额字段,需要确保查询 charge_elecfee_amount(电费金额)
|
||||
if 'custom_total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
|
||||
db_fields.append('charge_elecfee_amount')
|
||||
|
||||
# 确保至少有 order_no 字段用于关联分时数据
|
||||
@@ -506,6 +517,31 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
|
||||
|
||||
log_info(f"[日报生成] 已计算 {len(time_period_electricity)} 条订单的分时段电量", 'report')
|
||||
|
||||
# 计算虚拟字段(自定义服务费、自定义实收总金额)并添加到订单数据中
|
||||
# 这样求和数据才能正确计算这些字段的总和
|
||||
has_custom_service_fee = config.get('custom_service_fee_price') is not None and str(config.get('custom_service_fee_price', '')).strip() != ''
|
||||
if has_custom_service_fee:
|
||||
custom_service_fee_price = float(config['custom_service_fee_price'])
|
||||
for order in orders:
|
||||
charge_degree = float(order.get('charge_degree', 0) or 0)
|
||||
custom_service_fee = round(charge_degree * custom_service_fee_price, 2)
|
||||
order['custom_service_fee'] = custom_service_fee
|
||||
|
||||
# 计算自定义实收总金额(实收电费 + 自定义服务费)
|
||||
actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
|
||||
custom_total_amount = round(actual_money + custom_service_fee, 2)
|
||||
order['custom_total_amount'] = custom_total_amount
|
||||
# 兼容旧版字段名 total_amount
|
||||
order['total_amount'] = custom_total_amount
|
||||
else:
|
||||
# 如果没有自定义服务费,自定义实收总金额 = 实收电费
|
||||
for order in orders:
|
||||
actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
|
||||
custom_total_amount = round(actual_money, 2)
|
||||
order['custom_total_amount'] = custom_total_amount
|
||||
# 兼容旧版字段名 total_amount
|
||||
order['total_amount'] = custom_total_amount
|
||||
|
||||
# 计算求和(保留三位小数)
|
||||
sum_results = {}
|
||||
for field in sum_fields:
|
||||
@@ -523,6 +559,27 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
|
||||
sum_results['charge_degree'] = round(total_charge_degree, 3)
|
||||
log_info(f"[日报生成] 强制采集充电电量: {sum_results['charge_degree']} kWh", 'report')
|
||||
|
||||
# 强制采集实收电费(charge_elecfee_amount),用于计算自定义实收总金额的求和
|
||||
if 'charge_elecfee_amount' not in sum_results and orders:
|
||||
has_charge_elecfee_amount = any('charge_elecfee_amount' in order for order in orders)
|
||||
if has_charge_elecfee_amount:
|
||||
total_charge_elecfee_amount = sum(float(order.get('charge_elecfee_amount', 0) or 0) for order in orders)
|
||||
sum_results['charge_elecfee_amount'] = round(total_charge_elecfee_amount, 3)
|
||||
|
||||
# 强制采集自定义服务费(custom_service_fee),直接使用订单中已计算好的值求和
|
||||
if 'custom_service_fee' not in sum_results and orders:
|
||||
has_custom_service_fee_field = any('custom_service_fee' in order for order in orders)
|
||||
if has_custom_service_fee_field:
|
||||
total_custom_service_fee = sum(float(order.get('custom_service_fee', 0) or 0) for order in orders)
|
||||
sum_results['custom_service_fee'] = round(total_custom_service_fee, 2)
|
||||
|
||||
# 强制采集自定义实收总金额(custom_total_amount),直接使用订单中已计算好的值求和
|
||||
if 'custom_total_amount' not in sum_results and orders:
|
||||
has_custom_total_amount = any('custom_total_amount' in order for order in orders)
|
||||
if has_custom_total_amount:
|
||||
total_custom_total_amount = sum(float(order.get('custom_total_amount', 0) or 0) for order in orders)
|
||||
sum_results['custom_total_amount'] = round(total_custom_total_amount, 2)
|
||||
|
||||
# 构建ID到名称的映射
|
||||
id_name_maps = build_id_to_name_map(orders, selected_fields)
|
||||
|
||||
@@ -772,11 +829,11 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
display_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
|
||||
else:
|
||||
display_name = '自定义服务费'
|
||||
elif field == 'total_amount':
|
||||
elif field == 'custom_total_amount' or field == 'total_amount':
|
||||
if total_amount_name and str(total_amount_name).strip():
|
||||
display_name = str(total_amount_name).strip()
|
||||
else:
|
||||
display_name = '实收金额'
|
||||
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]:
|
||||
@@ -810,19 +867,11 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
cell = ws.cell(row=row_idx, column=col_idx)
|
||||
|
||||
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)
|
||||
# 直接使用订单数据中已计算好的值
|
||||
value = order.get('custom_service_fee', '')
|
||||
elif field == 'custom_total_amount' or field == 'total_amount':
|
||||
# 直接使用订单数据中已计算好的值(兼容旧版字段名 total_amount)
|
||||
value = order.get('custom_total_amount', order.get('total_amount', ''))
|
||||
else:
|
||||
value = order.get(field, '')
|
||||
|
||||
@@ -842,7 +891,7 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
cell.border = thin_border
|
||||
|
||||
# 数字字段靠右对齐,其他居中或靠左
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'custom_total_amount', 'total_amount']:
|
||||
cell.alignment = Alignment(horizontal='right', vertical='center')
|
||||
if isinstance(value, (int, float)):
|
||||
cell.number_format = '0.00'
|
||||
@@ -873,21 +922,30 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
cell.border = thin_border
|
||||
|
||||
if field == 'custom_service_fee':
|
||||
if has_custom_service_fee:
|
||||
# 直接使用订单中已计算好的值求和,确保与数据行一致
|
||||
if 'custom_service_fee' in sum_results:
|
||||
value = sum_results['custom_service_fee']
|
||||
elif 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)
|
||||
value = ''
|
||||
cell.value = value
|
||||
cell.font = sum_font
|
||||
cell.alignment = Alignment(horizontal='right', vertical='center')
|
||||
cell.number_format = '0.00'
|
||||
elif field == 'custom_total_amount' or field == 'total_amount':
|
||||
# 直接使用订单中已计算好的值求和,确保与数据行一致
|
||||
if 'custom_total_amount' in sum_results:
|
||||
value = sum_results['custom_total_amount']
|
||||
else:
|
||||
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')
|
||||
@@ -1022,7 +1080,7 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
col_widths[col_idx] = min(max_length + 2, 50)
|
||||
|
||||
# 标记数值类型字段(求和类列)
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'custom_total_amount', 'total_amount']:
|
||||
numeric_cols.append(col_idx)
|
||||
|
||||
# 计算数值类型列的最大宽度,使所有求和类列宽度一致
|
||||
|
||||
@@ -51,6 +51,17 @@ def collect_sum_data_from_history(history_id=None, start_date=None, end_date=Non
|
||||
skipped_count = 0
|
||||
config_cache = {} # 缓存配置的排序号和自定义服务费单价
|
||||
|
||||
# 获取全局配置的求和数据采集字段
|
||||
sum_data_fields = None
|
||||
try:
|
||||
global_config_result = execute_query(
|
||||
'SELECT sum_data_fields FROM t_daily_report_global_config WHERE id = 1 LIMIT 1'
|
||||
)
|
||||
if global_config_result and global_config_result[0].get('sum_data_fields'):
|
||||
sum_data_fields = json.loads(global_config_result[0]['sum_data_fields'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for history in history_list:
|
||||
sum_results = history.get('sum_results')
|
||||
|
||||
@@ -115,6 +126,13 @@ def collect_sum_data_from_history(history_id=None, start_date=None, end_date=Non
|
||||
(history['report_date'], history['config_id'], history['split_value'])
|
||||
)
|
||||
|
||||
# 根据配置过滤采集字段
|
||||
# 如果配置了 sum_data_fields,则只采集这些字段(charge_degree 始终采集)
|
||||
if sum_data_fields and isinstance(sum_data_fields, list):
|
||||
filtered_fields = set(sum_data_fields)
|
||||
filtered_fields.add('charge_degree') # 充电电量始终采集
|
||||
sum_results = {k: v for k, v in sum_results.items() if k in filtered_fields}
|
||||
|
||||
# 逐条插入求和字段数据
|
||||
for field_key, field_value in sum_results.items():
|
||||
sum_data_id = int(datetime.now().timestamp() * 1000000) + collected_count
|
||||
@@ -179,6 +197,30 @@ def collect_sum_data_from_history(history_id=None, start_date=None, end_date=Non
|
||||
)
|
||||
execute_insert(sql, params)
|
||||
collected_count += 1
|
||||
|
||||
# 计算自定义实收总金额(实收电费 + 自定义服务费)
|
||||
# 实收电费从 sum_results 中获取(charge_elecfee_amount)
|
||||
charge_elecfee_amount = float(sum_results.get('charge_elecfee_amount', 0) or 0)
|
||||
custom_total_amount = round(charge_elecfee_amount + custom_service_fee, 2)
|
||||
sum_data_id = int(datetime.now().timestamp() * 1000000) + collected_count
|
||||
params = (
|
||||
sum_data_id,
|
||||
history['report_date'],
|
||||
history['config_id'],
|
||||
history.get('config_name', ''),
|
||||
history.get('split_type', ''),
|
||||
history.get('split_value', ''),
|
||||
history.get('split_name', ''),
|
||||
'custom_total_amount',
|
||||
'自定义实收总金额',
|
||||
custom_total_amount,
|
||||
history.get('total_orders', 0),
|
||||
sort_order,
|
||||
'auto',
|
||||
f'自动计算:实收电费{charge_elecfee_amount}元 + 自定义服务费{custom_service_fee}元'
|
||||
)
|
||||
execute_insert(sql, params)
|
||||
collected_count += 1
|
||||
except Exception as fee_error:
|
||||
log_error(f"[采集] 计算自定义服务费失败: {fee_error}", 'sum_data')
|
||||
|
||||
|
||||
@@ -97,6 +97,18 @@ function showCreateModal() {
|
||||
const customServiceFeeNameInput = document.getElementById('custom-service-fee-name');
|
||||
if (customServiceFeeNameInput) customServiceFeeNameInput.value = '';
|
||||
|
||||
// 重置显示自定义服务费字段开关
|
||||
const showCustomServiceFeeInput = document.getElementById('show-custom-service-fee');
|
||||
if (showCustomServiceFeeInput) showCustomServiceFeeInput.checked = false;
|
||||
|
||||
// 重置显示实收总金额字段开关
|
||||
const showTotalAmountInput = document.getElementById('show-total-amount');
|
||||
if (showTotalAmountInput) showTotalAmountInput.checked = false;
|
||||
|
||||
// 重置实收总金额表头名称
|
||||
const totalAmountNameInput = document.getElementById('total-amount-name');
|
||||
if (totalAmountNameInput) totalAmountNameInput.value = '';
|
||||
|
||||
document.getElementById('config-modal').classList.add('active');
|
||||
}
|
||||
|
||||
@@ -126,7 +138,9 @@ const SUMMABLE_FIELD_KEYS = [
|
||||
'invoice_fee', 'activity_electric_fee', 'activity_service_fee', 'activity_total_fee',
|
||||
'total_money',
|
||||
// 分时段电量
|
||||
'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity'
|
||||
'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity',
|
||||
// 虚拟字段(自定义计算字段)
|
||||
'custom_service_fee', 'custom_total_amount'
|
||||
];
|
||||
|
||||
// 渲染字段列表
|
||||
@@ -299,6 +313,44 @@ function updateFieldIndexes() {
|
||||
});
|
||||
}
|
||||
|
||||
// 虚拟字段开关切换事件
|
||||
function onVirtualFieldToggle(cb) {
|
||||
const fieldKey = cb.id === 'show-custom-service-fee' ? 'custom_service_fee' : 'custom_total_amount';
|
||||
const isChecked = cb.checked;
|
||||
|
||||
// 获取当前字段顺序
|
||||
const currentOrder = getSelectedFieldsOrder();
|
||||
|
||||
let newOrder = [];
|
||||
if (isChecked) {
|
||||
// 勾选:添加字段到列表末尾
|
||||
if (!currentOrder.includes(fieldKey)) {
|
||||
newOrder = [...currentOrder, fieldKey];
|
||||
} else {
|
||||
newOrder = currentOrder;
|
||||
}
|
||||
} else {
|
||||
// 取消勾选:从列表中移除字段
|
||||
newOrder = currentOrder.filter(f => f !== fieldKey);
|
||||
}
|
||||
|
||||
// 获取当前求和字段选择状态
|
||||
const sumFieldsList = document.getElementById('sum-fields-list');
|
||||
const currentSumFields = sumFieldsList ? Array.from(sumFieldsList.querySelectorAll('input:checked')).map(c => c.value) : [];
|
||||
|
||||
// 更新字段顺序列表和求和字段列表
|
||||
refreshSelectedFieldsOrder(newOrder);
|
||||
refreshSumFieldsList(newOrder, currentSumFields);
|
||||
|
||||
// 如果勾选了字段,更新字段列表中的checkbox状态(保持一致)
|
||||
const fieldList = document.getElementById('field-list');
|
||||
const fieldCb = fieldList?.querySelector(`input[value="${fieldKey}"]`);
|
||||
if (fieldCb) {
|
||||
fieldCb.checked = isChecked;
|
||||
fieldCb.closest('.checkbox-item')?.classList.toggle('checked', isChecked);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前字段顺序
|
||||
function getSelectedFieldsOrder() {
|
||||
const orderList = document.getElementById('selected-fields-order');
|
||||
@@ -548,7 +600,17 @@ async function saveConfig() {
|
||||
// 获取自定义服务费表头名称
|
||||
const customServiceFeeNameInput = document.getElementById('custom-service-fee-name');
|
||||
const customServiceFeeName = customServiceFeeNameInput?.value.trim() || null;
|
||||
|
||||
|
||||
// 获取显示自定义服务费字段开关
|
||||
const showCustomServiceFee = document.getElementById('show-custom-service-fee')?.checked || false;
|
||||
|
||||
// 获取显示实收总金额字段开关
|
||||
const showTotalAmount = document.getElementById('show-total-amount')?.checked || false;
|
||||
|
||||
// 获取实收总金额表头名称
|
||||
const totalAmountNameInput = document.getElementById('total-amount-name');
|
||||
const totalAmountName = totalAmountNameInput?.value.trim() || null;
|
||||
|
||||
if (!configName || !splitType || !splitValue) {
|
||||
alert('请填写所有必填字段');
|
||||
return;
|
||||
@@ -590,7 +652,10 @@ async function saveConfig() {
|
||||
field_custom_names: fieldCustomNamesData,
|
||||
show_monthly_total: showMonthlyTotal,
|
||||
custom_service_fee_price: customServiceFeePrice,
|
||||
custom_service_fee_name: customServiceFeeName
|
||||
custom_service_fee_name: customServiceFeeName,
|
||||
show_custom_service_fee: showCustomServiceFee,
|
||||
show_total_amount: showTotalAmount,
|
||||
total_amount_name: totalAmountName
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -683,6 +748,24 @@ async function editConfig(configId) {
|
||||
customServiceFeeNameInput.value = config.custom_service_fee_name || '';
|
||||
}
|
||||
|
||||
// 加载显示自定义服务费字段开关
|
||||
const showCustomServiceFeeInput = document.getElementById('show-custom-service-fee');
|
||||
if (showCustomServiceFeeInput) {
|
||||
showCustomServiceFeeInput.checked = config.show_custom_service_fee === 1;
|
||||
}
|
||||
|
||||
// 加载显示实收总金额字段开关
|
||||
const showTotalAmountInput = document.getElementById('show-total-amount');
|
||||
if (showTotalAmountInput) {
|
||||
showTotalAmountInput.checked = config.show_total_amount === 1;
|
||||
}
|
||||
|
||||
// 加载实收总金额表头名称
|
||||
const totalAmountNameInput = document.getElementById('total-amount-name');
|
||||
if (totalAmountNameInput) {
|
||||
totalAmountNameInput.value = config.total_amount_name || '';
|
||||
}
|
||||
|
||||
document.getElementById('config-modal').classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,20 @@ function renderSumDataList(rawList) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 收集所有动态求和字段(除了充电电量 charge_degree)
|
||||
// 获取全局配置的允许显示字段(charge_degree 始终显示)
|
||||
// 如果没有配置,则显示所有字段(向后兼容)
|
||||
const hasConfig = sumDataConfigFields && sumDataConfigFields.length > 0;
|
||||
const allowedFields = hasConfig ? new Set(sumDataConfigFields) : null;
|
||||
|
||||
// 收集所有动态求和字段(除了充电电量 charge_degree,且只收集允许显示的字段)
|
||||
const fieldMap = {};
|
||||
rawList.forEach(item => {
|
||||
const key = item.sum_field_key;
|
||||
if (key && key !== 'charge_degree' && !fieldMap[key]) {
|
||||
fieldMap[key] = item.sum_field_name || key;
|
||||
// 如果配置了允许字段,则只收集允许的字段;否则收集所有字段
|
||||
if (!hasConfig || allowedFields.has(key)) {
|
||||
fieldMap[key] = item.sum_field_name || key;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -186,6 +194,17 @@ async function loadSumData(page = 1) {
|
||||
if (listTbody) {
|
||||
listTbody.innerHTML = '<tr><td colspan="12" class="loading">加载中...</td></tr>';
|
||||
}
|
||||
|
||||
// 先加载全局配置
|
||||
try {
|
||||
const configResponse = await fetch('/api/global-config/sum-data-fields?_t=' + Date.now());
|
||||
const configResult = await configResponse.json();
|
||||
if (configResult.success) {
|
||||
sumDataConfigFields = configResult.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('加载全局配置失败:', error);
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('page_size', '1000');
|
||||
@@ -649,3 +668,109 @@ async function exportSumData() {
|
||||
alert('导出失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 求和数据可配置的采集字段列表
|
||||
const SUM_DATA_AVAILABLE_FIELDS = [
|
||||
{ key: 'sharp_electricity', name: '尖时电量(kWh)' },
|
||||
{ key: 'peak_electricity', name: '峰时电量(kWh)' },
|
||||
{ key: 'flat_electricity', name: '平时电量(kWh)' },
|
||||
{ key: 'valley_electricity', name: '谷时电量(kWh)' },
|
||||
{ key: 'charge_elecfee_amount', name: '实收电费(元)' },
|
||||
{ key: 'charge_servicefee_amount', name: '实收服务费(元)' },
|
||||
{ key: 'charge_amount', name: '实收总金额(元)' },
|
||||
{ key: 'charge_frequency', name: '充电次数' },
|
||||
{ key: 'custom_service_fee', name: '自定义服务费(元)' },
|
||||
{ key: 'custom_total_amount', name: '自定义实收总金额(元)' }
|
||||
];
|
||||
|
||||
let sumDataConfigFields = [];
|
||||
|
||||
// 初始化全局配置
|
||||
async function initSumDataConfig() {
|
||||
try {
|
||||
const response = await fetch('/api/global-config/sum-data-fields?_t=' + Date.now());
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
sumDataConfigFields = result.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('初始化全局配置失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时初始化
|
||||
document.addEventListener('DOMContentLoaded', initSumDataConfig);
|
||||
|
||||
// 显示求和数据全局配置模态框
|
||||
async function showSumDataConfigModal() {
|
||||
const modal = document.getElementById('sum-data-config-modal');
|
||||
const fieldsList = document.getElementById('sum-data-config-fields-list');
|
||||
fieldsList.innerHTML = '<div class="loading">加载中...</div>';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/global-config/sum-data-fields?_t=' + Date.now());
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
sumDataConfigFields = result.data || [];
|
||||
renderSumDataConfigFields(sumDataConfigFields);
|
||||
} else {
|
||||
fieldsList.innerHTML = '<div class="empty">加载失败</div>';
|
||||
}
|
||||
} catch (error) {
|
||||
fieldsList.innerHTML = '<div class="empty">加载失败: ' + error.message + '</div>';
|
||||
}
|
||||
|
||||
modal.classList.add('active');
|
||||
}
|
||||
|
||||
// 关闭求和数据全局配置模态框
|
||||
function closeSumDataConfigModal() {
|
||||
document.getElementById('sum-data-config-modal').classList.remove('active');
|
||||
}
|
||||
|
||||
// 渲染求和数据配置字段列表
|
||||
function renderSumDataConfigFields(selectedFields) {
|
||||
const fieldsList = document.getElementById('sum-data-config-fields-list');
|
||||
fieldsList.innerHTML = SUM_DATA_AVAILABLE_FIELDS.map(field => `
|
||||
<div class="checkbox-item ${selectedFields.includes(field.key) ? 'checked' : ''}" onclick="toggleSumDataConfigField(this)">
|
||||
<input type="checkbox" value="${field.key}"
|
||||
${selectedFields.includes(field.key) ? 'checked' : ''}>
|
||||
<label>${field.name} <span class="field-key-name">(${field.key})</span></label>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 切换求和数据配置字段选中状态
|
||||
function toggleSumDataConfigField(item) {
|
||||
const checkbox = item.querySelector('input[type="checkbox"]');
|
||||
checkbox.checked = !checkbox.checked;
|
||||
item.classList.toggle('checked', checkbox.checked);
|
||||
}
|
||||
|
||||
// 保存求和数据全局配置
|
||||
async function saveSumDataConfig() {
|
||||
const checkboxes = document.querySelectorAll('#sum-data-config-fields-list input[type="checkbox"]');
|
||||
const selectedFields = Array.from(checkboxes)
|
||||
.filter(cb => cb.checked)
|
||||
.map(cb => cb.value);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/global-config/sum-data-fields', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ sum_data_fields: selectedFields })
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('配置保存成功');
|
||||
sumDataConfigFields = selectedFields;
|
||||
closeSumDataConfigModal();
|
||||
loadSumData(sumDataCurrentPage);
|
||||
} else {
|
||||
alert('保存失败: ' + (result.message || '未知错误'));
|
||||
}
|
||||
} catch (error) {
|
||||
alert('保存失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@
|
||||
<button class="btn btn-success" onclick="showAddSumDataModal()">手动添加</button>
|
||||
<button class="btn btn-warning" onclick="collectSumDataFromHistory()">从历史采集</button>
|
||||
<button class="btn btn-info" onclick="exportSumData()">导出</button>
|
||||
<button class="btn btn-secondary" onclick="showSumDataConfigModal()">全局配置</button>
|
||||
<button class="btn btn-danger" onclick="batchDeleteSumData()" style="margin-left: auto;">批量删除</button>
|
||||
</div>
|
||||
|
||||
@@ -297,7 +298,24 @@
|
||||
<input type="text" id="custom-service-fee-name" class="form-control" placeholder="留空则使用默认名称(如:自定义服务费(0.8元/kWh))" style="width: 300px;" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="show-custom-service-fee" class="inline-checkbox" onchange="onVirtualFieldToggle(this)">
|
||||
在报表中显示自定义服务费字段
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="show-total-amount" class="inline-checkbox" onchange="onVirtualFieldToggle(this)">
|
||||
在报表中显示实收总金额字段(实收电费+自定义服务费)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>实收总金额表头名称:</label>
|
||||
<input type="text" id="total-amount-name" class="form-control" placeholder="留空则使用默认名称(实收总金额)" style="width: 300px;" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>分时段电量统计:</label>
|
||||
@@ -326,6 +344,28 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 求和数据全局配置模态框 -->
|
||||
<div id="sum-data-config-modal" class="modal">
|
||||
<div class="modal-content" style="max-width: 500px;">
|
||||
<div class="modal-header">
|
||||
<h2>求和数据全局配置</h2>
|
||||
<button class="close-btn" onclick="closeSumDataConfigModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>采集字段(勾选后将在求和数据页面显示和采集,充电电量始终采集):</label>
|
||||
<div id="sum-data-config-fields-list" style="border: 1px solid var(--border); border-radius: 6px; padding: 10px; min-height: 100px; max-height: 300px; overflow-y: auto;">
|
||||
<div class="loading">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" onclick="closeSumDataConfigModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="saveSumDataConfig()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加/编辑求和数据模态框 -->
|
||||
<div id="sum-data-modal" class="modal">
|
||||
<div class="modal-content" style="max-width: 600px;">
|
||||
|
||||
Reference in New Issue
Block a user