增加预算表的显示功能

This commit is contained in:
2025-12-03 17:17:17 +08:00
parent ddad32b481
commit acf4ef12ec
16 changed files with 1058 additions and 398 deletions

Binary file not shown.

View File

@@ -3,7 +3,7 @@ from django.contrib.admin.actions import delete_selected
from django.urls import reverse
from django.utils.html import format_html
from .models import Branch, EquipmentImage, Drawing, PublicScreen
from .models import Activity, Branch, Event, Contact, VideoTerminal
from .models import Activity, Branch, Event, Contact, VideoTerminal, Budget, EquipmentBudget, InfrastructureBudget, BudgetTemplate, TemplateEquipmentItem, TemplateInfrastructureItem
from django_select2.forms import Select2Widget
from unfold.admin import ModelAdmin
from django.contrib.admin import AdminSite
@@ -192,3 +192,96 @@ class VideoTerminalAdmin(ModelAdmin):
list_filter = ('terminal_type', 'branch')
search_fields = ('branch__name', 'description')
autocomplete_fields = ['branch']
# 预算相关Admin配置
# 设备预算内联
class EquipmentBudgetInline(admin.TabularInline):
model = EquipmentBudget
extra = 1
fields = ('project', 'model', 'unit_price', 'procurement_method', 'quantity', 'subtotal')
readonly_fields = ('subtotal',) # 小计自动计算,设为只读
# 基础设施预算内联
class InfrastructureBudgetInline(admin.TabularInline):
model = InfrastructureBudget
extra = 1
fields = ('name', 'remarks', 'unit_price', 'unit', 'quantity', 'subtotal', 'description')
readonly_fields = ('subtotal',) # 小计自动计算,设为只读
# 预算Admin
@admin.register(Budget)
class BudgetAdmin(ModelAdmin):
list_display = ('branch', 'name', 'total_budget', 'created_at')
list_filter = ('branch',)
search_fields = ('branch__name', 'name')
autocomplete_fields = ['branch']
readonly_fields = ('total_budget',) # 总预算自动计算,设为只读
inlines = [EquipmentBudgetInline, InfrastructureBudgetInline]
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
# 保存后重新计算总预算
obj.update_total_budget()
# 设备预算Admin如果需要单独管理
@admin.register(EquipmentBudget)
class EquipmentBudgetAdmin(ModelAdmin):
list_display = ('budget', 'project', 'model', 'unit_price', 'procurement_method', 'quantity', 'subtotal')
list_filter = ('budget__branch', 'project', 'procurement_method')
search_fields = ('budget__branch__name', 'project', 'model')
autocomplete_fields = ['budget']
readonly_fields = ('subtotal',)
# 基础设施预算Admin如果需要单独管理
@admin.register(InfrastructureBudget)
class InfrastructureBudgetAdmin(ModelAdmin):
list_display = ('budget', 'name', 'unit_price', 'unit', 'quantity', 'subtotal')
list_filter = ('budget__branch', 'name')
search_fields = ('budget__branch__name', 'name', 'description')
autocomplete_fields = ['budget']
readonly_fields = ('subtotal',)
# 预算模板相关Admin配置
# 模板设备项内联
class TemplateEquipmentItemInline(admin.TabularInline):
model = TemplateEquipmentItem
extra = 1
# 模板基础设施项内联
class TemplateInfrastructureItemInline(admin.TabularInline):
model = TemplateInfrastructureItem
extra = 1
# 模板设备项Admin如果需要单独管理
@admin.register(TemplateEquipmentItem)
class TemplateEquipmentItemAdmin(ModelAdmin):
list_display = ('template', 'project', 'model', 'unit_price', 'procurement_method')
list_filter = ('template', 'project', 'procurement_method')
search_fields = ('template__name', 'project', 'model')
autocomplete_fields = ['template']
# 模板基础设施项Admin如果需要单独管理
@admin.register(TemplateInfrastructureItem)
class TemplateInfrastructureItemAdmin(ModelAdmin):
list_display = ('template', 'name', 'unit_price', 'unit')
list_filter = ('template', 'unit')
search_fields = ('template__name', 'name', 'description')
autocomplete_fields = ['template']
# 预算模板Admin
@admin.register(BudgetTemplate)
class BudgetTemplateAdmin(ModelAdmin):
list_display = ('name', 'description', 'is_default', 'created_at')
list_filter = ('is_default',)
search_fields = ('name', 'description')
inlines = [TemplateEquipmentItemInline, TemplateInfrastructureItemInline]
def save_model(self, request, obj, form, change):
# 如果设置为默认模板,将其他模板的默认状态取消
if obj.is_default:
BudgetTemplate.objects.exclude(id=obj.id).update(is_default=False)
super().save_model(request, obj, form, change)

View File

@@ -0,0 +1,64 @@
# Generated by Django 5.0.6 on 2025-12-03 07:44
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('huodong', '0029_alter_activity_end_time_alter_activity_start_time_and_more'),
]
operations = [
migrations.CreateModel(
name='Budget',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('total_budget', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='总预算')),
('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='huodong.activity', verbose_name='活动')),
('branch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='huodong.branch', verbose_name='分支机构')),
],
options={
'verbose_name': '预算主表',
'verbose_name_plural': '预算主表',
},
),
migrations.CreateModel(
name='EquipmentBudget',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('project', models.CharField(max_length=255, verbose_name='项目')),
('model', models.CharField(max_length=255, verbose_name='型号')),
('unit_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='单价')),
('procurement_method', models.CharField(choices=[('本地询价采购', '本地询价采购'), ('订单采购', '订单采购'), ('按照总部配置要求本地询价采购', '按照总部配置要求本地询价采购'), ('本地询价采购或订单采购', '本地询价采购或订单采购')], max_length=50, verbose_name='采购方式')),
('quantity', models.IntegerField(default=1, verbose_name='数量')),
('subtotal', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='小计')),
('budget', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='equipment_budgets', to='huodong.budget', verbose_name='预算主表')),
],
options={
'verbose_name': '设备预算明细',
'verbose_name_plural': '设备预算明细',
},
),
migrations.CreateModel(
name='InfrastructureBudget',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='名称')),
('remarks', models.TextField(blank=True, verbose_name='备注')),
('unit_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='单价')),
('unit', models.CharField(max_length=20, verbose_name='单位')),
('description', models.TextField(blank=True, verbose_name='说明')),
('quantity', models.IntegerField(default=1, verbose_name='数量')),
('subtotal', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='小计')),
('budget', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='infrastructure_budgets', to='huodong.budget', verbose_name='预算主表')),
],
options={
'verbose_name': '基础设施预算明细',
'verbose_name_plural': '基础设施预算明细',
},
),
]

View File

@@ -0,0 +1,60 @@
# Generated by Django 5.0.6 on 2025-12-03 08:16
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('huodong', '0030_budget_equipmentbudget_infrastructurebudget'),
]
operations = [
migrations.CreateModel(
name='BudgetTemplate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='模板名称')),
('description', models.TextField(blank=True, verbose_name='模板描述')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('is_default', models.BooleanField(default=False, verbose_name='是否默认模板')),
],
options={
'verbose_name': '预算模板',
'verbose_name_plural': '预算模板',
},
),
migrations.CreateModel(
name='TemplateEquipmentItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('project', models.CharField(max_length=255, verbose_name='项目')),
('model', models.CharField(max_length=255, verbose_name='型号')),
('unit_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='参考单价')),
('procurement_method', models.CharField(choices=[('本地询价采购', '本地询价采购'), ('订单采购', '订单采购'), ('按照总部配置要求本地询价采购', '按照总部配置要求本地询价采购'), ('本地询价采购或订单采购', '本地询价采购或订单采购')], max_length=50, verbose_name='采购方式')),
('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='equipment_items', to='huodong.budgettemplate', verbose_name='模板')),
],
options={
'verbose_name': '模板设备项',
'verbose_name_plural': '模板设备项',
},
),
migrations.CreateModel(
name='TemplateInfrastructureItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='名称')),
('remarks', models.TextField(blank=True, verbose_name='备注')),
('unit_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='参考单价')),
('unit', models.CharField(max_length=20, verbose_name='单位')),
('description', models.TextField(blank=True, verbose_name='说明')),
('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='infrastructure_items', to='huodong.budgettemplate', verbose_name='模板')),
],
options={
'verbose_name': '模板基础设施项',
'verbose_name_plural': '模板基础设施项',
},
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.0.6 on 2025-12-03 09:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('huodong', '0031_budgettemplate_templateequipmentitem_and_more'),
]
operations = [
migrations.RemoveField(
model_name='budget',
name='activity',
),
migrations.AddField(
model_name='budget',
name='name',
field=models.CharField(default=1, max_length=255, verbose_name='预算名称'),
preserve_default=False,
),
]

View File

@@ -180,3 +180,148 @@ class Evaluation(models.Model):
def __str__(self):
return f"{self.activity.name} - {self.branch.name}"
# 预算相关模型
class Budget(models.Model):
"""预算主表"""
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, verbose_name='分支机构')
name = models.CharField(max_length=255, verbose_name='预算名称')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
total_budget = models.DecimalField(max_digits=15, decimal_places=2, default=0, verbose_name='总预算')
def __str__(self):
return f"{self.branch.name} - {self.name} 预算"
class Meta:
verbose_name = '预算主表'
verbose_name_plural = '预算主表'
class EquipmentBudget(models.Model):
"""设备预算明细"""
BUDGET_TYPES = (
('本地询价采购', '本地询价采购'),
('订单采购', '订单采购'),
('按照总部配置要求本地询价采购', '按照总部配置要求本地询价采购'),
('本地询价采购或订单采购', '本地询价采购或订单采购')
)
budget = models.ForeignKey(Budget, related_name='equipment_budgets', on_delete=models.CASCADE, verbose_name='预算主表')
project = models.CharField(max_length=255, verbose_name='项目')
model = models.CharField(max_length=255, verbose_name='型号')
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='单价')
procurement_method = models.CharField(max_length=50, choices=BUDGET_TYPES, verbose_name='采购方式')
quantity = models.IntegerField(default=1, verbose_name='数量')
subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name='小计')
def save(self, *args, **kwargs):
self.subtotal = self.unit_price * self.quantity
super().save(*args, **kwargs)
# 更新预算主表的总预算
self.update_total_budget()
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
# 更新预算主表的总预算
self.update_total_budget()
def update_total_budget(self):
"""更新预算主表的总预算"""
total = self.budget.equipment_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
total += self.budget.infrastructure_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
self.budget.total_budget = total
self.budget.save()
def __str__(self):
return f"{self.project} - {self.model}"
class Meta:
verbose_name = '设备预算明细'
verbose_name_plural = '设备预算明细'
class InfrastructureBudget(models.Model):
"""基础设施预算明细"""
budget = models.ForeignKey(Budget, related_name='infrastructure_budgets', on_delete=models.CASCADE, verbose_name='预算主表')
name = models.CharField(max_length=255, verbose_name='名称')
remarks = models.TextField(blank=True, verbose_name='备注')
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='单价')
unit = models.CharField(max_length=20, verbose_name='单位')
description = models.TextField(blank=True, verbose_name='说明')
quantity = models.IntegerField(default=1, verbose_name='数量')
subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name='小计')
def save(self, *args, **kwargs):
self.subtotal = self.unit_price * self.quantity
super().save(*args, **kwargs)
# 更新预算主表的总预算
self.update_total_budget()
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
# 更新预算主表的总预算
self.update_total_budget()
def update_total_budget(self):
"""更新预算主表的总预算"""
total = self.budget.equipment_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
total += self.budget.infrastructure_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
self.budget.total_budget = total
self.budget.save()
def __str__(self):
return self.name
class Meta:
verbose_name = '基础设施预算明细'
verbose_name_plural = '基础设施预算明细'
class BudgetTemplate(models.Model):
"""预算模板"""
name = models.CharField(max_length=255, verbose_name='模板名称')
description = models.TextField(blank=True, verbose_name='模板描述')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
is_default = models.BooleanField(default=False, verbose_name='是否默认模板')
def __str__(self):
return self.name
class Meta:
verbose_name = '预算模板'
verbose_name_plural = '预算模板'
class TemplateEquipmentItem(models.Model):
"""模板设备项"""
template = models.ForeignKey(BudgetTemplate, related_name='equipment_items', on_delete=models.CASCADE, verbose_name='模板')
project = models.CharField(max_length=255, verbose_name='项目')
model = models.CharField(max_length=255, verbose_name='型号')
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='参考单价')
procurement_method = models.CharField(max_length=50, choices=EquipmentBudget.BUDGET_TYPES, verbose_name='采购方式')
def __str__(self):
return f"{self.project} - {self.model}"
class Meta:
verbose_name = '模板设备项'
verbose_name_plural = '模板设备项'
class TemplateInfrastructureItem(models.Model):
"""模板基础设施项"""
template = models.ForeignKey(BudgetTemplate, related_name='infrastructure_items', on_delete=models.CASCADE, verbose_name='模板')
name = models.CharField(max_length=255, verbose_name='名称')
remarks = models.TextField(blank=True, verbose_name='备注')
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='参考单价')
unit = models.CharField(max_length=20, verbose_name='单位')
description = models.TextField(blank=True, verbose_name='说明')
def __str__(self):
return self.name
class Meta:
verbose_name = '模板基础设施项'
verbose_name_plural = '模板基础设施项'

View File

@@ -11,6 +11,125 @@
<span class="flex-grow block border-t border-black" aria-hidden="true" role="presentation"></span>
</h2>
<!-- Component ends here -->
<!-- 投入预算表 -->
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
<h2 class="text-2xl font-bold mb-4">投入预算表</h2>
<p class="text-gray-700 mb-4">分支机构项目的预算表,包括设备和基础设施明细</p>
<!-- 预算模板导入功能 -->
{% if budget_templates %} <!-- 只有当有模板时才显示导入功能 -->
<div class="mb-6 p-4 bg-blue-50 rounded-lg">
<h3 class="text-lg font-semibold mb-2">预算模板导入</h3>
<p class="text-sm text-gray-600 mb-3">从模板一键导入预算,快速生成预算表</p>
<form method="POST" action="{% url 'import-budget-template' branch.id %}">
{% csrf_token %}
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label for="template" class="block text-sm font-medium text-gray-700 mb-1">选择模板</label>
<select id="template" name="template" class="w-full p-2 border border-gray-300 rounded-md">
{% for template in budget_templates %}
<option value="{{ template.id }}">{{ template.name }}{% if template.is_default %} (默认){% endif %}</option>
{% endfor %}
</select>
</div>
<div>
<label for="budget_name" class="block text-sm font-medium text-gray-700 mb-1">预算名称</label>
<input type="text" id="budget_name" name="budget_name" placeholder="请输入预算名称" class="w-full p-2 border border-gray-300 rounded-md">
</div>
<div class="flex items-end">
<button type="submit" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md">
一键导入
</button>
</div>
</div>
</form>
</div>
{% endif %}
{% if budgets %}
{% for budget in budgets %}
<div class="mb-6">
<h3 class="text-lg font-semibold mb-3">{{ budget.activity.name }} - 总预算: ¥{{ budget.total_budget }}</h3>
<!-- 设备预算部分 -->
<div class="mb-4">
<h4 class="text-md font-semibold mb-2">设备预算明细</h4>
{% if budget.equipment_budgets.all %}
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">项目</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">型号</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">单价</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">采购方式</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">数量</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">小计</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{% for equipment in budget.equipment_budgets.all %}
<tr>
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.project }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.model }}</td>
<td class="px-6 py-4 whitespace-nowrap">¥{{ equipment.unit_price }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.get_procurement_method_display }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.quantity }}</td>
<td class="px-6 py-4 whitespace-nowrap">¥{{ equipment.subtotal }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-gray-500 italic">暂无设备预算明细</p>
{% endif %}
</div>
<!-- 基础设施预算部分 -->
<div>
<h4 class="text-md font-semibold mb-2">基础设施预算明细</h4>
{% if budget.infrastructure_budgets.all %}
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">名称</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">备注</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">单价</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">单位</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">数量</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">小计</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">说明</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{% for infrastructure in budget.infrastructure_budgets.all %}
<tr>
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.name }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.remarks }}</td>
<td class="px-6 py-4 whitespace-nowrap">¥{{ infrastructure.unit_price }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.unit }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.quantity }}</td>
<td class="px-6 py-4 whitespace-nowrap">¥{{ infrastructure.subtotal }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-gray-500 italic">暂无基础设施预算明细</p>
{% endif %}
</div>
</div>
{% endfor %}
{% else %}
<p class="text-gray-500 italic">暂无预算信息</p>
{% endif %}
</div>
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
<h2 class="text-2xl font-bold mb-4">基本信息</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">

View File

@@ -11,6 +11,7 @@ urlpatterns = [
path('api/', include(router.urls)),
path('', views.BranchAll, name='branch-all'),
path('branch/<int:branch_id>/', views.branch_detail, name='branch-detail'),
path('branch/<int:branch_id>/import-budget/', views.import_budget_template, name='import-budget-template'),
path('branch/info/', views.Branchinfo, name='branchinfo'),
path('statistics/', views.Statistics, name='statistics'),
path('contact/', views.contact_list, name='contact-list'),

View File

@@ -1,5 +1,5 @@
from rest_framework import viewsets
from .models import Branch, Activity, Evaluation, Event, VideoTerminal
from .models import Branch, Activity, Evaluation, Event, VideoTerminal, Budget, EquipmentBudget, InfrastructureBudget, BudgetTemplate, TemplateEquipmentItem, TemplateInfrastructureItem
from .serializers import BranchSerializer, ActivitySerializer, EvaluationSerializer
from django.shortcuts import render, redirect
from .models import PublicScreen
@@ -55,6 +55,12 @@ def branch_detail(request, branch_id):
equipment_images = branch.equipment_images.all()
public_screens = branch.public_screens.all()
# 获取预算数据
budgets = Budget.objects.filter(branch=branch).select_related('activity').prefetch_related('equipment_budgets', 'infrastructure_budgets').order_by('-created_at')
# 获取预算模板
budget_templates = BudgetTemplate.objects.all()
# 准备上下文数据
context = {
'branch': branch,
@@ -62,10 +68,62 @@ def branch_detail(request, branch_id):
'events': events,
'equipment_images': equipment_images,
'public_screens': public_screens,
'budgets': budgets,
'activities': activities,
'budget_templates': budget_templates,
}
return render(request, 'branch_detail.html', context)
def import_budget_template(request, branch_id):
"""从模板导入预算"""
if request.method == 'POST':
template_id = request.POST.get('template')
budget_name = request.POST.get('budget_name', '导入预算')
if template_id:
try:
# 获取模板和分支机构
template = BudgetTemplate.objects.get(pk=template_id)
branch = Branch.objects.get(pk=branch_id)
# 创建预算
budget = Budget.objects.create(
branch=branch,
name=budget_name
)
# 导入设备预算项
for equipment_item in template.equipment_items.all():
EquipmentBudget.objects.create(
budget=budget,
project=equipment_item.project,
model=equipment_item.model,
unit_price=equipment_item.unit_price,
procurement_method=equipment_item.procurement_method,
quantity=1 # 默认数量为1
)
# 导入基础设施预算项
for infrastructure_item in template.infrastructure_items.all():
InfrastructureBudget.objects.create(
budget=budget,
name=infrastructure_item.name,
remarks=infrastructure_item.remarks,
unit_price=infrastructure_item.unit_price,
unit=infrastructure_item.unit,
description=infrastructure_item.description,
quantity=1 # 默认数量为1
)
# 更新总预算
budget.update_total_budget()
except Exception as e:
print(f"导入预算模板失败: {e}")
return redirect('branch-detail', branch_id=branch_id)
# 在页面上显示所有的branch以及active的数量首页显示
def BranchAll(request):
branches = Branch.objects.exclude(activity__isnull=True).order_by('name')
@@ -442,3 +500,100 @@ def video_terminal_list(request):
'selected_type_name': selected_type_name,
}
return render(request, 'video_terminals.html', context)
# 预算相关视图
def create_budget(request, branch_id):
branch = Branch.objects.get(pk=branch_id)
activities = Activity.objects.filter(branch=branch)
if request.method == 'POST':
activity_id = request.POST.get('activity')
if activity_id:
activity = Activity.objects.get(pk=activity_id)
budget = Budget.objects.create(branch=branch, activity=activity)
return redirect('budget_detail', branch_id=branch_id, budget_id=budget.id)
context = {
'branch': branch,
'activities': activities,
}
return render(request, 'create_budget.html', context)
def budget_detail(request, branch_id, budget_id):
branch = Branch.objects.get(pk=branch_id)
budget = Budget.objects.get(pk=budget_id, branch=branch)
context = {
'branch': branch,
'budget': budget,
}
return render(request, 'budget_detail.html', context)
def add_equipment_budget(request, branch_id, budget_id):
branch = Branch.objects.get(pk=branch_id)
budget = Budget.objects.get(pk=budget_id, branch=branch)
if request.method == 'POST':
project = request.POST.get('project')
model = request.POST.get('model')
unit_price = request.POST.get('unit_price')
procurement_method = request.POST.get('procurement_method')
quantity = request.POST.get('quantity', 1)
if project and model and unit_price and procurement_method:
EquipmentBudget.objects.create(
budget=budget,
project=project,
model=model,
unit_price=unit_price,
procurement_method=procurement_method,
quantity=quantity
)
return redirect('budget_detail', branch_id=branch_id, budget_id=budget_id)
def add_infrastructure_budget(request, branch_id, budget_id):
branch = Branch.objects.get(pk=branch_id)
budget = Budget.objects.get(pk=budget_id, branch=branch)
if request.method == 'POST':
name = request.POST.get('name')
remarks = request.POST.get('remarks')
unit_price = request.POST.get('unit_price')
unit = request.POST.get('unit')
description = request.POST.get('description')
quantity = request.POST.get('quantity', 1)
if name and unit_price and unit:
InfrastructureBudget.objects.create(
budget=budget,
name=name,
remarks=remarks,
unit_price=unit_price,
unit=unit,
description=description,
quantity=quantity
)
return redirect('budget_detail', branch_id=branch_id, budget_id=budget_id)
def delete_equipment_budget(request, branch_id, budget_id, equipment_budget_id):
branch = Branch.objects.get(pk=branch_id)
budget = Budget.objects.get(pk=budget_id, branch=branch)
equipment_budget = EquipmentBudget.objects.get(pk=equipment_budget_id, budget=budget)
equipment_budget.delete()
return redirect('budget_detail', branch_id=branch_id, budget_id=budget_id)
def delete_infrastructure_budget(request, branch_id, budget_id, infrastructure_budget_id):
branch = Branch.objects.get(pk=branch_id)
budget = Budget.objects.get(pk=budget_id, branch=branch)
infrastructure_budget = InfrastructureBudget.objects.get(pk=infrastructure_budget_id, budget=budget)
infrastructure_budget.delete()
return redirect('budget_detail', branch_id=branch_id, budget_id=budget_id)