feat(client): add Chinese verbose_name and help_text to all client fields (Phase 4.1 part 2/9)

Sync DATA_MODEL_CLIENT.md field-level Chinese annotations to Django
models across 11 client tables (Client, ClientContact, ClientRequirement,
ClientSchoolPreference, ClientFavoriteFolder, ClientFolderItem,
ClientFollowLog, ClientFollowLogAttachment, ClientViewing,
ClientPropertyMatch, ClientStatusLog).

Pre-existing docstrings retained on ClientFollowLog (partitioned parent
treated as unmanaged) and ClientStatusLog (immutable audit log).
This commit is contained in:
2026-04-30 09:19:58 +08:00
parent 3638fc0302
commit e67b07a7c8
5 changed files with 678 additions and 121 deletions

View File

@@ -14,35 +14,103 @@ from core.models.base import UUIDPrimaryKeyModel
class ClientContact(UUIDPrimaryKeyModel):
client = models.ForeignKey(
"fonrey_client.Client", on_delete=models.CASCADE, related_name="contacts"
"fonrey_client.Client",
on_delete=models.CASCADE,
related_name="contacts",
verbose_name="所属客源",
help_text="联系人随客源级联删除",
)
sort_order = models.SmallIntegerField(
default=0,
verbose_name="排序顺序",
help_text="sort_order=0 为主联系人,姓名用于客源姓名显示",
)
name = models.CharField(
max_length=50,
verbose_name="联系人姓名",
)
sort_order = models.SmallIntegerField(default=0)
name = models.CharField(max_length=50)
gender = models.CharField(
max_length=10, choices=ClientContactGender.choices, default=ClientContactGender.MALE
max_length=10,
choices=ClientContactGender.choices,
default=ClientContactGender.MALE,
verbose_name="性别",
help_text="male=先生 / female=女士",
)
phone_enc = models.BinaryField()
phone_hash = models.CharField(max_length=64)
phone_country_code = models.CharField(max_length=10, default="+86")
phone_is_invalid = models.BooleanField(default=False)
phone_enc = models.BinaryField(
verbose_name="手机号(加密)",
help_text="AES-256-GCM 加密手机号电话1",
)
phone_hash = models.CharField(
max_length=64,
verbose_name="手机号哈希",
help_text="SHA-256 哈希(重复检测)",
)
phone_country_code = models.CharField(
max_length=10,
default="+86",
verbose_name="国际区号",
)
phone_is_invalid = models.BooleanField(
default=False,
verbose_name="号码是否无效",
help_text="标记无效后该号码不再参与重复检测",
)
phone2_enc = models.BinaryField(null=True, blank=True)
phone2_hash = models.CharField(max_length=64, blank=True, default="")
phone2_enc = models.BinaryField(
null=True,
blank=True,
verbose_name="备用电话2加密",
)
phone2_hash = models.CharField(
max_length=64,
blank=True,
default="",
verbose_name="备用电话2哈希",
help_text="SHA-256用于重复检测",
)
wechat = models.CharField(max_length=100, blank=True, default="")
qq = models.CharField(max_length=20, blank=True, default="")
remarks = models.CharField(max_length=200, blank=True, default="")
wechat = models.CharField(
max_length=100,
blank=True,
default="",
verbose_name="微信号",
)
qq = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="QQ号",
)
remarks = models.CharField(
max_length=200,
blank=True,
default="",
verbose_name="联系人备注",
help_text="最多200字",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
deleted_at = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="创建时间",
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="最后更新时间",
)
deleted_at = models.DateTimeField(
null=True,
blank=True,
verbose_name="删除时间",
help_text="软删除时间戳NULL=未删除(不影响客源本身)",
)
created_by = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="created_client_contacts",
verbose_name="创建人",
)
class Meta:
@@ -58,65 +126,152 @@ class ClientContact(UUIDPrimaryKeyModel):
class ClientRequirement(UUIDPrimaryKeyModel):
client = models.ForeignKey(
"fonrey_client.Client", on_delete=models.CASCADE, related_name="requirements"
"fonrey_client.Client",
on_delete=models.CASCADE,
related_name="requirements",
verbose_name="所属客源",
help_text="需求随客源级联删除",
)
requirement_type = models.CharField(
max_length=20, choices=ClientRequirementType.choices
max_length=20,
choices=ClientRequirementType.choices,
verbose_name="需求类型",
help_text="second_hand=二手 / new_house=新房 / rental=租房",
)
is_primary = models.BooleanField(
default=True,
verbose_name="是否主需求",
help_text="用于列表展示",
)
is_primary = models.BooleanField(default=True)
budget_min = models.DecimalField(
max_digits=12, decimal_places=2, null=True, blank=True
max_digits=12,
decimal_places=2,
null=True,
blank=True,
verbose_name="最低预算",
help_text="单位:万元/元,依据需求类型",
)
budget_max = models.DecimalField(
max_digits=12, decimal_places=2, null=True, blank=True
max_digits=12,
decimal_places=2,
null=True,
blank=True,
verbose_name="最高预算",
)
area_min = models.DecimalField(
max_digits=8, decimal_places=2, null=True, blank=True
max_digits=8,
decimal_places=2,
null=True,
blank=True,
verbose_name="最小面积",
help_text="单位:㎡",
)
area_max = models.DecimalField(
max_digits=8, decimal_places=2, null=True, blank=True
max_digits=8,
decimal_places=2,
null=True,
blank=True,
verbose_name="最大面积",
help_text="单位:㎡",
)
bedroom_counts = ArrayField(
models.SmallIntegerField(), blank=True, default=list
models.SmallIntegerField(),
blank=True,
default=list,
verbose_name="可接受卧室数",
help_text="多选,如 [2,3]",
)
floor_preferences = ArrayField(
models.CharField(max_length=20, choices=ClientFloorPreference.choices),
blank=True,
default=list,
verbose_name="楼层偏好",
help_text="多选no_first=不要一层 / low=低楼层 / mid=中楼层 / high=高楼层 / no_top=不要顶层",
)
orientations = ArrayField(
models.CharField(max_length=10, choices=ClientOrientation.choices),
blank=True,
default=list,
verbose_name="朝向偏好",
help_text="多选east=东 / south=南 / west=西 / north=北",
)
decorations = ArrayField(
models.CharField(max_length=10, choices=ClientDecoration.choices),
blank=True,
default=list,
verbose_name="装修偏好",
help_text="多选(枚举同 properties.decoration",
)
building_age_ranges = ArrayField(
models.CharField(max_length=20, choices=ClientBuildingAgeRange.choices),
blank=True,
default=list,
verbose_name="楼龄偏好",
help_text="多选within_5y / 5_10y / 10_15y / 15_20y / over_20y",
)
intent_district_ids = ArrayField(
models.UUIDField(), blank=True, default=list
models.UUIDField(),
blank=True,
default=list,
verbose_name="意向行政区",
help_text="行政区 ID 数组",
)
intent_business_area_ids = ArrayField(
models.UUIDField(), blank=True, default=list
models.UUIDField(),
blank=True,
default=list,
verbose_name="意向商圈",
help_text="商圈 ID 数组",
)
intent_complex_names = models.TextField(
blank=True,
default="",
verbose_name="意向小区",
help_text="文本逗号分隔最多500字",
)
transportation = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="交通要求",
help_text="最多50字",
)
intent_school_names = models.TextField(
blank=True,
default="",
verbose_name="意向学校",
help_text="文本,逗号分隔",
)
school_enrollment_date = models.DateField(
null=True,
blank=True,
verbose_name="入学时间",
help_text="月份精度取该月1日存储",
)
traffic_preference = models.TextField(
blank=True,
default="",
verbose_name="交通备注",
)
requirement_notes = models.CharField(
max_length=200,
blank=True,
default="",
verbose_name="需求备注",
help_text="最多200字",
)
intent_complex_names = models.TextField(blank=True, default="")
transportation = models.CharField(max_length=50, blank=True, default="")
intent_school_names = models.TextField(blank=True, default="")
school_enrollment_date = models.DateField(null=True, blank=True)
traffic_preference = models.TextField(blank=True, default="")
requirement_notes = models.CharField(max_length=200, blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="创建时间",
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="最后更新时间",
)
class Meta:
db_table = "client_requirements"
@@ -135,10 +290,24 @@ class ClientSchoolPreference(UUIDPrimaryKeyModel):
ClientRequirement,
on_delete=models.CASCADE,
related_name="school_preferences",
verbose_name="所属需求",
help_text="意向学校随需求级联删除",
)
school_id = models.UUIDField(
null=True,
blank=True,
verbose_name="学校ID",
help_text="从学校表选择,允许为 NULL自由输入",
)
school_name = models.CharField(
max_length=100,
verbose_name="学校名称",
help_text="当 school_id 为 NULL 时为手动输入",
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="创建时间",
)
school_id = models.UUIDField(null=True, blank=True)
school_name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "client_school_preferences"