增加序号,配置导出,导入,求和采集数据导出
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
日报求和数据采集与管理
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from lib.db import execute_query, execute_update, execute_insert
|
||||
from lib.field_mapping import get_field_display_name
|
||||
@@ -35,6 +36,7 @@ def collect_sum_data_from_history(history_id=None):
|
||||
|
||||
collected_count = 0
|
||||
skipped_count = 0
|
||||
config_sort_cache = {} # 缓存配置的排序号
|
||||
|
||||
for history in history_list:
|
||||
sum_results = history.get('sum_results')
|
||||
@@ -45,6 +47,24 @@ def collect_sum_data_from_history(history_id=None):
|
||||
elif sum_results is None:
|
||||
sum_results = {}
|
||||
|
||||
# 获取配置的排序号(缓存)
|
||||
config_id = history.get('config_id')
|
||||
sort_order = None
|
||||
if config_id:
|
||||
if config_id in config_sort_cache:
|
||||
sort_order = config_sort_cache[config_id]
|
||||
else:
|
||||
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']
|
||||
config_sort_cache[config_id] = sort_order
|
||||
except Exception:
|
||||
config_sort_cache[config_id] = None
|
||||
|
||||
# 强制确保有充电电量(charge_degree)
|
||||
if 'charge_degree' not in sum_results or sum_results['charge_degree'] is None:
|
||||
# 从订单表重新计算充电电量
|
||||
@@ -75,9 +95,9 @@ def collect_sum_data_from_history(history_id=None):
|
||||
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, data_source, remark,
|
||||
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, NOW(), NOW())
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
|
||||
'''
|
||||
params = (
|
||||
sum_data_id,
|
||||
@@ -91,6 +111,7 @@ def collect_sum_data_from_history(history_id=None):
|
||||
get_field_display_name(field_key),
|
||||
float(field_value) if field_value is not None else 0,
|
||||
history.get('total_orders', 0),
|
||||
sort_order,
|
||||
'auto',
|
||||
f'从历史记录自动采集,历史ID: {history["id"]}'
|
||||
)
|
||||
@@ -161,7 +182,7 @@ def _calculate_charge_degree(history):
|
||||
return None
|
||||
|
||||
|
||||
def get_sum_data_list(page=1, page_size=20, report_date=None, config_id=None,
|
||||
def get_sum_data_list(page=1, page_size=20, start_date=None, end_date=None, config_id=None,
|
||||
config_name=None, sum_field_key=None, data_source=None):
|
||||
"""
|
||||
查询求和数据列表
|
||||
@@ -169,7 +190,8 @@ def get_sum_data_list(page=1, page_size=20, report_date=None, config_id=None,
|
||||
Args:
|
||||
page: 页码
|
||||
page_size: 每页大小
|
||||
report_date: 报表日期(可选)
|
||||
start_date: 开始日期(可选)
|
||||
end_date: 结束日期(可选)
|
||||
config_id: 配置ID(可选)
|
||||
config_name: 配置名称(可选,模糊搜索)
|
||||
sum_field_key: 求和字段键名(可选)
|
||||
@@ -184,9 +206,13 @@ def get_sum_data_list(page=1, page_size=20, report_date=None, config_id=None,
|
||||
where_clauses = ['1=1']
|
||||
params = []
|
||||
|
||||
if report_date:
|
||||
where_clauses.append('report_date = %s')
|
||||
params.append(report_date)
|
||||
if start_date:
|
||||
where_clauses.append('report_date >= %s')
|
||||
params.append(start_date)
|
||||
|
||||
if end_date:
|
||||
where_clauses.append('report_date <= %s')
|
||||
params.append(end_date)
|
||||
|
||||
if config_id:
|
||||
where_clauses.append('config_id = %s')
|
||||
@@ -217,7 +243,7 @@ def get_sum_data_list(page=1, page_size=20, report_date=None, config_id=None,
|
||||
list_result = execute_query(
|
||||
f'''SELECT * FROM t_daily_report_sum_data
|
||||
WHERE {where_sql}
|
||||
ORDER BY report_date DESC, config_id, id DESC
|
||||
ORDER BY report_date DESC, sort_order ASC, config_id ASC, id DESC
|
||||
LIMIT %s OFFSET %s''',
|
||||
tuple(params) + (page_size, offset)
|
||||
)
|
||||
@@ -249,12 +275,27 @@ def add_sum_data(data):
|
||||
"""
|
||||
try:
|
||||
sum_data_id = int(datetime.now().timestamp() * 1000)
|
||||
|
||||
# 获取配置的排序号
|
||||
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, data_source, remark,
|
||||
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, NOW(), NOW())
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
|
||||
'''
|
||||
params = (
|
||||
sum_data_id,
|
||||
@@ -268,6 +309,7 @@ def add_sum_data(data):
|
||||
data.get('sum_field_name', ''),
|
||||
float(data.get('sum_value', 0)),
|
||||
data.get('total_orders', 0),
|
||||
sort_order,
|
||||
'manual',
|
||||
data.get('remark', '')
|
||||
)
|
||||
@@ -409,13 +451,176 @@ def batch_delete_sum_data(ids):
|
||||
return {'success': False, 'message': str(e)}
|
||||
|
||||
|
||||
def export_sum_data_to_excel(start_date=None, end_date=None, config_id=None, data_source=None, keyword=None):
|
||||
"""
|
||||
导出求和数据为Excel
|
||||
|
||||
Args:
|
||||
start_date: 开始日期(可选)
|
||||
end_date: 结束日期(可选)
|
||||
config_id: 配置ID(可选)
|
||||
data_source: 数据来源(可选)
|
||||
keyword: 配置名称关键词(可选)
|
||||
|
||||
Returns:
|
||||
dict: {success, message, file_path}
|
||||
"""
|
||||
try:
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
|
||||
|
||||
# 构建查询条件
|
||||
where_clauses = []
|
||||
params = []
|
||||
|
||||
if start_date:
|
||||
where_clauses.append('report_date >= %s')
|
||||
params.append(start_date)
|
||||
|
||||
if end_date:
|
||||
where_clauses.append('report_date <= %s')
|
||||
params.append(end_date)
|
||||
|
||||
if config_id:
|
||||
where_clauses.append('config_id = %s')
|
||||
params.append(config_id)
|
||||
|
||||
if data_source:
|
||||
where_clauses.append('data_source = %s')
|
||||
params.append(data_source)
|
||||
|
||||
if keyword:
|
||||
where_clauses.append('config_name LIKE %s')
|
||||
params.append(f'%{keyword}%')
|
||||
|
||||
where_sql = ''
|
||||
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 ())
|
||||
|
||||
# 创建Excel
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = '求和数据'
|
||||
|
||||
# 表头
|
||||
headers = ['序号', '报表日期', '配置名称', '拆分方式', '拆分值', '求和字段', '求和值', '订单数', '数据来源', '修改原因/备注', '创建时间', '更新时间']
|
||||
|
||||
header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
|
||||
header_font = Font(bold=True, color='FFFFFF', size=11)
|
||||
header_alignment = Alignment(horizontal='center', vertical='center')
|
||||
|
||||
thin_border = Border(
|
||||
left=Side(style='thin', color='000000'),
|
||||
right=Side(style='thin', color='000000'),
|
||||
top=Side(style='thin', color='000000'),
|
||||
bottom=Side(style='thin', color='000000')
|
||||
)
|
||||
|
||||
even_fill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
|
||||
|
||||
# 写入表头
|
||||
for col_idx, header in enumerate(headers, 1):
|
||||
cell = ws.cell(row=1, column=col_idx)
|
||||
cell.value = header
|
||||
cell.font = header_font
|
||||
cell.fill = header_fill
|
||||
cell.alignment = header_alignment
|
||||
cell.border = thin_border
|
||||
|
||||
ws.row_dimensions[1].height = 25
|
||||
|
||||
# 拆分方式映射
|
||||
split_type_map = {
|
||||
'company_id': '按企业ID',
|
||||
'user_id': '按用户ID',
|
||||
'station_id': '按场站ID'
|
||||
}
|
||||
|
||||
# 数据来源映射
|
||||
source_map = {
|
||||
'auto': '自动采集',
|
||||
'manual': '手动编辑'
|
||||
}
|
||||
|
||||
# 写入数据
|
||||
for row_idx, row in enumerate(rows, 2):
|
||||
is_even = (row_idx - 2) % 2 == 1
|
||||
|
||||
values = [
|
||||
row.get('sort_order') or '',
|
||||
row.get('report_date', ''),
|
||||
row.get('config_name', ''),
|
||||
split_type_map.get(row.get('split_type', ''), row.get('split_type', '')),
|
||||
row.get('split_name', '') or row.get('split_value', ''),
|
||||
row.get('sum_field_name', ''),
|
||||
float(row.get('sum_value', 0) or 0),
|
||||
int(row.get('total_orders', 0) or 0),
|
||||
source_map.get(row.get('data_source', ''), row.get('data_source', '')),
|
||||
row.get('remark', ''),
|
||||
str(row.get('create_time', '')) if row.get('create_time') else '',
|
||||
str(row.get('update_time', '')) if row.get('update_time') else ''
|
||||
]
|
||||
|
||||
for col_idx, val in enumerate(values, 1):
|
||||
cell = ws.cell(row=row_idx, column=col_idx)
|
||||
cell.value = val
|
||||
cell.border = thin_border
|
||||
|
||||
# 对齐方式:数字靠右,其他居中或靠左
|
||||
if col_idx in [7, 8]: # 求和值、订单数
|
||||
cell.alignment = Alignment(horizontal='right', vertical='center')
|
||||
if col_idx == 7:
|
||||
cell.number_format = '0.000'
|
||||
elif col_idx in [1, 2, 4, 9]: # 序号、日期、拆分方式、数据来源
|
||||
cell.alignment = Alignment(horizontal='center', vertical='center')
|
||||
else:
|
||||
cell.alignment = Alignment(horizontal='left', vertical='center')
|
||||
|
||||
if is_even:
|
||||
cell.fill = even_fill
|
||||
|
||||
ws.row_dimensions[row_idx].height = 22
|
||||
|
||||
# 调整列宽
|
||||
col_widths = [8, 14, 20, 12, 20, 18, 14, 10, 12, 30, 20, 20]
|
||||
for col_idx, width in enumerate(col_widths, 1):
|
||||
from openpyxl.utils import get_column_letter
|
||||
col_letter = get_column_letter(col_idx)
|
||||
ws.column_dimensions[col_letter].width = width
|
||||
|
||||
# 冻结首行
|
||||
ws.freeze_panes = 'A2'
|
||||
|
||||
# 保存文件
|
||||
reports_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'public', 'reports')
|
||||
os.makedirs(reports_dir, exist_ok=True)
|
||||
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
filename = f'求和数据导出_{timestamp}.xlsx'
|
||||
file_path = os.path.join(reports_dir, filename)
|
||||
wb.save(file_path)
|
||||
|
||||
return {'success': True, 'message': '导出成功', 'file_path': f'/public/reports/{filename}', 'filename': filename, 'total': len(rows)}
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return {'success': False, 'message': str(e)}
|
||||
|
||||
|
||||
def get_monthly_charge_degree_total(config_id=None, month=None):
|
||||
"""
|
||||
获取当月充电电量累计(从求和数据表查询,对账后的准确数据)
|
||||
|
||||
注意:
|
||||
- 数据来源于 t_daily_report_sum_data 表(线下对账后的数据,可能被手动修改过)
|
||||
- 只统计 sum_field_key = 'charge_degree' 的记录
|
||||
- 如果当天已经生成了日报并采集,自动包含在内,不会重复计算
|
||||
|
||||
Args:
|
||||
|
||||
Reference in New Issue
Block a user