diff --git a/application/hrm_mgnt/forms.py b/application/hrm_mgnt/forms.py index d81021f..b8b1af9 100644 --- a/application/hrm_mgnt/forms.py +++ b/application/hrm_mgnt/forms.py @@ -19,6 +19,12 @@ class EmployeeInformationForm(forms.ModelForm): class EmployeeInformationAddForm(DepartmentSelectionForm, forms.ModelForm): + primary_department = forms.ChoiceField( + choices=[('', '---------')] + [(dept.department_name, dept.department_name) for dept in PrimaryDepartment.objects.all()], + widget=forms.Select(attrs={'class': 'form-control'}), + label="一级部门" + ) + class Meta: model = EmployeeInformation fields = [field.name for field in EmployeeInformation._meta.fields if @@ -33,6 +39,9 @@ class EmployeeInformationAddForm(DepartmentSelectionForm, forms.ModelForm): 'base_salary': forms.NumberInput() } + def __init__(self, *args, **kwargs): + super(EmployeeInformationAddForm, self).__init__(*args, **kwargs) + class EmployeeInformationEditForm(DepartmentSelectionForm, forms.ModelForm): class Meta: diff --git a/application/org_mgnt/models.py b/application/org_mgnt/models.py index cec813f..243383f 100644 --- a/application/org_mgnt/models.py +++ b/application/org_mgnt/models.py @@ -37,7 +37,7 @@ class CompanyEntity(models.Model): verbose_name_plural = '公司主体信息登记表' def __str__(self): - return f"{self.company_name} - {self.entity_id}" + return self.company_name def get_historical_evolution(self): return "\n".join([ @@ -48,8 +48,7 @@ class CompanyEntity(models.Model): class EntityChangeRecord(models.Model): record_id = models.AutoField(primary_key=True, verbose_name='记录编号') - company_entity = models.ForeignKey(CompanyEntity, on_delete=models.CASCADE, related_name='change_records', - verbose_name='公司主体', default=1) + company_entity = models.ForeignKey(CompanyEntity, on_delete=models.CASCADE, related_name='change_records', verbose_name='公司主体', default=1) change_date = models.DateField(verbose_name='变更日期') change_type = models.CharField(max_length=255, verbose_name='变更类型') content_before_change = models.TextField(verbose_name='变更前内容') @@ -82,13 +81,11 @@ class CompanyBankAccount(models.Model): ) account_id = models.AutoField(primary_key=True, verbose_name='账户ID') - company_entity = models.ForeignKey(CompanyEntity, on_delete=models.CASCADE, related_name='bank_accounts', - verbose_name='公司ID', default=1) + company_entity = models.ForeignKey(CompanyEntity, on_delete=models.CASCADE, related_name='bank_accounts', verbose_name='公司ID', default=1) bank_name = models.CharField(max_length=255, verbose_name='开户行名称') account_number = models.CharField(max_length=255, verbose_name='账号') account_type = models.CharField(max_length=10, choices=ACCOUNT_TYPE_CHOICES, verbose_name='账户类型') - account_status = models.CharField(max_length=10, choices=ACCOUNT_STATUS_CHOICES, verbose_name='账户状态', - default='active') + account_status = models.CharField(max_length=10, choices=ACCOUNT_STATUS_CHOICES, verbose_name='账户状态', default='active') class Meta: verbose_name = '公司银行账户' @@ -123,4 +120,4 @@ class SecondaryDepartment(models.Model): unique_together = ('primary_department', 'secondary_department_name') def __str__(self): - return f"{self.secondary_department_name} ({self.primary_department})" + return self.secondary_department_name diff --git a/application/perf_mgnt/forms.py b/application/perf_mgnt/forms.py index 167437b..a7190e4 100644 --- a/application/perf_mgnt/forms.py +++ b/application/perf_mgnt/forms.py @@ -5,10 +5,9 @@ from ..org_mgnt.models import PrimaryDepartment class GroupBusinessTargetForm(forms.ModelForm): - primary_department = forms.ModelChoiceField( - queryset=PrimaryDepartment.objects.all(), + primary_department = forms.ChoiceField( + choices=[('', '---------')] + [(dept.department_name, dept.department_name) for dept in PrimaryDepartment.objects.all()], widget=forms.Select(attrs={'class': 'form-control'}), - empty_label="选择一级部门", label="一级部门" ) @@ -30,9 +29,6 @@ class GroupBusinessTargetForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(GroupBusinessTargetForm, self).__init__(*args, **kwargs) - if 'instance' in kwargs: - self.fields['primary_department'].initial = kwargs['instance'].primary_department - print(f"Initial primary department: {self.fields['primary_department'].initial}") # 调试输出 def clean(self): cleaned_data = super().clean() diff --git a/common/urls.py b/common/urls.py index d248810..eb42967 100644 --- a/common/urls.py +++ b/common/urls.py @@ -3,10 +3,6 @@ from common.views import * urlpatterns = [ path('error_page/', error_page, name='error_page'), - path('download_excel_template//', download_template, name='download_template'), - path('download_excel_template///', download_excel_template, - name='download_excel_template'), - path('common_excel_parse/', common_excel_parse, name='common_excel_parse'), path('save_excel_data/', save_excel_table_data, name='save_excel_table_data'), path('load_secondary_departments/', load_secondary_departments, name='load_secondary_departments'), diff --git a/common/views.py b/common/views.py index cfa5db5..7cd1f24 100644 --- a/common/views.py +++ b/common/views.py @@ -1,25 +1,16 @@ import json -import os -import urllib.parse import uuid -import openpyxl from django.apps import apps from django.core.exceptions import ValidationError from django.shortcuts import render -from openpyxl import load_workbook -from django.conf import settings from django.contrib.auth.decorators import login_required -from django.contrib.staticfiles import finders -from django.core.files.storage import default_storage -from django.http import FileResponse, HttpResponseNotFound, JsonResponse +from django.http import JsonResponse, HttpResponse from django.views.decorators.csrf import csrf_protect -from rest_framework.serializers import ModelSerializer -from application import fac_mgnt from application.fac_mgnt.models import InvoiceRecord -from application.org_mgnt.models import SecondaryDepartment +from application.org_mgnt.models import SecondaryDepartment, PrimaryDepartment from application.pjt_mgnt.models import ProjectLedger @@ -27,155 +18,6 @@ def error_page(request): return render(request, 'error_page.html') -@login_required -def download_template(request, template_name): - """ - 该视图提供下载指定的Excel模板文件。 - - 参数: - request: HttpRequest对象。 - template_name: 请求下载的Excel模板文件的名称,期望是一个字符串。 - fields: 包含字段信息的字典,用于生成Excel文件的表头和格式。 - - 返回: - FileResponse对象,允许用户下载生成的Excel文件。 - 如果文件未找到,则返回一个HttpResponseNotFound响应。 - """ - # 使用finders.find()根据文件名在Django的静态文件目录中查找文件的绝对路径 - file_path = finders.find(f'excels/{template_name}') - - # 如果文件路径不存在,返回404响应 - if not file_path: - return HttpResponseNotFound('

文件未找到

') - - # 创建FileResponse对象,设置为以附件形式下载,设置MIME类型为Excel文件 - response = FileResponse(open(file_path, 'rb'), - content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') - # 设置Content-Disposition头,告诉浏览器这是一个需要下载的文件 - # 使用urllib.parse.quote对文件名进行URL编码,以确保文件名中包含的特殊字符不会引起问题 - response['Content-Disposition'] = f'attachment; filename="{urllib.parse.quote(template_name)}"' - return response - - -@login_required -def download_excel_template(request, template_name, fields): - """ - 该视图提供下载指定的Excel模板文件。 - - 参数: - request: HttpRequest对象。 - template_name: 请求下载的Excel模板文件的名称,期望是一个字符串。 - fields: 包含字段信息的字典,用于生成Excel文件的表头和格式。 - - 返回: - FileResponse对象,允许用户下载生成的Excel文件。 - 如果文件未找到,则返回一个HttpResponseNotFound响应。 - """ - fields = json.loads(urllib.parse.unquote(fields).replace("'", '"')) - - # 创建一个新的工作簿 - wb = openpyxl.Workbook() - ws = wb.active - - # 设置表头行 - headers = [field['label'] for field in fields if field['is_add']] - ws.append(headers) - - # 保存生成的Excel文件到指定路径 - static_dir = os.path.join(settings.BASE_DIR, 'static', 'excels') - if not os.path.exists(static_dir): - os.makedirs(static_dir) - temp_file_path = os.path.join(static_dir, template_name) - wb.save(temp_file_path) - - # 创建FileResponse对象,设置为以附件形式下载,设置MIME类型为Excel文件 - response = FileResponse(open(temp_file_path, 'rb'), - content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') - - response['Content-Disposition'] = f'attachment; filename="{urllib.parse.quote(template_name)}"' - - return response - - -@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) - - # 保存文件到服务器 - file_name = default_storage.save(excel_file.name, excel_file) - file_path = os.path.join(settings.MEDIA_ROOT, file_name) - - try: - # 打开并解析Excel文件 - workbook = load_workbook(file_path, data_only=True) - sheet = workbook.active - - # 读取第一行作为表头 - 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.verbose_name in header_row] - model_verbose_name = [field.verbose_name for field in model._meta.fields if - not field.primary_key and field.verbose_name in header_row] - - 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} - instance_list = [] - for row in sheet.iter_rows(min_row=2, values_only=True): - if not all(value is None for value in row): - instance_list.append({header_to_field_map[header]: value for header, value in zip(header_row, row)}) - - # 清理,删除上传的文件 - os.remove(file_path) - - return JsonResponse({"table_data": instance_list, "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): @@ -234,11 +76,19 @@ def save_excel_table_data(request): @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) + try: + primary_department_name = request.GET.get('primary_department') + primary_department = PrimaryDepartment.objects.get(department_name=primary_department_name) + secondary_departments = SecondaryDepartment.objects.filter(primary_department_id=primary_department.primary_department_id).order_by('secondary_department_name') + + # 创建 HTML 字符串 + options = '' + for dept in secondary_departments: + options += f'' + + return HttpResponse(options) + except Exception as e: + return HttpResponse('') @csrf_protect diff --git a/templates/form_partial.html b/templates/form_partial.html index 45cb16d..6764363 100644 --- a/templates/form_partial.html +++ b/templates/form_partial.html @@ -104,45 +104,39 @@ -