save code
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Excel数据导入脚本
|
||||
从docs/example.xls导入工程项目数据到数据库
|
||||
"""
|
||||
|
||||
import sys
|
||||
import xlrd
|
||||
import mysql.connector
|
||||
from mysql.connector import Error
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
# 配置
|
||||
EXCEL_FILE = '../docs/example.xls'
|
||||
DB_CONFIG = {
|
||||
'host': 'localhost',
|
||||
'user': 'root',
|
||||
'password': 'rootpassword',
|
||||
'database': 'project_manager',
|
||||
'charset': 'utf8mb4'
|
||||
}
|
||||
|
||||
def get_database_connection():
|
||||
"""获取数据库连接"""
|
||||
try:
|
||||
connection = mysql.connector.connect(**DB_CONFIG)
|
||||
return connection
|
||||
except Error as e:
|
||||
print(f'数据库连接错误: {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def parse_date_value(cell_value, workbook):
|
||||
"""解析Excel日期值"""
|
||||
if cell_value == '':
|
||||
return None
|
||||
|
||||
# 检查是否是日期类型
|
||||
try:
|
||||
date_tuple = xlrd.xldate_as_tuple(cell_value, workbook.datemode)
|
||||
return f'{date_tuple[0]}-{date_tuple[1]:02d}-{date_tuple[2]:02d}'
|
||||
except:
|
||||
pass
|
||||
|
||||
# 检查特殊值
|
||||
if cell_value in ['未到期', '可退质保金', '未开工']:
|
||||
return None
|
||||
|
||||
# 尝试解析字符串日期
|
||||
try:
|
||||
date_obj = datetime.strptime(str(cell_value), '%Y-%m-%d')
|
||||
return date_obj.strftime('%Y-%m-%d')
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def parse_number_value(cell_value):
|
||||
"""解析数字值"""
|
||||
if cell_value == '':
|
||||
return None
|
||||
try:
|
||||
return float(cell_value)
|
||||
except:
|
||||
return None
|
||||
|
||||
def parse_int_value(cell_value):
|
||||
"""解析整数值"""
|
||||
num = parse_number_value(cell_value)
|
||||
if num is not None:
|
||||
return int(num)
|
||||
return None
|
||||
|
||||
def parse_enum_value(cell_value, allowed_values):
|
||||
"""解析枚举值"""
|
||||
if cell_value == '':
|
||||
return None
|
||||
if cell_value in allowed_values:
|
||||
return cell_value
|
||||
return None
|
||||
|
||||
def clean_text_value(cell_value):
|
||||
"""清理文本值"""
|
||||
if cell_value == '':
|
||||
return None
|
||||
return str(cell_value).strip()
|
||||
|
||||
def import_projects_from_sheet(sheet, connection, cursor, sheet_name):
|
||||
"""从工作表导入项目数据"""
|
||||
print(f'\n正在导入工作表: {sheet_name}')
|
||||
print(f'总行数: {sheet.nrows}')
|
||||
|
||||
# 获取管理员用户ID(用于created_by字段)
|
||||
cursor.execute("SELECT id FROM users WHERE username='admin' LIMIT 1")
|
||||
result = cursor.fetchone()
|
||||
if not result:
|
||||
print('错误: 未找到管理员用户', file=sys.stderr)
|
||||
return False
|
||||
admin_id = result[0]
|
||||
|
||||
success_count = 0
|
||||
skip_count = 0
|
||||
error_count = 0
|
||||
|
||||
# 从第6行开始(前5行是表头)
|
||||
for row_idx in range(5, sheet.nrows):
|
||||
try:
|
||||
# 读取数据
|
||||
row_data = [sheet.cell_value(row_idx, col_idx) for col_idx in range(min(61, sheet.ncols))]
|
||||
|
||||
# 检查是否是合计行或空行
|
||||
if row_data[0] == '' or str(row_data[0]).strip() == '':
|
||||
skip_count += 1
|
||||
continue
|
||||
|
||||
# 准备SQL插入语句
|
||||
sql = """
|
||||
INSERT INTO projects (
|
||||
project_no, power_contract_no, name, subitem_count, subitem_code,
|
||||
total_investment, contract_amount, warranty_ratio, settlement_amount,
|
||||
total_cost_estimated, voltage_level, engineering_type, owner_unit,
|
||||
owner_contact, bidding_type, signing_date, start_date, planned_end_date,
|
||||
actual_end_date, warranty_amount, warranty_expiry_date, actual_warranty_refund_date,
|
||||
project_department, project_leader, payment_method, total_cost_control,
|
||||
is_adjusted, labor_cost_control, labor_cost_planned, labor_cost_paid,
|
||||
material_cost_control, material_cost_payable, material_cost_actual,
|
||||
material_cost_paid, other_cost_control, other_cost_payable, other_cost_actual,
|
||||
tax_amount, profit, actual_profit, cost_settlement_amount, cumulative_progress,
|
||||
receivable_amount, invoice_amount, actual_receipt_amount, receipt_completion_rate,
|
||||
payable_amount, actual_payment_amount, unpaid_amount, payment_completion_rate,
|
||||
labor_debt_amount, settlement_cost_amount, settlement_labor_cost,
|
||||
settlement_material_cost, settlement_other_cost, due_settlement_count,
|
||||
unsettlement_count, problems, suggestions, remarks, status, created_by
|
||||
) VALUES (
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
|
||||
)
|
||||
"""
|
||||
|
||||
# 准备参数
|
||||
params = (
|
||||
clean_text_value(row_data[1]), # project_no
|
||||
clean_text_value(row_data[2]), # power_contract_no
|
||||
clean_text_value(row_data[3]), # name
|
||||
parse_int_value(row_data[4]), # subitem_count
|
||||
clean_text_value(row_data[5]), # subitem_code
|
||||
parse_number_value(row_data[6]), # total_investment
|
||||
parse_number_value(row_data[7]), # contract_amount
|
||||
parse_number_value(row_data[8]), # warranty_ratio
|
||||
parse_number_value(row_data[9]), # settlement_amount
|
||||
parse_number_value(row_data[10]), # total_cost_estimated
|
||||
clean_text_value(row_data[11]), # voltage_level
|
||||
clean_text_value(row_data[12]), # engineering_type
|
||||
clean_text_value(row_data[13]), # owner_unit
|
||||
clean_text_value(row_data[14]), # owner_contact
|
||||
clean_text_value(row_data[15]), # bidding_type
|
||||
parse_date_value(row_data[16], connection._connection.workbook), # signing_date
|
||||
parse_date_value(row_data[17], connection._connection.workbook), # start_date
|
||||
parse_date_value(row_data[18], connection._connection.workbook), # planned_end_date
|
||||
parse_date_value(row_data[19], connection._connection.workbook), # actual_end_date
|
||||
parse_number_value(row_data[20]), # warranty_amount
|
||||
parse_date_value(row_data[21], connection._connection.workbook), # warranty_expiry_date
|
||||
parse_date_value(row_data[22], connection._connection.workbook), # actual_warranty_refund_date
|
||||
clean_text_value(row_data[23]), # project_department
|
||||
clean_text_value(row_data[24]), # project_leader
|
||||
clean_text_value(row_data[25]), # payment_method
|
||||
parse_number_value(row_data[26]), # total_cost_control
|
||||
parse_enum_value(row_data[27], ['是', '否']), # is_adjusted
|
||||
parse_number_value(row_data[28]), # labor_cost_control
|
||||
parse_number_value(row_data[29]), # labor_cost_planned
|
||||
parse_number_value(row_data[30]), # labor_cost_paid
|
||||
parse_number_value(row_data[31]), # material_cost_control
|
||||
parse_number_value(row_data[32]), # material_cost_payable
|
||||
parse_number_value(row_data[33]), # material_cost_actual
|
||||
parse_number_value(row_data[34]), # material_cost_paid
|
||||
parse_number_value(row_data[35]), # other_cost_control
|
||||
parse_number_value(row_data[36]), # other_cost_payable
|
||||
parse_number_value(row_data[37]), # other_cost_actual
|
||||
parse_number_value(row_data[38]), # tax_amount
|
||||
parse_number_value(row_data[39]), # profit
|
||||
parse_number_value(row_data[40]), # actual_profit
|
||||
parse_number_value(row_data[41]), # cost_settlement_amount
|
||||
parse_number_value(row_data[42]), # cumulative_progress
|
||||
parse_number_value(row_data[43]), # receivable_amount
|
||||
parse_number_value(row_data[44]), # invoice_amount
|
||||
parse_number_value(row_data[45]), # actual_receipt_amount
|
||||
parse_number_value(row_data[46]), # receipt_completion_rate
|
||||
parse_number_value(row_data[47]), # payable_amount
|
||||
parse_number_value(row_data[48]), # actual_payment_amount
|
||||
parse_number_value(row_data[49]), # unpaid_amount
|
||||
parse_number_value(row_data[50]), # payment_completion_rate
|
||||
parse_number_value(row_data[51]), # labor_debt_amount
|
||||
parse_number_value(row_data[52]), # settlement_cost_amount
|
||||
parse_number_value(row_data[53]), # settlement_labor_cost
|
||||
parse_number_value(row_data[54]), # settlement_material_cost
|
||||
parse_number_value(row_data[55]), # settlement_other_cost
|
||||
parse_int_value(row_data[56]), # due_settlement_count
|
||||
parse_int_value(row_data[57]), # unsettlement_count
|
||||
clean_text_value(row_data[58]), # problems
|
||||
clean_text_value(row_data[59]), # suggestions
|
||||
clean_text_value(row_data[60]), # remarks
|
||||
'新建', # status (默认新建)
|
||||
admin_id # created_by
|
||||
)
|
||||
|
||||
# 跳过没有项目名称的行
|
||||
if not params[2]:
|
||||
skip_count += 1
|
||||
continue
|
||||
|
||||
cursor.execute(sql, params)
|
||||
success_count += 1
|
||||
|
||||
except Error as e:
|
||||
print(f'第{row_idx+1}行导入错误: {e}', file=sys.stderr)
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
print(f'导入完成: 成功 {success_count} 条, 跳过 {skip_count} 条, 错误 {error_count} 条')
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print('='*60)
|
||||
print('工程项目数据导入脚本')
|
||||
print('='*60)
|
||||
|
||||
# 检查Excel文件是否存在
|
||||
if not os.path.exists(EXCEL_FILE):
|
||||
print(f'错误: Excel文件不存在: {EXCEL_FILE}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 打开Excel文件
|
||||
try:
|
||||
workbook = xlrd.open_workbook(EXCEL_FILE)
|
||||
print(f'已打开Excel文件: {EXCEL_FILE}')
|
||||
print(f'工作表数量: {len(workbook.sheet_names())}')
|
||||
except Exception as e:
|
||||
print(f'错误: 无法打开Excel文件: {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 获取数据库连接
|
||||
connection = get_database_connection()
|
||||
cursor = connection.cursor()
|
||||
|
||||
try:
|
||||
# 导入主要工作表
|
||||
main_sheets = [
|
||||
'1-1基建',
|
||||
'1-2业扩',
|
||||
'1-3客户',
|
||||
'1-4营销',
|
||||
'2检修、技改、应急抢修项目'
|
||||
]
|
||||
|
||||
for sheet_name in main_sheets:
|
||||
if sheet_name in workbook.sheet_names():
|
||||
sheet = workbook.sheet_by_name(sheet_name)
|
||||
import_projects_from_sheet(sheet, connection, cursor, sheet_name)
|
||||
else:
|
||||
print(f'警告: 工作表不存在: {sheet_name}')
|
||||
|
||||
# 提交事务
|
||||
connection.commit()
|
||||
|
||||
# 显示统计信息
|
||||
cursor.execute("SELECT COUNT(*) FROM projects")
|
||||
total_count = cursor.fetchone()[0]
|
||||
print(f'\n数据库中共有 {total_count} 个项目')
|
||||
|
||||
cursor.execute("SELECT engineering_type, COUNT(*) as count FROM projects GROUP BY engineering_type")
|
||||
print('\n按工程类别统计:')
|
||||
for row in cursor.fetchall():
|
||||
print(f' {row[0]}: {row[1]} 个')
|
||||
|
||||
print('\n' + '='*60)
|
||||
print('数据导入完成!')
|
||||
print('='*60)
|
||||
|
||||
except Exception as e:
|
||||
print(f'错误: {e}', file=sys.stderr)
|
||||
connection.rollback()
|
||||
sys.exit(1)
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user