悠修复自定义实收金额和求和采集功能增强

This commit is contained in:
2026-07-28 14:16:46 +08:00
parent e72acb58ec
commit 4a1b0f71c3
9 changed files with 454 additions and 39 deletions

View File

@@ -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)

View 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

View File

@@ -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:

View File

@@ -172,7 +172,7 @@ FIELD_MAPPING = {
# 自定义计算字段(虚拟字段)
'custom_service_fee': '自定义服务费(元)',
'total_amount': '实收金额(元)',
'custom_total_amount': '自定义实收金额(元)',
# 车辆信息(从 t_car 表关联)
'car_bus_path': '公交线路',

View File

@@ -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)
# 计算数值类型列的最大宽度,使所有求和类列宽度一致

View File

@@ -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')

View File

@@ -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');
}
}

View File

@@ -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);
}
}

View File

@@ -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()">&times;</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;">