""" 线索表单:FormDefinition 是可复用的表单定义 Snippet,通过 core.blocks.FormBlock 嵌入任意 StreamField 页面;提交结果保存为 Lead。 详见 documents/设计方案分析与完善版.md §2.6(FormBlock)与 B2B 官网核心转化路径。 """ from django.db import models from modelcluster.fields import ParentalKey from modelcluster.models import ClusterableModel from wagtail.admin.panels import FieldPanel, InlinePanel from wagtail.models import Orderable from wagtail.snippets.models import register_snippet FIELD_TYPE_CHOICES = [ ("text", "单行文本"), ("textarea", "多行文本"), ("email", "邮箱"), ("tel", "电话"), ("select", "下拉选择"), ] @register_snippet class FormDefinition(ClusterableModel): """可复用的线索表单定义。""" name = models.CharField(max_length=100, verbose_name="表单名称") submit_button_text = models.CharField( max_length=50, default="提交", verbose_name="提交按钮文案" ) success_message = models.CharField( max_length=200, default="提交成功,我们会尽快与您联系。", verbose_name="提交成功提示", ) notification_email = models.EmailField(blank=True, verbose_name="通知邮箱") panels = [ FieldPanel("name"), FieldPanel("submit_button_text"), FieldPanel("success_message"), FieldPanel("notification_email"), InlinePanel("fields", label="表单字段"), ] class Meta: verbose_name = "线索表单" verbose_name_plural = "线索表单" def __str__(self): return self.name class FormDefinitionField(Orderable): """FormDefinition 的子字段,编辑器在后台可自由增删排序。""" form = ParentalKey( FormDefinition, on_delete=models.CASCADE, related_name="fields" ) label = models.CharField(max_length=100, verbose_name="字段标签") field_key = models.SlugField( max_length=50, verbose_name="字段标识", help_text="提交数据中使用的 key,例如 name / email / phone", ) field_type = models.CharField( max_length=20, choices=FIELD_TYPE_CHOICES, default="text", verbose_name="字段类型" ) required = models.BooleanField(default=True, verbose_name="是否必填") choices = models.CharField( max_length=255, blank=True, verbose_name="可选项", help_text="逗号分隔,仅“下拉选择”类型使用", ) panels = [ FieldPanel("label"), FieldPanel("field_key"), FieldPanel("field_type"), FieldPanel("required"), FieldPanel("choices"), ] @register_snippet class Lead(models.Model): """表单提交产生的线索记录,供销售/市场团队在后台查看。""" form = models.ForeignKey( FormDefinition, on_delete=models.SET_NULL, null=True, related_name="leads", verbose_name="来源表单", ) data = models.JSONField(default=dict, verbose_name="提交数据") source_url = models.URLField(blank=True, verbose_name="来源页面") created_at = models.DateTimeField(auto_now_add=True, verbose_name="提交时间") panels = [ FieldPanel("form"), FieldPanel("data"), FieldPanel("source_url"), ] class Meta: verbose_name = "线索" verbose_name_plural = "线索" ordering = ["-created_at"] def __str__(self): form_name = self.form.name if self.form_id else "(表单已删除)" return f"{form_name} - {self.created_at:%Y-%m-%d %H:%M}"