174 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
from django.db import models
 | 
						|
from apps.system.models import Post, User
 | 
						|
 | 
						|
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
 | 
						|
 | 
						|
 | 
						|
class Employee(CommonBModel):
 | 
						|
    """
 | 
						|
    员工信息
 | 
						|
    """
 | 
						|
    JOB_ON = 10
 | 
						|
    JOB_OFF = 20
 | 
						|
    JOB_RETIRE = 30
 | 
						|
    jobstate_choices = (
 | 
						|
        (JOB_ON, '在职'),
 | 
						|
        (JOB_OFF, '离职'),
 | 
						|
        (JOB_RETIRE, '退休')
 | 
						|
    )
 | 
						|
    PEOPLE_TYPE_CHOICES = (
 | 
						|
        ('employee', '内部员工'),
 | 
						|
        ('remployee', '相关方人员'),
 | 
						|
        ('visitor', '访客'),
 | 
						|
        ('driver', '司机')
 | 
						|
    )
 | 
						|
    type = models.CharField('人员类型', default='employee',
 | 
						|
                            max_length=10, choices=PEOPLE_TYPE_CHOICES)
 | 
						|
    user = models.OneToOneField(User,
 | 
						|
                                verbose_name='系统账号',
 | 
						|
                                related_name='employee',
 | 
						|
                                on_delete=models.SET_NULL, null=True, blank=True)
 | 
						|
    name = models.CharField('姓名', max_length=20)
 | 
						|
    phone = models.CharField('手机号', max_length=11, null=True, blank=True)
 | 
						|
    email = models.EmailField('邮箱号', null=True, blank=True)
 | 
						|
    number = models.CharField('人员编号', max_length=50, null=True, blank=True)
 | 
						|
    photo = models.CharField('证件照', max_length=1000, null=True, blank=True)
 | 
						|
    id_number = models.CharField(
 | 
						|
        '身份证号', max_length=100, null=True, blank=True, unique=True)
 | 
						|
    gender = models.CharField('性别', max_length=10, default='男')
 | 
						|
    signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
 | 
						|
    birthday = models.DateField('出生年月日', null=True, blank=True)
 | 
						|
    qualification = models.CharField(
 | 
						|
        '学历', max_length=50, null=True, blank=True)
 | 
						|
    job_state = models.IntegerField(
 | 
						|
        '在职状态', choices=jobstate_choices, default=10)
 | 
						|
    is_atwork = models.BooleanField('当前在岗', default=False)
 | 
						|
    show_atwork = models.BooleanField('是否展示在岗状态', default=True)
 | 
						|
    last_check_time = models.DateTimeField('打卡时间', null=True, blank=True)
 | 
						|
    not_work_remark = models.CharField(
 | 
						|
        '当前未打卡说明', null=True, blank=True, max_length=200)
 | 
						|
    third_info = models.JSONField(
 | 
						|
        '三方信息', default=dict, null=False, blank=True)  # 主要是定位卡信息
 | 
						|
    post = models.ForeignKey(Post, verbose_name='所属岗位',
 | 
						|
                             on_delete=models.SET_NULL, null=True, blank=True)
 | 
						|
    face_data = models.JSONField(
 | 
						|
        '人脸数据', null=True, blank=True)  # 存储的是字典(模型名:人脸数据)
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        verbose_name = '员工补充信息'
 | 
						|
        verbose_name_plural = verbose_name
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.name
 | 
						|
 | 
						|
    def save(self, *args, **kwargs) -> None:
 | 
						|
        return super().save(*args, **kwargs)
 | 
						|
 | 
						|
 | 
						|
# class Card(CommonAModel):
 | 
						|
#     """
 | 
						|
#     卡
 | 
						|
#     """
 | 
						|
#     CARD_FACE = 10
 | 
						|
#     CARD_LOCATION = 20
 | 
						|
 | 
						|
 | 
						|
class NotWorkRemark(CommonADModel):
 | 
						|
    """
 | 
						|
    离岗说明
 | 
						|
    """
 | 
						|
    not_work_date = models.DateField('未打卡日期')
 | 
						|
    user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE)
 | 
						|
    remark = models.CharField('未打卡说明', null=True, blank=True, max_length=200)
 | 
						|
 | 
						|
 | 
						|
class Attendance(CommonADModel):
 | 
						|
    """
 | 
						|
    到岗记录
 | 
						|
    """
 | 
						|
    ATT_STATE_CHOICES = [
 | 
						|
        ('pending', '待定'),
 | 
						|
        ('normal', '正常'),
 | 
						|
        ('late', '迟到'),
 | 
						|
        ('early_leave', '早退'),
 | 
						|
        ('absent', '未到岗'),
 | 
						|
        ('leave', '请假'),
 | 
						|
        # 可以根据需要添加更多状态
 | 
						|
    ]
 | 
						|
 | 
						|
    user = models.ForeignKey(
 | 
						|
        User, verbose_name='关联人员', on_delete=models.CASCADE)
 | 
						|
    work_date = models.DateField('工作日期')
 | 
						|
    shift = models.ForeignKey(
 | 
						|
        'mtm.shift', verbose_name='班次', on_delete=models.CASCADE)
 | 
						|
    team = models.ForeignKey('mtm.team', verbose_name='班组',
 | 
						|
                             on_delete=models.SET_NULL, null=True, blank=True)
 | 
						|
    post = models.ForeignKey('system.post', verbose_name='岗位',
 | 
						|
                             on_delete=models.SET_NULL, null=True, blank=True)
 | 
						|
    work_time_start = models.DateTimeField('工作开始时间')
 | 
						|
    work_time_end = models.DateTimeField('工作结束时间')
 | 
						|
    state = models.CharField('状态', max_length=20,
 | 
						|
                             choices=ATT_STATE_CHOICES, default='pending', help_text=str(ATT_STATE_CHOICES))
 | 
						|
    note = models.TextField('备注信息', default='', blank=True)
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        unique_together = ('user', 'work_date', 'shift')
 | 
						|
 | 
						|
 | 
						|
class ClockRecord(BaseModel):
 | 
						|
    """
 | 
						|
    打卡记录
 | 
						|
    """
 | 
						|
    ClOCK_ON = 10
 | 
						|
    CLOCK_OFF = 20
 | 
						|
    CLOCK_ING = 30
 | 
						|
    type_choice = (
 | 
						|
        (ClOCK_ON, '上班打卡'),
 | 
						|
        (CLOCK_OFF, '下班打卡'),
 | 
						|
        (CLOCK_ING, '忽略'),  # 尽量不用
 | 
						|
    )
 | 
						|
    E_TYPE_LESS = 10
 | 
						|
    E_TYPE_MORE = 20
 | 
						|
    E_TYPE_MISS = 30
 | 
						|
    E_TYPE_ADD = 40
 | 
						|
    E_TYPE_CHOISE = (
 | 
						|
        (E_TYPE_LESS, '在岗时间短'),
 | 
						|
        (E_TYPE_MORE, '在岗时间长'),
 | 
						|
        (E_TYPE_MISS, '缺卡'),
 | 
						|
        (E_TYPE_ADD, '加班')
 | 
						|
    )
 | 
						|
    type = models.PositiveSmallIntegerField(
 | 
						|
        '打卡类型', choices=type_choice, default=ClOCK_ON)
 | 
						|
    employee = models.ForeignKey(
 | 
						|
        Employee, verbose_name='对应人员', on_delete=models.CASCADE)
 | 
						|
    clock_time = models.DateTimeField('打卡时间', null=True, blank=True)
 | 
						|
    # panel, location, door, manual
 | 
						|
    trigger = models.CharField('触发', max_length=20)
 | 
						|
    detail = models.JSONField('相关记录', default=dict,
 | 
						|
                              null=False, blank=True)  # 里面主要有对应的ID值
 | 
						|
    exception_type = models.PositiveSmallIntegerField(
 | 
						|
        '异常类型', choices=E_TYPE_CHOISE, null=True, blank=True)
 | 
						|
    note = models.CharField('备注', max_length=20, default='')
 | 
						|
    attendance = models.ForeignKey(
 | 
						|
        Attendance, on_delete=models.SET_NULL, verbose_name='关联到岗记录', null=True, blank=True)
 | 
						|
 | 
						|
 | 
						|
class Certificate(CommonAModel):
 | 
						|
    """
 | 
						|
    证书
 | 
						|
    """
 | 
						|
    CERTIFICATE_TYPE_CHOICES = (
 | 
						|
        (10, '特种作业证书'),
 | 
						|
        (20, '特种设备操作证书'),
 | 
						|
        (30, '安全管理人员证书')
 | 
						|
    )
 | 
						|
    employee = models.ForeignKey(
 | 
						|
        Employee, verbose_name='对应人员', on_delete=models.CASCADE)
 | 
						|
    name = models.CharField('证书名称', max_length=20)
 | 
						|
    number = models.CharField('证书编号', max_length=20)
 | 
						|
    type = models.PositiveSmallIntegerField('证书类型', default=10)
 | 
						|
    issue_date = models.DateField('发证日期')
 | 
						|
    expiration_date = models.DateField('有效期')
 | 
						|
    review_date = models.DateField('下一次复审日期')
 | 
						|
    file = models.TextField('文件地址', null=True, blank=True)
 |