import json from datetime import datetime from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.http import JsonResponse, Http404 from django.shortcuts import render from django.template.loader import render_to_string from django.urls import reverse from django.views.decorators.csrf import csrf_protect from application.hrm_mgnt.forms import * from application.hrm_mgnt.models import * from application.org_mgnt.models import SecondaryDepartment from common.auth import custom_permission_required from common.utils.page_helper import paginate_query_and_assign_numbers from django.http import JsonResponse from django.core.files.storage import default_storage from django.conf import settings from openpyxl import load_workbook from django.apps import apps from rest_framework.serializers import ModelSerializer from django.core.exceptions import ValidationError import os @login_required @custom_permission_required('hrm_mgnt.view_employeeinformation') def emp_list_view(request): # 声明查询集 query_set = EmployeeInformation.objects.filter().order_by('-employee_id') # 获取查询参数 name = request.GET.get('name', '') department = request.GET.get('department', '') # 根据提供的参数进行筛选 if name: query_set = query_set.filter(name__icontains=name) if department: query_set = query_set.filter(primary_department=department) # 对查询结果进行分页,每页10条记录 items = paginate_query_and_assign_numbers( request=request, queryset=query_set, per_page=10 ) # 构建上下文查询参数字符串 query_params = '&name={}'.format(name) + '&department={}'.format(department) # Excel上传模板 template_name = "人力资源管理-人员基本信息-Excel上传模板.xlsx" # 构建上下文 context = { # 模型设置 "model_config": "hrm_mgnt.EmployeeInformation", # 分页数据 "items": items, # 面包屑 "breadcrumb_list": [ {"title": "首页", "name": "index"}, {"title": "人力资源管理", "name": "index"}, {"title": "人员基本信息表", "name": "emt_list"} ], # 筛选表单选项 "filters": [ { "type": "text", "id": "name", "name": "name", "label": "姓名", "placeholder": "请输入姓名" }, { "type": "select", "id": "department", "name": "department", "label": "一级部门", "options": [ {"value": "天信", "display": "天信"}, {"value": "混改", "display": "混改"}, {"value": "艾力芬特", "display": "艾力芬特"}, {"value": "星河", "display": "星河"}, {"value": "星海", "display": "星海"} ] } ], # Excel上传解析 "excel_upload_config": { "template_url": reverse("download_template", kwargs={'template_name': template_name}), "parse_url": reverse("common_excel_parse"), "save_url": reverse("save_excel_table_data"), "fields_preview_config": { "name": {"type": "text", "width": "180px"}, "id_number": {"type": "text", "width": "220px"}, "gender": {"type": "text", "width": "100px"}, "birthday": {"type": "date", "width": "110px"}, "age": {"type": "text", "width": "80px"}, "height": {"type": "text", "width": "100px"}, "weight": {"type": "text", "width": "100px"}, "blood_type": {"type": "text", "width": "80px"}, "ethnicity": {"type": "text", "width": "180px"}, "domicile": {"type": "text", "width": "220px"}, "marital_status": {"type": "text", "width": "120px"}, "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"}, "mobile_number": {"type": "text", "width": "150px"}, "email": {"type": "text", "width": "200px"}, "mailing_address": {"type": "text", "width": "280px"}, "emergency_contact": {"type": "text", "width": "150px"}, "relation_with_contact": {"type": "text", "width": "150px"}, "emergency_contact_phone": {"type": "text", "width": "150px"}, "education": {"type": "text", "width": "100px"}, "undergraduate_school": {"type": "text", "width": "220px"}, "graduate_school": {"type": "text", "width": "220px"}, "major": {"type": "text", "width": "220px"}, "technical_title": {"type": "text", "width": "180px"}, "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"} } }, # 上下文查询参数 "query_params": query_params, # 表格显示排除配置 "table_exclude_field_name": ['employee_id'], # 筛选表单提交链接 "form_action_url": "emp_list", # 修改对象提交链接 "modify_url": reverse("emp_list_modify"), # 新增对象提交链接 "add_url": reverse("emp_list_add"), # 删除对象提交链接 "delete_url": reverse("emp_list_delete"), } return render(request, 'emp_list.html', context) @login_required @custom_permission_required('hrm_mgnt.add_employeeinformation') def emp_list_add(request): if request.method == 'POST': form = EmployeeInformationAddForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "添加成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': form = EmployeeInformationAddForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.change_employeeinformation') def emp_list_modify(request): if request.method == 'POST': current_base_salary = None if 'id' in request.POST: instance = EmployeeInformation.objects.get(employee_id=request.POST['id']) current_base_salary = instance.base_salary # 获取当前基本工资 form = EmployeeInformationForm(request.POST, instance=instance) else: form = EmployeeInformationEditForm(request.POST) if form.is_valid(): employee = form.save() new_base_salary = form.cleaned_data.get('base_salary') # 判断基本工资是否有变化 if 'id' in request.POST and current_base_salary != new_base_salary: SalaryChangeRecord.objects.create( employee=employee, change_date=datetime.datetime.now(), previous_value=current_base_salary if current_base_salary else 0, new_value=new_base_salary, approved_by=request.user.username ) return JsonResponse({"message": "保存成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': if 'id' in request.GET: try: instance = EmployeeInformation.objects.get(employee_id=request.GET['id']) form = EmployeeInformationEditForm(instance=instance) form.fields['secondary_department'].queryset = SecondaryDepartment.objects.filter(primary_department=instance.primary_department).order_by('secondary_department_name') except EmployeeInformation.DoesNotExist: raise Http404("对象不存在") else: form = EmployeeInformationEditForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.delete_employeeinformation') def emp_list_delete(request): if request.method == 'GET': employee_id = request.GET.get('employee_id') EmployeeInformation.objects.filter(employee_id=employee_id).delete() return JsonResponse({"message": "删除成功"}) return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.view_salarychangerecord') def get_salary_change_records(request, employee_id): records = SalaryChangeRecord.objects.filter(employee_id=employee_id).values( 'change_date', 'previous_value', 'new_value', 'approved_by') return JsonResponse(list(records), safe=False) @login_required @custom_permission_required('hrm_mgnt.view_employeeattendancerecord') def attd_rec_list_view(request): # 声明查询集 query_set = EmployeeAttendanceRecord.objects.filter().order_by('-record_id') # 获取查询参数 employee = request.GET.get('employee', '') year_month = request.GET.get('year_month', '') primary_department = request.GET.get('primary_department', '') # 根据提供的参数进行筛选 if employee: query_set = query_set.filter(employee__name__icontains=employee) if year_month: query_set = query_set.filter(year_month__icontains=year_month) if primary_department: query_set = query_set.filter(employee__primary_department__icontains=primary_department) # 对查询结果进行分页,每页10条记录 items = paginate_query_and_assign_numbers( request=request, queryset=query_set, per_page=10 ) # 构建上下文查询参数字符串 query_params = '&employee={}'.format(employee) + '&year_month={}'.format( year_month) + '&primary_department={}'.format(primary_department) # Excel上传模板 template_name = "人力资源管理-员工考勤记录-Excel上传模板.xlsx" # 构建上下文 context = { "model_config": 'hrm_mgnt.EmployeeAttendanceRecord', "items": items, "breadcrumb_list": [ {"title": "首页", "name": "index"}, {"title": "人力资源管理", "name": "index"}, {"title": "员工考勤记录表", "name": "attd_rec_list"} ], "filters": [ {"type": "text", "id": "employee", "name": "employee", "label": "员工", "placeholder": "请输入员工姓名"}, {"type": "month", "id": "year_month", "name": "year_month", "label": "年月"}, {"type": "select", "id": "primary_department", "name": "primary_department", "label": "一级部门", "options": [{"value": "天信", "display": "天信"}, {"value": "混改", "display": "混改"}, {"value": "艾力芬特", "display": "艾力芬特"}, {"value": "星河", "display": "星河"}, {"value": "星海", "display": "星海"}]} ], "excel_upload_config": { "template_url": reverse("download_template", kwargs={'template_name': template_name}), "parse_url": reverse("common_excel_parse_attd"), "save_url": reverse("save_excel_table_data_attd"), "fields_preview_config": { "employee": {"type": "text", "width": "180px"}, "year_month": {"type": "date", "width": "110px"}, "late": {"type": "number", "width": "80px"}, "early_leave": {"type": "number", "width": "80px"}, "absenteeism": {"type": "number", "width": "80px"}, "annual_leave": {"type": "number", "width": "80px"}, "personal_leave": {"type": "number", "width": "80px"}, "sick_leave": {"type": "number", "width": "80px"}, } }, "query_params": query_params, "form_action_url": 'attd_rec_list', "modify_url": reverse("attd_rec_list_modify"), "add_url": reverse("attd_rec_list_add"), "delete_url": reverse("attd_rec_list_delete"), "table_exclude_field_name": ['record_id'], } return render(request, 'attd_list.html', context) @login_required @custom_permission_required('hrm_mgnt.add_employeeattendancerecord') def attd_rec_list_add(request): if request.method == 'POST': form = EmployeeAttendanceRecordForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "添加成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': form = EmployeeAttendanceRecordForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.change_employeeattendancerecord') def attd_rec_list_modify(request): if request.method == 'POST': if 'id' in request.POST: instance = EmployeeAttendanceRecord.objects.get(record_id=request.POST['id']) form = EmployeeAttendanceRecordForm(request.POST, instance=instance) else: form = EmployeeAttendanceRecordForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "保存成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': if 'id' in request.GET: try: instance = EmployeeAttendanceRecord.objects.get(record_id=request.GET['id']) form = EmployeeAttendanceRecordForm(instance=instance) except EmployeeAttendanceRecord.DoesNotExist: raise Http404("对象不存在") else: form = EmployeeAttendanceRecordForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.delete_employeeattendancerecord') def attd_rec_list_delete(request): if request.method == 'GET': record_id = request.GET.get('record_id') EmployeeAttendanceRecord.objects.filter(record_id=record_id).delete() return JsonResponse({"message": "删除成功"}) return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.view_otherleavedetails') def get_other_leave_details(request, attendance_record_id): records = OtherLeaveDetails.objects.filter(attendance_record_id=attendance_record_id).values( 'leave_type', 'days', 'description') return JsonResponse(list(records), safe=False) @login_required @custom_permission_required('hrm_mgnt.view_annualleaverecord') def alv_list_view(request): # 声明查询集 query_set = AnnualLeaveRecord.objects.filter().order_by('-record_id') # 获取查询参数 employee_name = request.GET.get('employee_name', '') year = request.GET.get('year', '') # 根据提供的参数进行筛选 if employee_name: query_set = query_set.filter(employee_name__icontains=employee_name) if year: query_set = query_set.filter(year__icontains=year) # 对查询结果进行分页,每页10条记录 items = paginate_query_and_assign_numbers( request=request, queryset=query_set, per_page=10 ) # 构建上下文查询参数字符串 query_params = '&employee_name={}'.format(employee_name) + '&year={}'.format(year) # Excel上传模板 template_name = "人力资源管理-年假使用记录-Excel上传模板.xlsx" # 构建上下文 context = { "model_config": 'hrm_mgnt.AnnualLeaveRecord', "items": items, "breadcrumb_list": [ {"title": "首页", "name": "index"}, {"title": "人力资源管理", "name": "index"}, {"title": "年假使用记录", "name": "alv_list"} ], "filters": [ {"type": "text", "id": "employee_name", "name": "employee_name", "label": "姓名", "placeholder": "请输入姓名"}, {"type": "select", "id": "year", "name": "year", "label": "年度", "options": [{"value": "2024", "display": "2024"}, {"value": "2023", "display": "2023"}, {"value": "2022", "display": "2022"}, {"value": "2021", "display": "2021"}, {"value": "2020", "display": "2020"}]} ], "excel_upload_config": { "template_url": reverse("download_template", kwargs={'template_name': template_name}), "parse_url": reverse("common_excel_parse"), "save_url": reverse("save_excel_table_data"), "fields_preview_config": { "year": {"type": "text", "width": "80px"}, "employee_name": {"type": "text", "width": "180px"}, "primary_department": {"type": "text", "width": "180px"}, "total_annual_leave": {"type": "number", "width": "80px"}, "used_annual_leave": {"type": "number", "width": "80px"}, "remaining_annual_leave": {"type": "number", "width": "80px"} } }, "query_params": query_params, "form_action_url": 'alv_list', "modify_url": reverse("alv_list_modify"), "add_url": reverse("alv_list_add"), "delete_url": reverse("alv_list_delete"), "table_exclude_field_name": ['record_id'], } return render(request, 'items_list.html', context) @login_required @custom_permission_required('hrm_mgnt.add_annualleaverecord') def alv_list_add(request): if request.method == 'POST': form = AnnualLeaveRecordForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "添加成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': form = AnnualLeaveRecordForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.change_annualleaverecord') def alv_list_modify(request): if request.method == 'POST': if 'id' in request.POST: instance = AnnualLeaveRecord.objects.get(record_id=request.POST['id']) form = AnnualLeaveRecordForm(request.POST, instance=instance) else: form = AnnualLeaveRecordForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "保存成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': if 'id' in request.GET: try: instance = AnnualLeaveRecord.objects.get(record_id=request.GET['id']) form = AnnualLeaveRecordForm(instance=instance) except AnnualLeaveRecord.DoesNotExist: raise Http404("对象不存在") else: form = AnnualLeaveRecordForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.delete_annualleaverecord') def alv_list_delete(request): if request.method == 'GET': record_id = request.GET.get('record_id') AnnualLeaveRecord.objects.filter(record_id=record_id).delete() return JsonResponse({"message": "删除成功"}) return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.view_rank') def rk_list_view(request): # 声明查询集 query_set = Rank.objects.filter().order_by('-rank_id') # 获取查询参数 rank_name = request.GET.get('rank_name', '') # 根据提供的参数进行筛选 if rank_name: query_set = query_set.filter(rank_name__icontains=rank_name) # 对查询结果进行分页,每页10条记录 items = paginate_query_and_assign_numbers( request=request, queryset=query_set, per_page=10 ) # 构建上下文查询参数字符串 query_params = '&rank_name={}'.format(rank_name) # Excel上传模板 template_name = "人力资源管理-职级表-Excel上传模板.xlsx" # 构建上下文 context = { "model_config": 'hrm_mgnt.Rank', "items": items, "breadcrumb_list": [ {"title": "首页", "name": "index"}, {"title": "人力资源管理", "name": "index"}, {"title": "职级表", "name": "rk_list"} ], "filters": [{"type": "text", "id": "rank_name", "name": "rank_name", "label": "职级名称", "placeholder": "请输入职级名称"}], "excel_upload_config": { "template_url": reverse("download_template", kwargs={'template_name': template_name}), "parse_url": reverse("common_excel_parse"), "save_url": reverse("save_excel_table_data"), "fields_preview_config": { "rank_name": {"type": "text", "width": "180px"}, "rank_description": {"type": "text", "width": "220px"}, } }, "query_params": query_params, "form_action_url": 'rk_list', "modify_url": reverse("rk_list_modify"), "add_url": reverse("rk_list_add"), "delete_url": reverse("rk_list_delete"), "table_exclude_field_name": ['rank_id'], } return render(request, 'items_list.html', context) @login_required @custom_permission_required('hrm_mgnt.add_rank') def rk_list_add(request): if request.method == 'POST': form = RankForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "添加成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': form = RankForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.change_rank') def rk_list_modify(request): if request.method == 'POST': if 'id' in request.POST: instance = Rank.objects.get(rank_id=request.POST['id']) form = RankForm(request.POST, instance=instance) else: form = RankForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "保存成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': if 'id' in request.GET: try: instance = Rank.objects.get(rank_id=request.GET['id']) form = RankForm(instance=instance) except Rank.DoesNotExist: raise Http404("对象不存在") else: form = RankForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.delete_rank') def rk_list_delete(request): if request.method == 'GET': rank_id = request.GET.get('rank_id') Rank.objects.filter(rank_id=rank_id).delete() return JsonResponse({"message": "删除成功"}) return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.view_position') def pst_list_view(request): # 声明查询集 query_set = Position.objects.filter().order_by('-position_id') # 获取查询参数 position_name = request.GET.get('position_name', '') # 根据提供的参数进行筛选 if position_name: query_set = query_set.filter(position_name__icontains=position_name) # 对查询结果进行分页,每页10条记录 items = paginate_query_and_assign_numbers( request=request, queryset=query_set, per_page=10 ) # 构建上下文查询参数字符串 query_params = '&position_name={}'.format(position_name) # Excel上传模板 template_name = "人力资源管理-岗位表-Excel上传模板.xlsx" # 构建上下文 context = { "model_config": 'hrm_mgnt.Position', "items": items, "breadcrumb_list": [ {"title": "首页", "name": "index"}, {"title": "人力资源管理", "name": "index"}, {"title": "岗位表", "name": "pst_list"} ], "filters": [ {"type": "text", "id": "position_name", "name": "position_name", "label": "岗位名称", "placeholder": "请输入岗位名称"} ], "excel_upload_config": { "template_url": reverse("download_template", kwargs={'template_name': template_name}), "parse_url": reverse("common_excel_parse"), "save_url": reverse("save_excel_table_data"), "fields_preview_config": { "position_name": {"type": "text", "width": "180px"}, "position_description": {"type": "text", "width": "220px"}, } }, "query_params": query_params, "form_action_url": 'pst_list', "modify_url": reverse("pst_list_modify"), "add_url": reverse("pst_list_add"), "delete_url": reverse("pst_list_delete"), "table_exclude_field_name": ['position_id'], } return render(request, 'items_list.html', context) @login_required @custom_permission_required('hrm_mgnt.add_position') def pst_list_add(request): if request.method == 'POST': form = PositionForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "添加成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': form = PositionForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.change_position') def pst_list_modify(request): if request.method == 'POST': if 'id' in request.POST: instance = Position.objects.get(position_id=request.POST['id']) form = PositionForm(request.POST, instance=instance) else: form = PositionForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "保存成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': if 'id' in request.GET: try: instance = Position.objects.get(position_id=request.GET['id']) form = PositionForm(instance=instance) except Position.DoesNotExist: raise Http404("对象不存在") else: form = PositionForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required @custom_permission_required('hrm_mgnt.delete_position') def pst_list_delete(request): if request.method == 'GET': position_id = request.GET.get('position_id') Position.objects.filter(position_id=position_id).delete() return JsonResponse({"message": "删除成功"}) return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required def emp_list_for_create_account_profile(request): # 查询还没有创建AccountProfile的员工信息 query_set = EmployeeInformation.objects.exclude(account_profile__isnull=False).order_by('-employee_id') # 获取查询参数 name = request.GET.get('name', '') # 根据提供的参数进行筛选 if name: query_set = query_set.filter(name__icontains=name) # 对查询结果进行分页 paginator = Paginator(query_set, 10) # 每页显示10条记录 page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) # 创建员工信息的列表,包含需要的字段 employees = [ { 'employee_id': emp.employee_id, 'name': emp.name, 'email': emp.email, 'mobile_number': emp.mobile_number, 'primary_department': emp.primary_department.department_name if emp.primary_department else '', 'position': emp.position.position_name if emp.position else '' } for emp in page_obj.object_list ] # 返回JSON响应 return JsonResponse({ 'success': True, 'employees': employees, 'has_previous': page_obj.has_previous(), 'has_next': page_obj.has_next(), 'num_pages': paginator.num_pages, 'current_page': page_obj.number }) @login_required # @custom_permission_required('hrm_mgnt.view_performanceevaluation') def performance_list_view(request): # 声明查询集 query_set = PerformanceEvaluation.objects.select_related('employee').order_by('-performance_id') # 获取查询参数 name = request.GET.get('name', '') department = request.GET.get('department', '') # 根据提供的参数进行筛选 if name: query_set = query_set.filter(employee__name__icontains=name) if department: query_set = query_set.filter(employee__primary_department=department) # 对查询结果进行分页,每页10条记录 items = paginate_query_and_assign_numbers( request=request, queryset=query_set, per_page=10 ) # 构建上下文查询参数字符串 query_params = '&name={}'.format(name) + '&department={}'.format(department) # Excel上传模板 template_name = "人力资源管理-员工绩效-Excel上传模板.xlsx" # 构建上下文 context = { "model_config": "hrm_mgnt.PerformanceEvaluation", "items": items, "breadcrumb_list": [ {"title": "首页", "name": "index"}, {"title": "人力资源管理", "name": "index"}, {"title": "员工绩效表", "name": "performance_list"} ], "filters": [ { "type": "text", "id": "name", "name": "name", "label": "姓名", "placeholder": "请输入姓名" }, { "type": "select", "id": "department", "name": "department", "label": "一级部门", "options": [ {"value": "天信", "display": "天信"}, {"value": "混改", "display": "混改"}, {"value": "艾力芬特", "display": "艾力芬特"}, {"value": "星河", "display": "星河"}, {"value": "星海", "display": "星海"} ] } ], "table_exclude_field_name": ['performance_id'], "excel_upload_config": { "template_url": reverse("download_template", kwargs={'template_name': template_name}), "parse_url": reverse("common_excel_parse_pe"), "save_url": reverse("save_excel_table_data_pe"), "fields_preview_config": { "employee": {"type": "text", "width": "180px"}, "year": {"type": "text", "width": "180px"}, "performance_score": {"type": "number", "width": "180px"}, } }, "query_params": query_params, "form_action_url": "performance_list", "modify_url": reverse("performance_modify"), "add_url": reverse("performance_add"), "delete_url": reverse("performance_delete"), } return render(request, 'performance_list.html', context) @login_required # @custom_permission_required('hrm_mgnt.add_performanceevaluation') def performance_add(request): if request.method == 'POST': form = PerformanceEvaluationAddForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "添加成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': form = PerformanceEvaluationAddForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required # @custom_permission_required('hrm_mgnt.change_performanceevaluation') def performance_modify(request): if request.method == 'POST': if 'id' in request.POST: instance = PerformanceEvaluation.objects.get(performance_id=request.POST['id']) form = PerformanceEvaluationForm(request.POST, instance=instance) else: form = PerformanceEvaluationForm(request.POST) if form.is_valid(): form.save() return JsonResponse({"message": "保存成功"}) else: form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html, "errors": form.errors}, status=400) elif request.method == 'GET': if 'id' in request.GET: try: instance = PerformanceEvaluation.objects.get(performance_id=request.GET['id']) form = PerformanceEvaluationForm(instance=instance) except PerformanceEvaluation.DoesNotExist: raise Http404("对象不存在") else: form = PerformanceEvaluationForm() form_html = render_to_string('form_partial.html', {'form': form}, request) return JsonResponse({"form_html": form_html}) else: return JsonResponse({"message": "无效的请求方法"}, status=405) @login_required # @custom_permission_required('hrm_mgnt.delete_performanceevaluation') def performance_delete(request): if request.method == 'GET': performance_id = request.GET.get('performance_id') PerformanceEvaluation.objects.filter(performance_id=performance_id).delete() return JsonResponse({"message": "删除成功"}) return JsonResponse({"message": "无效的请求方法"}, status=405) @csrf_protect @login_required def common_excel_parse(request): """ 该函数用于解析上传的Excel文件并返回数据。 Args: request: HTTP请求对象,包含上传的Excel文件。 Returns: JsonResponse: 包含解析后的Excel数据的JSON响应,或包含错误消息的JSON响应。 Raises: N/A """ # 如果是POST请求并且有上传的文件 if request.method == 'POST' and request.FILES: # 获取上传的Excel文件 excel_file = request.FILES.get('excel_file') # 如果没有提供文件,返回错误响应 if not excel_file: return JsonResponse({'error': '请先选择文件。'}, status=400) # 获取模型名称 model_config = request.POST.get('model_config', '') # 动态获取模型 try: app_label, model_name = model_config.split('.') model = apps.get_model(app_label, model_name) except (LookupError, KeyError, ValueError): return JsonResponse({'error': '模型配置错误。'}, status=400) # 获取模型中配置的不需要的字段 exclude_fields = getattr(model, 'excluded_fields', []) # 保存文件到服务器 file_name = default_storage.save(excel_file.name, excel_file) file_path = os.path.join(settings.MEDIA_ROOT, file_name) def create_dynamic_serializer(mod, include): class DynamicSerializer(ModelSerializer): class Meta: model = mod fields = include def to_representation(self, instance): representation = super().to_representation(instance) if 'employee' in representation and instance.employee: representation['employee'] = instance.employee.name return representation return DynamicSerializer try: # 打开并解析Excel文件 workbook = load_workbook(file_path, data_only=True) sheet = workbook.active data = [] # 读取第一行作为表头 header_row = [cell.value for cell in sheet[1]] # 获取字段名和 verbose_name,排除索引字段 model_fields = [field.name for field in model._meta.fields if not field.primary_key and field.name not in exclude_fields] model_verbose_name = [field.verbose_name for field in model._meta.fields if not field.primary_key and field.name not in exclude_fields] if not all(item in model_verbose_name for item in header_row): return JsonResponse({'error': '表头不匹配,请使用正确的Excel上传模板。'}, status=400) # 组成 fields_map fields_map = dict(zip(model_fields, header_row)) fields_map_nf = dict(zip(header_row, model_fields)) # 创建一个映射,将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] for row in sheet.iter_rows(min_row=2, values_only=True): if not all(value is None for value in row): instance_data = dict(zip(model_fields, row)) # 处理employee字段,假设模型中有employee字段并且Excel文件中的表头包含员工姓名 employee_name = instance_data.get('employee') if employee_name: try: employee_instance = EmployeeInformation.objects.get(name=employee_name) instance_data['employee'] = employee_instance except EmployeeInformation.DoesNotExist: return JsonResponse({'error': f'找不到姓名为 {employee_name} 的员工信息。'}, status=400) instance = model(**instance_data) try: instance.full_clean() data.append(instance) 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) except Exception as e: # 清理,删除上传的文件 os.remove(file_path) return JsonResponse({'error': f'解析文件时出错: {str(e)}'}, status=500) return JsonResponse({'error': '请求错误'}, status=400) @csrf_protect @login_required def save_excel_table_data(request): if request.method == 'POST': try: data = json.loads(request.body) model_config = data.get('model_config') table_data = data.get('table_data') if not model_config or not table_data: return JsonResponse({'error': '缺少必要的参数'}, status=400) # 分割 model_config 以获取 app_label 和 model_name try: app_label, model_name = model_config.split('.') Model = apps.get_model(app_label, model_name) except (ValueError, LookupError): return JsonResponse({'error': '无效的 model_config'}, status=400) # 获取模型中配置的不需要的字段 exclude_fields = getattr(Model, 'excluded_fields', []) # 创建模型实例列表 instances = [] for row_data in table_data: # 处理employee字段,假设模型中有employee字段并且table_data中包含员工姓名 employee_name = row_data.get('employee') if employee_name: try: employee_instance = EmployeeInformation.objects.get(name=employee_name) row_data['employee'] = employee_instance except EmployeeInformation.DoesNotExist: return JsonResponse({'error': f'找不到姓名为 {employee_name} 的员工信息。'}, status=400) try: # 排除不需要的字段 instance_data = {key: value for key, value in row_data.items() if key not in exclude_fields} instance = Model(**instance_data) 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) return JsonResponse({'message': '表格数据保存成功'}, status=200) except json.JSONDecodeError: return JsonResponse({'error': '无效的JSON格式'}, status=400) except Exception as e: return JsonResponse({'error': f'服务器内部错误: {str(e)}'}, status=500) return JsonResponse({'error': '无效的请求方法'}, status=400) @csrf_protect @login_required def common_excel_parse_pe(request): """ 该函数用于解析上传的Excel文件并返回数据。 Args: request: HTTP请求对象,包含上传的Excel文件。 Returns: JsonResponse: 包含解析后的Excel数据的JSON响应,或包含错误消息的JSON响应。 Raises: N/A """ # 如果是POST请求并且有上传的文件 if request.method == 'POST' and request.FILES: # 获取上传的Excel文件 excel_file = request.FILES.get('excel_file') # 如果没有提供文件,返回错误响应 if not excel_file: return JsonResponse({'error': '请先选择文件。'}, status=400) # 获取模型名称 model_config = request.POST.get('model_config', '') # 动态获取模型 try: app_label, model_name = model_config.split('.') model = apps.get_model(app_label, model_name) except (LookupError, KeyError, ValueError): return JsonResponse({'error': '模型配置错误。'}, status=400) # 获取模型中配置的不需要的字段 exclude_fields = getattr(model, 'excluded_fields', []) # 保存文件到服务器 file_name = default_storage.save(excel_file.name, excel_file) file_path = os.path.join(settings.MEDIA_ROOT, file_name) def create_dynamic_serializer(mod, include): class DynamicSerializer(ModelSerializer): class Meta: model = mod fields = include def to_representation(self, instance): representation = super().to_representation(instance) if 'employee' in representation and instance.employee: representation['employee'] = instance.employee.name return representation return DynamicSerializer try: # 打开并解析Excel文件 workbook = load_workbook(file_path, data_only=True) sheet = workbook.active data = [] # 读取第一行作为表头 header_row = [cell.value for cell in sheet[1]] # 获取字段名和 verbose_name,排除索引字段 model_fields = [field.name for field in model._meta.fields if not field.primary_key and field.name not in exclude_fields] model_verbose_name = [field.verbose_name for field in model._meta.fields if not field.primary_key and field.name not in exclude_fields] if not all(item in model_verbose_name for item in header_row): return JsonResponse({'error': '表头不匹配,请使用正确的Excel上传模板。'}, status=400) # 组成 fields_map fields_map = dict(zip(model_fields, header_row)) fields_map_nf = dict(zip(header_row, model_fields)) # 创建一个映射,将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] for row in sheet.iter_rows(min_row=2, values_only=True): if not all(value is None for value in row): instance_data = dict(zip(model_fields, row)) # 处理employee字段,假设模型中有employee字段并且Excel文件中的表头包含员工姓名 employee_name = instance_data.get('employee') if employee_name: try: employee_instance = EmployeeInformation.objects.get(name=employee_name) instance_data['employee'] = employee_instance except EmployeeInformation.DoesNotExist: return JsonResponse({'error': f'找不到姓名为 {employee_name} 的员工信息。'}, status=400) instance = model(**instance_data) try: instance.full_clean() data.append(instance) 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) except Exception as e: # 清理,删除上传的文件 os.remove(file_path) return JsonResponse({'error': f'解析文件时出错: {str(e)}'}, status=500) return JsonResponse({'error': '请求错误'}, status=400) @csrf_protect @login_required def save_excel_table_data_pe(request): if request.method == 'POST': try: data = json.loads(request.body) model_config = data.get('model_config') table_data = data.get('table_data') if not model_config or not table_data: return JsonResponse({'error': '缺少必要的参数'}, status=400) # 分割 model_config 以获取 app_label 和 model_name try: app_label, model_name = model_config.split('.') Model = apps.get_model(app_label, model_name) except (ValueError, LookupError): return JsonResponse({'error': '无效的 model_config'}, status=400) # 获取模型中配置的不需要的字段 exclude_fields = getattr(Model, 'excluded_fields', []) # 创建模型实例列表 instances = [] for row_data in table_data: # 处理employee字段,假设模型中有employee字段并且table_data中包含员工姓名 employee_name = row_data.get('employee') if employee_name: try: employee_instance = EmployeeInformation.objects.get(name=employee_name) row_data['employee'] = employee_instance except EmployeeInformation.DoesNotExist: return JsonResponse({'error': f'找不到姓名为 {employee_name} 的员工信息。'}, status=400) try: # 排除不需要的字段 instance_data = {key: value for key, value in row_data.items() if key not in exclude_fields} instance = Model(**instance_data) 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) return JsonResponse({'message': '表格数据保存成功'}, status=200) except json.JSONDecodeError: return JsonResponse({'error': '无效的JSON格式'}, status=400) except Exception as e: return JsonResponse({'error': f'服务器内部错误: {str(e)}'}, status=500) return JsonResponse({'error': '无效的请求方法'}, status=400)