commit 上传excel-人员基本信息部分
This commit is contained in:
parent
2f63e0981e
commit
ba909c0f41
|
@ -19,7 +19,7 @@ class ExpenseType(models.Model):
|
|||
# 费用明细表
|
||||
class ExpenseDetail(models.Model):
|
||||
detail_id = models.AutoField(primary_key=True, verbose_name='明细ID')
|
||||
type_id = models.ForeignKey(ExpenseType, on_delete=models.CASCADE, verbose_name='费用类型ID')
|
||||
type_id = models.ForeignKey(ExpenseType, on_delete=models.CASCADE, verbose_name='费用类型名称')
|
||||
expense_detail = models.CharField(max_length=255, unique=True, verbose_name='费用明细')
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -9,6 +9,7 @@ from django.urls import reverse
|
|||
from django.views.decorators.csrf import csrf_protect
|
||||
from django.views.decorators.http import require_POST, require_http_methods
|
||||
|
||||
from application import pjt_mgnt
|
||||
from application.fac_mgnt.forms import *
|
||||
from application.fac_mgnt.models import *
|
||||
from application.hrm_mgnt.models import PerformanceEvaluation
|
||||
|
@ -53,9 +54,7 @@ def exp_type_list_view(request):
|
|||
"parse_url": reverse("common_excel_parse"),
|
||||
"save_url": reverse("save_excel_table_data"),
|
||||
"fields_preview_config": {
|
||||
"type_id": {"type": "text", "width": "180px"},
|
||||
"expense_type": {"type": "text", "width": "180px"},
|
||||
"actions": {"type": "actions", "width": "100px"}
|
||||
}
|
||||
},
|
||||
"query_params": query_params,
|
||||
|
@ -152,8 +151,8 @@ def exp_detail_list_view(request):
|
|||
"table_exclude_field_name": ['detail_id'],
|
||||
"excel_upload_config": {
|
||||
"template_url": reverse("download_template", kwargs={'template_name': template_name}),
|
||||
"parse_url": reverse("common_excel_parse_exp"),
|
||||
"save_url": reverse("save_excel_table_data_exp"),
|
||||
"parse_url": reverse("common_excel_parse"),
|
||||
"save_url": reverse("save_excel_table_data"),
|
||||
"fields_preview_config": {
|
||||
"type_id": {"type": "text", "width": "180px"},
|
||||
"expense_detail": {"type": "text", "width": "180px"},
|
||||
|
@ -280,8 +279,8 @@ def gpb_list_view(request):
|
|||
"table_exclude_field_name": ['budget_id'],
|
||||
"excel_upload_config": {
|
||||
"template_url": reverse("download_template", kwargs={'template_name': template_name}),
|
||||
"parse_url": reverse("common_excel_parse_gab"),
|
||||
"save_url": reverse("save_excel_table_data_gab"),
|
||||
"parse_url": reverse("common_excel_parse"),
|
||||
"save_url": reverse("save_excel_table_data"),
|
||||
"fields_preview_config": {
|
||||
"primary_department": {"type": "text", "width": "180px"},
|
||||
"year": {"type": "number", "width": "100px"},
|
||||
|
@ -2184,8 +2183,8 @@ def common_excel_parse_pjt(request):
|
|||
project_name = instance_data.get('project_name')
|
||||
if project_name:
|
||||
try:
|
||||
project_instance = ProjectLedger.objects.get(project_name=project_name)
|
||||
instance_data['project_id'] = project_instance
|
||||
project_instance = pjt_mgnt.models.ProjectLedger.objects.get(project_name=project_name)
|
||||
instance_data['project'] = project_instance
|
||||
except ProjectLedger.DoesNotExist:
|
||||
return JsonResponse({'error': f'找不到名称为 {project_name} 的项目台账记录。'}, status=400)
|
||||
|
||||
|
|
|
@ -109,14 +109,13 @@ def emp_list_view(request):
|
|||
"political_affiliation": {"type": "text", "width": "120px"},
|
||||
"entry_date": {"type": "date", "width": "110px"},
|
||||
"regularization_date": {"type": "date", "width": "110px"},
|
||||
"departure_date": {"type": "date", "width": "110px"},
|
||||
"employment_type": {"type": "text", "width": "100px"},
|
||||
"status": {"type": "text", "width": "80px"},
|
||||
"primary_department": {"type": "text", "width": "180px"},
|
||||
"secondary_department": {"type": "text", "width": "180px"},
|
||||
"position": {"type": "text", "width": "180px"},
|
||||
"grade": {"type": "text", "width": "120px"},
|
||||
"contract_end_date": {"type": "date", "width": "110px"},
|
||||
"rank": {"type": "text", "width": "180px"},
|
||||
"contract_end_date": {"type": "text", "width": "180px"},
|
||||
"mobile_number": {"type": "text", "width": "150px"},
|
||||
"email": {"type": "text", "width": "200px"},
|
||||
"mailing_address": {"type": "text", "width": "280px"},
|
||||
|
@ -131,8 +130,6 @@ def emp_list_view(request):
|
|||
"base_salary": {"type": "text", "width": "120px"},
|
||||
"salary_account_number": {"type": "text", "width": "220px"},
|
||||
"bank_of_salary_account": {"type": "text", "width": "220px"},
|
||||
"resignation_type": {"type": "text", "width": "120px"},
|
||||
"resignation_reason": {"type": "textarea", "width": "300px"}
|
||||
}
|
||||
},
|
||||
# 上下文查询参数
|
||||
|
|
|
@ -59,7 +59,6 @@ def proj_ledger_list_view(request):
|
|||
"parse_url": reverse("common_excel_parse"),
|
||||
"save_url": reverse("save_excel_table_data"),
|
||||
"fields_preview_config": {
|
||||
"project_id": {"type": "text", "width": "180px"},
|
||||
"project_name": {"type": "text", "width": "180px"},
|
||||
"start_date": {"type": "date", "width": "180px"},
|
||||
"end_date": {"type": "date", "width": "180px"},
|
||||
|
@ -88,7 +87,6 @@ def proj_ledger_list_view(request):
|
|||
"actual_net_income": {"type": "number", "width": "180px"},
|
||||
"outstanding_net_income": {"type": "number", "width": "180px"},
|
||||
"notes": {"type": "text", "width": "180px"},
|
||||
"actions": {"type": "actions", "width": "100px"}
|
||||
}
|
||||
},
|
||||
"query_params": query_params,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.urls import path
|
||||
from common.views import *
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('error_page/', error_page, name='error_page'),
|
||||
path('download_excel_template/<str:template_name>/', download_template, name='download_template'),
|
||||
|
|
|
@ -22,6 +22,7 @@ from application.org_mgnt.models import SecondaryDepartment
|
|||
def error_page(request):
|
||||
return render(request, 'error_page.html')
|
||||
|
||||
|
||||
@login_required
|
||||
def download_template(request, template_name):
|
||||
"""
|
||||
|
@ -164,34 +165,45 @@ def common_excel_parse(request):
|
|||
fields_map = dict(zip(model_fields, header_row))
|
||||
fields_map_nf = dict(zip(header_row, model_fields))
|
||||
|
||||
# 检查表头是否与模型字段名对应
|
||||
# if not set(header_row).issubset(model_verbose_name):
|
||||
# return JsonResponse({'error': '表头不匹配,请使用正确的Excel上传模板。'}, status=400)
|
||||
|
||||
# 创建一个映射,将Excel表头映射到模型字段名
|
||||
header_to_field_map = {header: fields_map_nf[header] for header in header_row}
|
||||
header_fields = [header_to_field_map[header] for header in header_row]
|
||||
|
||||
# 动态处理外键关系
|
||||
def get_related_instance(model, field_name, value):
|
||||
field = model._meta.get_field(field_name)
|
||||
if field.is_relation:
|
||||
related_model = field.related_model
|
||||
related_field_name_list = related_model._meta.fields # 获取关联模型的第一个字段名
|
||||
for related_field_name in related_field_name_list:
|
||||
try:
|
||||
related_instance = related_model.objects.get(**{related_field_name.name: value})
|
||||
value = related_instance
|
||||
return value
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
else:
|
||||
return value
|
||||
|
||||
for row in sheet.iter_rows(min_row=2, values_only=True):
|
||||
if not all(value is None for value in row):
|
||||
# 使用映射来确保每个Excel单元格的数据对应到正确的模型字段
|
||||
instance_data = {header_to_field_map[header]: value for header, value in zip(header_row, row)}
|
||||
preview_data = instance_data.copy()
|
||||
for field_name, value in instance_data.items():
|
||||
instance_data[field_name] = get_related_instance(model, field_name, value)
|
||||
|
||||
instance = model(**instance_data)
|
||||
try:
|
||||
instance.full_clean()
|
||||
data.append(instance)
|
||||
data.append(preview_data)
|
||||
except ValidationError as e:
|
||||
return JsonResponse({'error': f'数据校验错误: {e.message_dict}'}, status=400)
|
||||
|
||||
# 动态获取序列化器
|
||||
serializer_class = create_dynamic_serializer(model, include=header_fields)
|
||||
|
||||
serializer = serializer_class(data, many=True)
|
||||
|
||||
# 清理,删除上传的文件
|
||||
os.remove(file_path)
|
||||
|
||||
return JsonResponse({"table_data": serializer.data, "fields_map": fields_map}, safe=False)
|
||||
return JsonResponse({"table_data": data, "fields_map": fields_map}, safe=False)
|
||||
except Exception as e:
|
||||
# 清理,删除上传的文件
|
||||
os.remove(file_path)
|
||||
|
@ -219,34 +231,47 @@ def save_excel_table_data(request):
|
|||
except (ValueError, LookupError):
|
||||
return JsonResponse({'error': '无效的 model_config'}, status=400)
|
||||
|
||||
# 创建模型实例列表
|
||||
instances = []
|
||||
for row_data in table_data:
|
||||
instance_data = {}
|
||||
for field_name, value in row_data.items():
|
||||
field = Model._meta.get_field(field_name)
|
||||
if field.is_relation:
|
||||
related_model = field.related_model
|
||||
related_field_name_list = related_model._meta.fields
|
||||
for related_field_name in related_field_name_list:
|
||||
try:
|
||||
related_instance = related_model.objects.get(**{related_field_name.name: value})
|
||||
value = related_instance
|
||||
instance_data[field_name] = value
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
else:
|
||||
instance_data[field_name] = value
|
||||
instance = Model(**instance_data)
|
||||
try:
|
||||
instance = Model(**row_data)
|
||||
instance.full_clean() # 验证数据
|
||||
instance.full_clean()
|
||||
instances.append(instance)
|
||||
except ValidationError as e:
|
||||
return JsonResponse({'error': f'数据校验错误: {e.message_dict}'}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({'error': f'创建实例时出错: {str(e)}'}, status=500)
|
||||
|
||||
# 批量创建模型实例
|
||||
try:
|
||||
Model.objects.bulk_create(instances)
|
||||
except Exception as e:
|
||||
return JsonResponse({'error': f'批量保存数据时出错: {str(e)}'}, status=500)
|
||||
# 批量保存数据
|
||||
Model.objects.bulk_create(instances)
|
||||
|
||||
return JsonResponse({'message': '表格数据保存成功'}, status=200)
|
||||
return JsonResponse({'success': '数据保存成功'}, status=201)
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({'error': '无效的JSON格式'}, status=400)
|
||||
return JsonResponse({'error': '无效的JSON数据'}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({'error': f'服务器内部错误: {str(e)}'}, status=500)
|
||||
return JsonResponse({'error': '无效的请求方法'}, status=400)
|
||||
return JsonResponse({'error': f'保存数据时出错: {str(e)}'}, status=500)
|
||||
|
||||
return JsonResponse({'error': '请求错误'}, status=400)
|
||||
|
||||
|
||||
@login_required
|
||||
def load_secondary_departments(request):
|
||||
primary_department_id = request.GET.get('primary_department_id')
|
||||
secondary_departments = SecondaryDepartment.objects.filter(primary_department_id=primary_department_id).order_by('secondary_department_name')
|
||||
return JsonResponse(list(secondary_departments.values('secondary_department_id', 'secondary_department_name')), safe=False)
|
||||
secondary_departments = SecondaryDepartment.objects.filter(primary_department_id=primary_department_id).order_by(
|
||||
'secondary_department_name')
|
||||
return JsonResponse(list(secondary_departments.values('secondary_department_id', 'secondary_department_name')),
|
||||
safe=False)
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue