From 4a1b0f71c391d6cb9d51c980cc69e3e1e03204c3 Mon Sep 17 00:00:00 2001 From: haoslm <6083297@qq.com> Date: Tue, 28 Jul 2026 14:16:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=82=A0=E4=BF=AE=E5=A4=8D=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=AE=9E=E6=94=B6=E9=87=91=E9=A2=9D=E5=92=8C=E6=B1=82?= =?UTF-8?q?=E5=92=8C=E9=87=87=E9=9B=86=E5=8A=9F=E8=83=BD=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/api/__init__.py | 4 ++ lib/api/global_config_api.py | 36 ++++++++++ lib/db_init.py | 27 ++++++++ lib/field_mapping.py | 2 +- lib/report_generator.py | 124 ++++++++++++++++++++++++--------- lib/sum_data_collector.py | 42 ++++++++++++ public/static/js/config.js | 89 +++++++++++++++++++++++- public/static/js/sum_data.js | 129 ++++++++++++++++++++++++++++++++++- templates/index.html | 40 +++++++++++ 9 files changed, 454 insertions(+), 39 deletions(-) create mode 100644 lib/api/global_config_api.py diff --git a/lib/api/__init__.py b/lib/api/__init__.py index 9f3cea5..1e35c74 100644 --- a/lib/api/__init__.py +++ b/lib/api/__init__.py @@ -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) diff --git a/lib/api/global_config_api.py b/lib/api/global_config_api.py new file mode 100644 index 0000000..b280a29 --- /dev/null +++ b/lib/api/global_config_api.py @@ -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 \ No newline at end of file diff --git a/lib/db_init.py b/lib/db_init.py index 23034cc..1335842 100644 --- a/lib/db_init.py +++ b/lib/db_init.py @@ -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: diff --git a/lib/field_mapping.py b/lib/field_mapping.py index a87ee6e..009bb28 100644 --- a/lib/field_mapping.py +++ b/lib/field_mapping.py @@ -172,7 +172,7 @@ FIELD_MAPPING = { # 自定义计算字段(虚拟字段) 'custom_service_fee': '自定义服务费(元)', - 'total_amount': '实收金额(元)', + 'custom_total_amount': '自定义实收总金额(元)', # 车辆信息(从 t_car 表关联) 'car_bus_path': '公交线路', diff --git a/lib/report_generator.py b/lib/report_generator.py index 0b41630..71cf241 100644 --- a/lib/report_generator.py +++ b/lib/report_generator.py @@ -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) # 计算数值类型列的最大宽度,使所有求和类列宽度一致 diff --git a/lib/sum_data_collector.py b/lib/sum_data_collector.py index d75fc28..35e3a6a 100644 --- a/lib/sum_data_collector.py +++ b/lib/sum_data_collector.py @@ -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') diff --git a/public/static/js/config.js b/public/static/js/config.js index 8a6b713..74ffe68 100644 --- a/public/static/js/config.js +++ b/public/static/js/config.js @@ -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'); } } diff --git a/public/static/js/sum_data.js b/public/static/js/sum_data.js index 7648f29..d463704 100644 --- a/public/static/js/sum_data.js +++ b/public/static/js/sum_data.js @@ -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 = '加载中...'; } + + // 先加载全局配置 + 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 = '
加载中...
'; + + 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 = '
加载失败
'; + } + } catch (error) { + fieldsList.innerHTML = '
加载失败: ' + error.message + '
'; + } + + 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 => ` +
+ + +
+ `).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); + } +} diff --git a/templates/index.html b/templates/index.html index 2ba82a9..fe35822 100644 --- a/templates/index.html +++ b/templates/index.html @@ -183,6 +183,7 @@ + @@ -297,7 +298,24 @@ +
+ +
+
+ +
+ +
+ + +
@@ -326,6 +344,28 @@
+ + +