Files
fonrey/apps/org/models/staff.py
ishenwei f185127335 feat(org): add Chinese verbose_name and help_text to all org fields (Phase 4.1 part 4/9)
Sync DATA_MODEL_ORG.md field-level Chinese annotations to Django
models across 11 org tables (OrgUnit, Staff, StaffPersonalInfo,
StaffTransferLog, StaffRewardPunish, StaffAccount, StaffWorkExperience,
StaffEducation, StaffTraining, StaffFamilyMember, StaffRemark).
2026-04-30 09:25:17 +08:00

366 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.conf import settings
from django.db import models
from core.enums import StaffGender, StaffIdType, StaffRole, StaffStatus
from core.models.base import SoftDeleteModel
class Staff(SoftDeleteModel):
org_unit = models.ForeignKey(
"org.OrgUnit",
on_delete=models.RESTRICT,
related_name="staff_members",
db_index=True,
verbose_name="所属组织节点",
help_text="当前所属组织节点(门店或店组)",
)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="staff_profile",
verbose_name="登录账号",
help_text="Django auth 登录账号",
)
name = models.CharField(
max_length=50,
verbose_name="真实姓名",
)
nickname = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="昵称",
help_text="通讯录/显示名",
)
employee_no = models.CharField(
max_length=30,
null=True,
blank=True,
unique=True,
verbose_name="员工工号",
help_text="系统自动生成或手动录入",
)
role = models.CharField(
max_length=30,
choices=StaffRole.choices,
verbose_name="系统角色",
help_text="agent=经纪人 / store_manager=店长 / area_manager=区域经理 / admin=管理员 / operator=运营 / system=系统账号",
)
job_title = models.CharField(
max_length=100,
blank=True,
default="",
verbose_name="职务名称",
help_text='如「高级业务员」',
)
job_category = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="职务类别",
help_text='如「置业顾问」(经纪人判定字段)',
)
job_level = models.SmallIntegerField(
null=True,
blank=True,
verbose_name="职级",
)
supervisor = models.ForeignKey(
"self",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="subordinates",
verbose_name="直属上级",
)
status = models.CharField(
max_length=20,
choices=StaffStatus.choices,
default=StaffStatus.ACTIVE,
verbose_name="员工状态",
help_text="active=在职 / probation=试用期 / resigned=已离职 / frozen=账号冻结",
)
phone_enc = models.BinaryField(
null=True,
blank=True,
verbose_name="手机号(加密)",
help_text="AES-256-GCM 加密手机号",
)
phone_hash = models.CharField(
max_length=64,
null=True,
blank=True,
db_index=True,
verbose_name="手机号哈希",
help_text="SHA-256 哈希,用于唯一性索引",
)
phone_hide = models.BooleanField(
default=False,
verbose_name="通讯录隐藏手机号",
)
email = models.EmailField(
max_length=255,
blank=True,
default="",
verbose_name="邮箱",
)
extension = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="分机号",
)
avatar_key = models.TextField(
blank=True,
default="",
verbose_name="头像存储路径",
help_text="R2/S3 头像路径",
)
is_active = models.BooleanField(
default=True,
verbose_name="是否启用",
help_text="FALSE 时账号不可登录(联动 auth_user.is_active",
)
is_system_admin = models.BooleanField(
default=False,
verbose_name="是否系统管理员",
help_text="影响权限上限",
)
first_joined_at = models.DateField(
null=True,
blank=True,
verbose_name="首次入职日期",
help_text="计算工龄起点",
)
rejoined_at = models.DateField(
null=True,
blank=True,
verbose_name="最近复职日期",
)
resigned_at = models.DateField(
null=True,
blank=True,
verbose_name="最近离职日期",
)
joined_count = models.SmallIntegerField(
default=1,
verbose_name="累计入职次数",
)
industry_exp_years = models.SmallIntegerField(
null=True,
blank=True,
verbose_name="行业经验",
help_text="单位:年",
)
mentor = models.ForeignKey(
"self",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="mentees",
verbose_name="师傅",
help_text="带教员工",
)
business_type = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="业务类型",
)
bank_name = models.CharField(
max_length=100,
blank=True,
default="",
verbose_name="银行名称",
)
bank_account = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="银行卡号",
help_text="内部财务用",
)
partner_no = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="联号",
)
recruit_by = models.ForeignKey(
"self",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="recruited_staff",
verbose_name="招聘人",
)
recruit_source = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="招聘来源",
)
referrer = models.ForeignKey(
"self",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="referred_staff",
verbose_name="转介人",
)
class Meta:
db_table = "staff"
verbose_name = "员工"
verbose_name_plural = "员工"
indexes = [
models.Index(fields=["org_unit"], name="idx_staff_org_unit"),
models.Index(fields=["supervisor"], name="idx_staff_supervisor"),
models.Index(fields=["status"], name="idx_staff_status"),
]
def __str__(self) -> str:
return self.name
class StaffPersonalInfo(models.Model):
staff = models.OneToOneField(
"org.Staff",
on_delete=models.CASCADE,
related_name="personal_info",
primary_key=True,
verbose_name="所属员工",
)
gender = models.CharField(
max_length=10,
choices=StaffGender.choices,
blank=True,
default="",
verbose_name="性别",
help_text="male=男 / female=女 / unknown=未知",
)
id_type = models.CharField(
max_length=20,
choices=StaffIdType.choices,
blank=True,
default="",
verbose_name="证件类型",
help_text="id_card=身份证 / passport=护照 / other=其他",
)
id_number_enc = models.BinaryField(
null=True,
blank=True,
verbose_name="证件号码(加密)",
help_text="AES 加密",
)
id_number_hash = models.CharField(
max_length=64,
null=True,
blank=True,
db_index=True,
verbose_name="证件号码哈希",
help_text="SHA-256 哈希,实名认证比对用",
)
id_verified = models.BooleanField(
default=False,
verbose_name="是否实名认证",
)
id_verified_at = models.DateTimeField(
null=True,
blank=True,
verbose_name="认证时间",
)
birthdate = models.DateField(
null=True,
blank=True,
verbose_name="出生日期",
)
native_place = models.CharField(
max_length=100,
blank=True,
default="",
verbose_name="籍贯",
)
domicile_type = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="户籍性质",
)
marital_status = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="婚姻状况",
)
political_status = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="政治面貌",
)
has_children = models.BooleanField(
null=True,
blank=True,
verbose_name="有无子女",
)
education_level = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="最高学历",
)
ethnicity = models.CharField(
max_length=20,
blank=True,
default="",
verbose_name="民族",
)
domicile_address = models.CharField(
max_length=200,
blank=True,
default="",
verbose_name="户口所在地",
)
residence_address = models.CharField(
max_length=200,
blank=True,
default="",
verbose_name="居住地址",
)
work_start_date = models.DateField(
null=True,
blank=True,
verbose_name="参加工作时间",
)
emergency_contact = models.CharField(
max_length=50,
blank=True,
default="",
verbose_name="紧急联系人",
)
emergency_phone_enc = models.BinaryField(
null=True,
blank=True,
verbose_name="紧急联系人电话(加密)",
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="最后更新时间",
)
updated_by = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="updated_personal_info",
verbose_name="最后修改人",
)
class Meta:
db_table = "staff_personal_info"
verbose_name = "员工个人信息"
verbose_name_plural = "员工个人信息"