Split maintenance into host and battery types with separate forms

This commit is contained in:
xiaji
2026-05-18 11:34:15 +08:00
parent 82fcbaf22a
commit 7a02213046
15 changed files with 363 additions and 15 deletions

Binary file not shown.

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.6 on 2026-05-18 03:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ups_manager', '0003_alter_upshost_brand'),
]
operations = [
migrations.AddField(
model_name='maintenancerecord',
name='maintenance_type',
field=models.CharField(choices=[('host', '主机维修'), ('battery', '电池维修')], default='host', max_length=20, verbose_name='维修类型'),
),
]

View File

@@ -90,6 +90,12 @@ class Battery(models.Model):
class MaintenanceRecord(models.Model):
MAINTENANCE_TYPE_CHOICES = [
('host', '主机维修'),
('battery', '电池维修'),
]
maintenance_type = models.CharField(max_length=20, choices=MAINTENANCE_TYPE_CHOICES, default='host', verbose_name='维修类型')
ups_host = models.ForeignKey(UPSHost, on_delete=models.CASCADE, verbose_name='UPS主机')
battery = models.ForeignKey(Battery, on_delete=models.SET_NULL, blank=True, null=True, verbose_name='电池')
supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, blank=True, null=True, verbose_name='维保供应商')
@@ -99,7 +105,7 @@ class MaintenanceRecord(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
def __str__(self):
return f'{self.ups_host} - {self.maintenance_date}'
return f'{self.get_maintenance_type_display()} - {self.ups_host} - {self.maintenance_date}'
class Meta:
verbose_name = '维修记录'

View File

@@ -0,0 +1,155 @@
{% extends 'ups_manager/base.html' %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-lg">
<div class="card-header bg-success text-white">
<h2 class="mb-0">添加电池维修记录</h2>
</div>
<div class="card-body">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
<div class="row g-4">
<div class="col-md-12">
<div class="form-group">
<label for="{{ form.ups_host.id_for_label }}" class="form-label font-weight-semibold">
{{ form.ups_host.label }} <span class="text-danger">*</span>
</label>
{{ form.ups_host }}
{% if form.ups_host.errors %}
{% for error in form.ups_host.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label for="{{ form.battery.id_for_label }}" class="form-label font-weight-semibold">
{{ form.battery.label }} <span class="text-danger">*</span>
</label>
{{ form.battery }}
{% if form.battery.errors %}
{% for error in form.battery.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.supplier.id_for_label }}" class="form-label font-weight-semibold">
{{ form.supplier.label }}
</label>
{{ form.supplier }}
{% if form.supplier.errors %}
{% for error in form.supplier.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.maintenance_date.id_for_label }}" class="form-label font-weight-semibold">
{{ form.maintenance_date.label }} <span class="text-danger">*</span>
</label>
<input type="text"
id="{{ form.maintenance_date.id_for_label }}"
name="{{ form.maintenance_date.name }}"
class="form-control datepicker"
value="{{ form.maintenance_date.value|date:'Y-m-d' }}"
placeholder="选择日期">
{% if form.maintenance_date.errors %}
{% for error in form.maintenance_date.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.technician.id_for_label }}" class="form-label font-weight-semibold">
{{ form.technician.label }} <span class="text-danger">*</span>
</label>
{{ form.technician }}
{% if form.technician.errors %}
{% for error in form.technician.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label for="{{ form.content.id_for_label }}" class="form-label font-weight-semibold">
{{ form.content.label }} <span class="text-danger">*</span>
</label>
{{ form.content }}
{% if form.content.errors %}
{% for error in form.content.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
<div class="mt-5 d-flex justify-content-end gap-3">
<a href="{% url 'maintenance_list' %}" class="btn btn-secondary px-6">
<i class="fas fa-arrow-left mr-2"></i>取消
</a>
<button type="submit" class="btn btn-success px-6">
<i class="fas fa-save mr-2"></i>保存
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
flatpickr('.datepicker', {
dateFormat: 'Y-m-d',
locale: 'zh',
allowInput: true,
todayButton: true,
clearButton: true,
minDate: '1900-01-01',
maxDate: new Date()
});
});
</script>
<style>
.form-control:focus {
border-color: #198754;
box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
}
.card {
border-radius: 12px;
}
.card-header {
border-radius: 12px 12px 0 0 !important;
}
.font-weight-semibold {
font-weight: 600;
}
.flatpickr-calendar {
border-radius: 8px;
box-shadow: 0 10px 40px rgba(0,0,0,0.15);
}
</style>
{% endblock %}

View File

@@ -0,0 +1,141 @@
{% extends 'ups_manager/base.html' %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-lg">
<div class="card-header bg-primary text-white">
<h2 class="mb-0">添加主机维修记录</h2>
</div>
<div class="card-body">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
<div class="row g-4">
<div class="col-md-12">
<div class="form-group">
<label for="{{ form.ups_host.id_for_label }}" class="form-label font-weight-semibold">
{{ form.ups_host.label }} <span class="text-danger">*</span>
</label>
{{ form.ups_host }}
{% if form.ups_host.errors %}
{% for error in form.ups_host.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.supplier.id_for_label }}" class="form-label font-weight-semibold">
{{ form.supplier.label }}
</label>
{{ form.supplier }}
{% if form.supplier.errors %}
{% for error in form.supplier.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.maintenance_date.id_for_label }}" class="form-label font-weight-semibold">
{{ form.maintenance_date.label }} <span class="text-danger">*</span>
</label>
<input type="text"
id="{{ form.maintenance_date.id_for_label }}"
name="{{ form.maintenance_date.name }}"
class="form-control datepicker"
value="{{ form.maintenance_date.value|date:'Y-m-d' }}"
placeholder="选择日期">
{% if form.maintenance_date.errors %}
{% for error in form.maintenance_date.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.technician.id_for_label }}" class="form-label font-weight-semibold">
{{ form.technician.label }} <span class="text-danger">*</span>
</label>
{{ form.technician }}
{% if form.technician.errors %}
{% for error in form.technician.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label for="{{ form.content.id_for_label }}" class="form-label font-weight-semibold">
{{ form.content.label }} <span class="text-danger">*</span>
</label>
{{ form.content }}
{% if form.content.errors %}
{% for error in form.content.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
<div class="mt-5 d-flex justify-content-end gap-3">
<a href="{% url 'maintenance_list' %}" class="btn btn-secondary px-6">
<i class="fas fa-arrow-left mr-2"></i>取消
</a>
<button type="submit" class="btn btn-primary px-6">
<i class="fas fa-save mr-2"></i>保存
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
flatpickr('.datepicker', {
dateFormat: 'Y-m-d',
locale: 'zh',
allowInput: true,
todayButton: true,
clearButton: true,
minDate: '1900-01-01',
maxDate: new Date()
});
});
</script>
<style>
.form-control:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
.card {
border-radius: 12px;
}
.card-header {
border-radius: 12px 12px 0 0 !important;
}
.font-weight-semibold {
font-weight: 600;
}
.flatpickr-calendar {
border-radius: 8px;
box-shadow: 0 10px 40px rgba(0,0,0,0.15);
}
</style>
{% endblock %}

View File

@@ -6,18 +6,22 @@
<div class="card mb-4">
<div class="card-body">
<form method="get" class="row g-3">
<div class="col-md-4">
<input type="text" name="ups_model" class="form-control" placeholder="UPS型号" value="{{ request.GET.ups_model }}">
<div class="col-md-3">
<input type="text" name="ups_host" class="form-control" placeholder="UPS型号" value="{{ request.GET.ups_host }}">
</div>
<div class="col-md-4">
<div class="col-md-3">
<input type="text" name="technician" class="form-control" placeholder="维修人员" value="{{ request.GET.technician }}">
</div>
<div class="col-md-4">
<input type="text" name="supplier" class="form-control" placeholder="维保供应商" value="{{ request.GET.supplier }}">
</div>
<div class="col-md-12">
<div class="col-md-6 d-flex gap-2 align-items-end">
<button type="submit" class="btn btn-primary">搜索</button>
<a href="{% url 'maintenance_add' %}" class="btn btn-success float-end">添加维修记录</a>
<div class="ms-auto">
<a href="{% url 'host_maintenance_add' %}" class="btn btn-primary">
<i class="fas fa-server me-1"></i>添加主机维修
</a>
<a href="{% url 'battery_maintenance_add' %}" class="btn btn-success ms-2">
<i class="fas fa-battery-full me-1"></i>添加电池维修
</a>
</div>
</div>
</form>
</div>
@@ -26,18 +30,26 @@
<table class="table table-striped">
<thead>
<tr>
<th width="100">维修类型</th>
<th>UPS主机</th>
<th>电池</th>
<th>维保供应商</th>
<th>维修日期</th>
<th>维修内容</th>
<th>维修人员</th>
<th>操作</th>
<th width="120">操作</th>
</tr>
</thead>
<tbody>
{% for record in maintenance_list %}
<tr>
<td>
{% if record.maintenance_type == 'host' %}
<span class="badge bg-primary">主机维修</span>
{% else %}
<span class="badge bg-success">电池维修</span>
{% endif %}
</td>
<td>{{ record.ups_host }}</td>
<td>{{ record.battery|default:"-" }}</td>
<td>{{ record.supplier|default:"-" }}</td>
@@ -51,7 +63,7 @@
</tr>
{% empty %}
<tr>
<td colspan="7" class="text-center text-muted">暂无维修记录</td>
<td colspan="8" class="text-center text-muted">暂无维修记录</td>
</tr>
{% endfor %}
</tbody>

View File

@@ -25,7 +25,8 @@ urlpatterns = [
path('supplier/<int:pk>/delete/', views.SupplierDeleteView.as_view(), name='supplier_delete'),
path('maintenance/', views.MaintenanceListView.as_view(), name='maintenance_list'),
path('maintenance/add/', views.MaintenanceCreateView.as_view(), name='maintenance_add'),
path('maintenance/host/add/', views.HostMaintenanceCreateView.as_view(), name='host_maintenance_add'),
path('maintenance/battery/add/', views.BatteryMaintenanceCreateView.as_view(), name='battery_maintenance_add'),
path('maintenance/<int:pk>/edit/', views.MaintenanceUpdateView.as_view(), name='maintenance_edit'),
path('maintenance/<int:pk>/delete/', views.MaintenanceDeleteView.as_view(), name='maintenance_delete'),
]

View File

@@ -285,17 +285,32 @@ class MaintenanceListView(ListView):
return queryset.order_by('-maintenance_date')
class MaintenanceCreateView(CreateView):
class HostMaintenanceCreateView(CreateView):
model = MaintenanceRecord
template_name = 'ups_manager/maintenance_form.html'
template_name = 'ups_manager/host_maintenance_form.html'
fields = ['ups_host', 'supplier', 'maintenance_date', 'technician', 'content']
success_url = reverse_lazy('maintenance_list')
def form_valid(self, form):
form.instance.maintenance_type = 'host'
return super().form_valid(form)
class BatteryMaintenanceCreateView(CreateView):
model = MaintenanceRecord
template_name = 'ups_manager/battery_maintenance_form.html'
fields = ['ups_host', 'battery', 'supplier', 'maintenance_date', 'technician', 'content']
success_url = reverse_lazy('maintenance_list')
def form_valid(self, form):
form.instance.maintenance_type = 'battery'
return super().form_valid(form)
class MaintenanceUpdateView(UpdateView):
model = MaintenanceRecord
template_name = 'ups_manager/maintenance_form.html'
fields = ['ups_host', 'supplier', 'maintenance_date', 'technician', 'content']
fields = ['ups_host', 'battery', 'supplier', 'maintenance_date', 'technician', 'content']
success_url = reverse_lazy('maintenance_list')