feat: 添加字段自定义报表名头功能

Coze-Commit-Type: user
Coze-User-ID: 3722323274763196
Coze-Conversation-ID: 9894087
This commit is contained in:
user9994793890
2026-07-13 11:27:11 +08:00
parent 81945f467a
commit d7a3e3fa9a
3 changed files with 58 additions and 13 deletions

15
app.py
View File

@@ -67,6 +67,7 @@ def create_config():
time_periods = data.get('time_periods', {})
merge_telecom = 1 if data.get('merge_telecom') else 0
telecom_vehicle_no = data.get('telecom_vehicle_no', '')
field_custom_names = data.get('field_custom_names', {})
if not config_name or not split_type or not split_value:
return jsonify({'success': False, 'message': '缺少必填字段'}), 400
@@ -84,8 +85,8 @@ def create_config():
sql = """
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, is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 1, %s, NOW(), NOW())
sum_fields, time_periods, merge_telecom, telecom_vehicle_no, field_custom_names, is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 1, %s, NOW(), NOW())
"""
params = (
@@ -99,6 +100,7 @@ def create_config():
json.dumps(time_periods, ensure_ascii=False),
merge_telecom,
telecom_vehicle_no,
json.dumps(field_custom_names, ensure_ascii=False) if field_custom_names else None,
sort_order
)
@@ -127,12 +129,13 @@ def update_config(config_id):
time_periods = data.get('time_periods', {})
merge_telecom = 1 if data.get('merge_telecom') else 0
telecom_vehicle_no = data.get('telecom_vehicle_no', '')
field_custom_names = data.get('field_custom_names', {})
sql = """
UPDATE t_daily_report_config
SET config_name = %s, split_type = %s, split_value = %s, split_name = %s,
selected_fields = %s, sum_fields = %s, time_periods = %s,
merge_telecom = %s, telecom_vehicle_no = %s, update_time = NOW()
merge_telecom = %s, telecom_vehicle_no = %s, field_custom_names = %s, update_time = NOW()
WHERE id = %s
"""
@@ -146,6 +149,7 @@ def update_config(config_id):
json.dumps(time_periods, ensure_ascii=False),
merge_telecom,
telecom_vehicle_no,
json.dumps(field_custom_names, ensure_ascii=False) if field_custom_names else None,
config_id
)
@@ -188,8 +192,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, is_active, sort_order, create_time, update_time)
VALUES (%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, is_active, sort_order, create_time, update_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())''',
(
new_id,
new_name,
@@ -201,6 +205,7 @@ def copy_config(config_id):
original.get('time_periods', ''),
original.get('merge_telecom', 0),
original.get('telecom_vehicle_no', ''),
original.get('field_custom_names', None),
original['is_active'],
sort_order
)

View File

@@ -416,7 +416,8 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
split_name=config.get('split_name', config['split_value']),
start_time=start_time_str,
end_time=end_time_str,
id_name_maps=id_name_maps
id_name_maps=id_name_maps,
field_custom_names=config.get('field_custom_names')
)
print(f"[日报生成] Excel文件已生成: {file_path}")
@@ -491,12 +492,13 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
def generate_excel(orders, selected_fields, sum_fields, sum_results,
config_name, split_name, start_time, end_time,
id_name_maps=None):
id_name_maps=None, field_custom_names=None):
"""
生成Excel文件
Args:
id_name_maps: ID到名称的映射字典格式为 {field_name: {id_value: name_value}}
field_custom_names: 字段自定义名头字典,格式为 {field_key: custom_name}
Returns:
str: 文件路径
@@ -532,10 +534,14 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
# 写入表头(中文)
header_row = 4
field_custom_names = field_custom_names or {}
for col_idx, field in enumerate(selected_fields, 1):
cell = ws.cell(row=header_row, column=col_idx)
# 优先使用自定义名头
if field in field_custom_names and field_custom_names[field]:
display_name = field_custom_names[field]
# 如果是ID字段且有名称映射表头显示为名称而不是ID
if field in id_name_maps and id_name_maps[field]:
elif field in id_name_maps and id_name_maps[field]:
# 将"用户ID"改为"用户""企业ID"改为"企业"等
display_name = get_field_display_name(field).replace('ID', '')
else:

View File

@@ -1125,6 +1125,9 @@
document.getElementById('split-type').value = '';
document.getElementById('split-value').innerHTML = '<option value="">请先选择拆分方式</option>';
// 重置字段自定义名头
fieldCustomNames = {};
// 重置合并特来电配置
const mergeTelecomCheckbox = document.getElementById('merge-telecom');
const telecomVehicleNoInput = document.getElementById('telecom-vehicle-no');
@@ -1212,12 +1215,20 @@
refreshSelectedFieldsOrder(checkedFields);
}
// 字段自定义名头存储
let fieldCustomNames = {};
// 刷新已选字段顺序列表
function refreshSelectedFieldsOrder(selectedFields) {
function refreshSelectedFieldsOrder(selectedFields, customNames = null) {
const orderGroup = document.getElementById('selected-fields-order-group');
const orderList = document.getElementById('selected-fields-order');
if (!orderList) return;
// 如果传入了自定义名头,更新全局变量
if (customNames !== null) {
fieldCustomNames = {...customNames};
}
// 根据是否有已选字段,显示/隐藏字段顺序区域
if (orderGroup) {
orderGroup.style.display = selectedFields.length > 0 ? 'block' : 'none';
@@ -1229,12 +1240,16 @@
orderList.innerHTML = selectedFields.map((fieldKey, index) => {
const field = allFields.find(f => f.key === fieldKey);
const displayName = field ? field.display : fieldKey;
const customName = fieldCustomNames[fieldKey] || '';
const isFirst = index === 0;
const isLast = index === selectedFields.length - 1;
return `
<div class="selected-field-item" data-field="${fieldKey}">
<span class="field-index">#${index + 1}</span>
<span class="field-name">${displayName}</span>
<span class="field-name" title="${displayName}">${displayName}</span>
<input type="text" class="field-custom-name" placeholder="自定义报表名头" value="${customName}"
onchange="updateFieldCustomName('${fieldKey}', this.value)"
style="flex: 1; min-width: 100px; padding: 4px 8px; font-size: 12px;">
<div class="field-actions">
<button type="button" class="btn-move" onclick="moveFieldUp(${index})" ${isFirst ? 'disabled' : ''} title="上移">↑</button>
<button type="button" class="btn-move" onclick="moveFieldDown(${index})" ${isLast ? 'disabled' : ''} title="下移">↓</button>
@@ -1244,6 +1259,20 @@
}).join('');
}
}
// 更新字段自定义名头
function updateFieldCustomName(fieldKey, customName) {
if (customName && customName.trim()) {
fieldCustomNames[fieldKey] = customName.trim();
} else {
delete fieldCustomNames[fieldKey];
}
}
// 获取字段自定义名头
function getFieldCustomNames() {
return {...fieldCustomNames};
}
// 字段上移
function moveFieldUp(index) {
@@ -1631,6 +1660,9 @@
alert('请输入特来电车量自编号');
return;
}
// 获取字段自定义名头
const fieldCustomNamesData = getFieldCustomNames();
const data = {
config_name: configName,
@@ -1641,7 +1673,8 @@
sum_fields: sumFields,
time_periods: timePeriods,
merge_telecom: mergeTelecom,
telecom_vehicle_no: telecomVehicleNo
telecom_vehicle_no: telecomVehicleNo,
field_custom_names: fieldCustomNamesData
};
try {
@@ -1697,8 +1730,9 @@
// 加载字段并回显选中状态
await loadFields(config.selected_fields, config.sum_fields);
// 加载字段顺序
refreshSelectedFieldsOrder(config.selected_fields);
// 加载字段顺序和自定义名头
const customNames = config.field_custom_names || {};
refreshSelectedFieldsOrder(config.selected_fields, customNames);
// 初始化时段编辑器并加载配置
initTimePeriodEditor();