diff --git a/backend/apps/material/management/commands/import_materials_from_excel.py b/backend/apps/material/management/commands/import_materials_from_excel.py
index 777f5e5..8d71276 100644
--- a/backend/apps/material/management/commands/import_materials_from_excel.py
+++ b/backend/apps/material/management/commands/import_materials_from_excel.py
@@ -245,8 +245,6 @@ class Command(BaseCommand):
material_subcategory = _single_line(get(row, "材料子类"))
if not material_category:
material_category = "-"
- if not material_subcategory:
- material_subcategory = "-"
application_scene = _parse_application_scene(get(row, "应用场景"))
replace_type = REPLACE_TYPE_MAP.get(_cell(get(row, "替代材料")))
@@ -256,9 +254,14 @@ class Command(BaseCommand):
"name": name[:255],
"major_category": major_category,
"material_category": material_category,
- "material_subcategory": material_subcategory,
+ "material_subcategory": material_subcategory or None,
"stage": _parse_choice(get(row, "阶段"), STAGE_VALUES),
"importance_level": _parse_choice(get(row, "重要等级"), IMPORTANCE_LEVEL_VALUES),
+ "landing_project": _single_line(get(row, "落地项目")) or None,
+ "contact_person": _single_line(get(row, "对接人")) or None,
+ "contact_phone": _single_line(get(row, "对接人联系方式")) or None,
+ "handler": _single_line(get(row, "经办人")) or None,
+ "remark": _single_line(get(row, "备注")) or None,
"spec": _single_line(get(row, "规格型号")) or None,
"standard": _single_line(get(row, "符合标准")) or None,
"application_scene": application_scene or None,
diff --git a/backend/apps/material/migrations/0005_alter_material_options_and_more.py b/backend/apps/material/migrations/0005_alter_material_options_and_more.py
new file mode 100644
index 0000000..c4381df
--- /dev/null
+++ b/backend/apps/material/migrations/0005_alter_material_options_and_more.py
@@ -0,0 +1,38 @@
+# Generated by Django 4.2.7 on 2026-03-19 01:19
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('material', '0004_alter_material_options_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='material',
+ name='contact_person',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='对接人'),
+ ),
+ migrations.AddField(
+ model_name='material',
+ name='contact_phone',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='对接人联系方式'),
+ ),
+ migrations.AddField(
+ model_name='material',
+ name='handler',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='经办人'),
+ ),
+ migrations.AddField(
+ model_name='material',
+ name='landing_project',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='落地项目'),
+ ),
+ migrations.AddField(
+ model_name='material',
+ name='remark',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='备注'),
+ ),
+ ]
diff --git a/backend/apps/material/migrations/0006_alter_material_options_and_more.py b/backend/apps/material/migrations/0006_alter_material_options_and_more.py
new file mode 100644
index 0000000..7b3c82c
--- /dev/null
+++ b/backend/apps/material/migrations/0006_alter_material_options_and_more.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.7 on 2026-03-19 01:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('material', '0005_alter_material_options_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='material',
+ name='material_subcategory',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='材料子分类'),
+ ),
+ ]
diff --git a/backend/apps/material/models.py b/backend/apps/material/models.py
index b876f15..b3b7d7d 100644
--- a/backend/apps/material/models.py
+++ b/backend/apps/material/models.py
@@ -59,9 +59,14 @@ class Material(models.Model):
name = models.CharField(max_length=255, verbose_name='材料名称')
major_category = models.CharField(max_length=20, choices=MAJOR_CATEGORY_CHOICES, verbose_name='专业类别')
material_category = models.CharField(max_length=255, verbose_name='材料分类')
- material_subcategory = models.CharField(max_length=255, verbose_name='材料子分类')
+ material_subcategory = models.CharField(max_length=255, blank=True, null=True, verbose_name='材料子分类')
stage = models.CharField(max_length=20, choices=STAGE_CHOICES, blank=True, null=True, verbose_name='阶段')
importance_level = models.CharField(max_length=20, choices=IMPORTANCE_LEVEL_CHOICES, blank=True, null=True, verbose_name='重要等级')
+ landing_project = models.CharField(max_length=255, blank=True, null=True, verbose_name='落地项目')
+ contact_person = models.CharField(max_length=255, blank=True, null=True, verbose_name='对接人')
+ contact_phone = models.CharField(max_length=255, blank=True, null=True, verbose_name='对接人联系方式')
+ handler = models.CharField(max_length=255, blank=True, null=True, verbose_name='经办人')
+ remark = models.CharField(max_length=255, blank=True, null=True, verbose_name='备注')
spec = models.CharField(max_length=255, blank=True, null=True, verbose_name='规格型号')
standard = models.CharField(max_length=255, blank=True, null=True, verbose_name='符合标准')
application_scene = models.JSONField(default=list, blank=True, null=True, verbose_name='应用场景')
diff --git a/backend/apps/material/serializers.py b/backend/apps/material/serializers.py
index e1f2f3c..ce28f98 100644
--- a/backend/apps/material/serializers.py
+++ b/backend/apps/material/serializers.py
@@ -44,7 +44,8 @@ class MaterialSerializer(serializers.ModelSerializer):
model = Material
fields = ['id', 'name', 'major_category', 'major_category_display',
'material_category', 'material_subcategory', 'stage', 'stage_display',
- 'importance_level', 'importance_level_display', 'spec', 'standard',
+ 'importance_level', 'importance_level_display', 'landing_project',
+ 'contact_person', 'contact_phone', 'handler', 'remark', 'spec', 'standard',
'application_scene', 'application_scene_display', 'application_desc',
'replace_type', 'replace_type_display', 'advantage', 'advantage_display',
'advantage_desc', 'cost_compare', 'cost_desc', 'cases', 'brochure',
@@ -91,7 +92,8 @@ class MaterialListSerializer(serializers.ModelSerializer):
model = Material
fields = ['id', 'name', 'major_category', 'major_category_display',
'material_category', 'material_subcategory', 'stage', 'stage_display',
- 'importance_level', 'importance_level_display', 'factory',
+ 'importance_level', 'importance_level_display', 'landing_project',
+ 'contact_person', 'contact_phone', 'handler', 'remark', 'factory',
'factory_name', 'brand', 'status', 'status_display']
diff --git a/frontend/src/views/MaterialDetail.vue b/frontend/src/views/MaterialDetail.vue
index 298e870..6b85317 100644
--- a/frontend/src/views/MaterialDetail.vue
+++ b/frontend/src/views/MaterialDetail.vue
@@ -12,6 +12,11 @@
{{ displayText(material.material_subcategory) }}
{{ displayText(material.stage_display) }}
{{ displayText(material.importance_level_display) }}
+ {{ displayText(material.landing_project) }}
+ {{ displayText(material.contact_person) }}
+ {{ displayText(material.contact_phone) }}
+ {{ displayText(material.handler) }}
+ {{ displayText(material.remark) }}
{{ displayText(material.spec) }}
{{ displayText(material.standard) }}
{{ displayList(material.application_scene_display) }}
diff --git a/frontend/src/views/MaterialManage.vue b/frontend/src/views/MaterialManage.vue
index f9f0567..414b4e1 100644
--- a/frontend/src/views/MaterialManage.vue
+++ b/frontend/src/views/MaterialManage.vue
@@ -20,6 +20,11 @@
+
+
+
+
+
@@ -63,8 +68,8 @@
-
-
+
+
@@ -78,6 +83,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -214,6 +234,11 @@ const form = reactive({
material_subcategory: '',
stage: '',
importance_level: '',
+ landing_project: '',
+ contact_person: '',
+ contact_phone: '',
+ handler: '',
+ remark: '',
spec: '',
standard: '',
application_scene: [],
@@ -311,6 +336,11 @@ const resetForm = () => {
material_subcategory: '',
stage: '',
importance_level: '',
+ landing_project: '',
+ contact_person: '',
+ contact_phone: '',
+ handler: '',
+ remark: '',
spec: '',
standard: '',
application_scene: [],
@@ -397,10 +427,11 @@ const onSave = async () => {
await updateMaterial(currentId.value, payload)
} else {
await createMaterial(payload)
+ pagination.page = 1
}
ElMessage.success('保存成功')
dialogVisible.value = false
- loadMaterials()
+ await loadMaterials()
} catch (error) {
ElMessage.error(error.response?.data?.detail || '保存失败')
}