You've already forked opc-backend
130 lines
6.6 KiB
Python
130 lines
6.6 KiB
Python
|
|
import uuid
|
||
|
|
from django.db import models
|
||
|
|
|
||
|
|
class TaskStatus(models.TextChoices):
|
||
|
|
DRAFT = 'DRAFT', '草稿'
|
||
|
|
OPEN = 'OPEN', '已发布'
|
||
|
|
IN_PROGRESS = 'IN_PROGRESS', '进行中'
|
||
|
|
IN_REVIEW = 'IN_REVIEW', '待验收'
|
||
|
|
COMPLETED = 'COMPLETED', '已完成'
|
||
|
|
CANCELLED = 'CANCELLED', '已取消'
|
||
|
|
|
||
|
|
class ApplyStatus(models.TextChoices):
|
||
|
|
PENDING = 'PENDING', '待审核'
|
||
|
|
APPROVED = 'APPROVED', '已录用'
|
||
|
|
REJECTED = 'REJECTED', '已拒绝'
|
||
|
|
WITHDRAWN = 'WITHDRAWN', '已撤回'
|
||
|
|
DELIVERED = 'DELIVERED', '交付待验收'
|
||
|
|
COMPLETED = 'COMPLETED', '已完成'
|
||
|
|
|
||
|
|
class Task(models.Model):
|
||
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||
|
|
publisher = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='published_tasks')
|
||
|
|
enterprise = models.ForeignKey('users.Enterprise', on_delete=models.SET_NULL, null=True, blank=True, related_name='tasks')
|
||
|
|
title = models.CharField(max_length=256)
|
||
|
|
description = models.TextField()
|
||
|
|
skill_tags = models.JSONField(default=list)
|
||
|
|
budget_min = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
|
||
|
|
budget_max = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
|
||
|
|
currency = models.CharField(max_length=8, default='CNY')
|
||
|
|
deadline = models.DateField(null=True, blank=True)
|
||
|
|
task_type = models.CharField(max_length=64, null=True, blank=True)
|
||
|
|
attachments = models.JSONField(default=list)
|
||
|
|
contact_user = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='+')
|
||
|
|
contact_name = models.CharField(max_length=64, null=True, blank=True)
|
||
|
|
contact_phone = models.CharField(max_length=32, null=True, blank=True)
|
||
|
|
contact_email = models.EmailField(null=True, blank=True)
|
||
|
|
contact_wechat = models.CharField(max_length=64, null=True, blank=True)
|
||
|
|
status = models.CharField(max_length=16, choices=TaskStatus.choices, default=TaskStatus.DRAFT)
|
||
|
|
assignee = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='assigned_tasks')
|
||
|
|
assigned_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
completed_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
completion_note = models.TextField(null=True, blank=True)
|
||
|
|
deliverables = models.JSONField(default=list)
|
||
|
|
cancelled_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
cancel_reason = models.TextField(null=True, blank=True)
|
||
|
|
is_deleted = models.BooleanField(default=False)
|
||
|
|
is_recommended = models.BooleanField(default=False, help_text='管理员推荐')
|
||
|
|
recommend_priority = models.IntegerField(default=0, help_text='推荐优先级, 越大越靠前')
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
updated_at = models.DateTimeField(auto_now=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
db_table = 'tasks'
|
||
|
|
ordering = ['-is_recommended', '-recommend_priority', '-created_at']
|
||
|
|
|
||
|
|
class TaskApplication(models.Model):
|
||
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||
|
|
task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='applications')
|
||
|
|
applicant = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='task_applications')
|
||
|
|
cover_letter = models.TextField(null=True, blank=True)
|
||
|
|
expected_days = models.IntegerField(null=True, blank=True)
|
||
|
|
expected_price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
|
||
|
|
attachments = models.JSONField(default=list)
|
||
|
|
negotiation_history = models.JSONField(default=list)
|
||
|
|
status = models.CharField(max_length=16, choices=ApplyStatus.choices, default=ApplyStatus.PENDING)
|
||
|
|
reject_reason = models.TextField(null=True, blank=True)
|
||
|
|
reviewed_by = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='reviewed_applications')
|
||
|
|
reviewed_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
deliverables = models.JSONField(default=list)
|
||
|
|
completion_note = models.TextField(null=True, blank=True)
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
updated_at = models.DateTimeField(auto_now=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
db_table = 'task_applications'
|
||
|
|
unique_together = ('task', 'applicant')
|
||
|
|
ordering = ['-created_at']
|
||
|
|
|
||
|
|
class InvitationStatus(models.TextChoices):
|
||
|
|
PENDING = 'PENDING', '待处理'
|
||
|
|
ACCEPTED = 'ACCEPTED', '已接受'
|
||
|
|
REJECTED = 'REJECTED', '已拒绝'
|
||
|
|
DISCUSSING = 'DISCUSSING', '洽谈中'
|
||
|
|
|
||
|
|
class TaskInvitation(models.Model):
|
||
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||
|
|
task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='invitations')
|
||
|
|
expert = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='task_invitations')
|
||
|
|
message = models.TextField(null=True, blank=True)
|
||
|
|
messages = models.JSONField(default=list)
|
||
|
|
status = models.CharField(max_length=16, choices=InvitationStatus.choices, default=InvitationStatus.PENDING)
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
updated_at = models.DateTimeField(auto_now=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
db_table = 'task_invitations'
|
||
|
|
unique_together = ('task', 'expert')
|
||
|
|
ordering = ['-created_at']
|
||
|
|
|
||
|
|
class DeliveryStatus(models.TextChoices):
|
||
|
|
PENDING = 'PENDING', '待验收'
|
||
|
|
APPROVED = 'APPROVED', '已验收'
|
||
|
|
REJECTED = 'REJECTED', '已驳回'
|
||
|
|
|
||
|
|
class DeliveryRecord(models.Model):
|
||
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||
|
|
application = models.ForeignKey(TaskApplication, on_delete=models.CASCADE, related_name='delivery_records')
|
||
|
|
note = models.TextField()
|
||
|
|
files = models.JSONField(default=list)
|
||
|
|
status = models.CharField(max_length=16, choices=DeliveryStatus.choices, default=DeliveryStatus.PENDING)
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
updated_at = models.DateTimeField(auto_now=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
db_table = 'delivery_records'
|
||
|
|
ordering = ['-created_at']
|
||
|
|
|
||
|
|
class TaskReview(models.Model):
|
||
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||
|
|
task = models.OneToOneField(Task, on_delete=models.CASCADE, related_name='review')
|
||
|
|
reviewer = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='given_reviews')
|
||
|
|
reviewee = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='received_reviews')
|
||
|
|
score = models.IntegerField(default=5) # 1 to 5
|
||
|
|
comment = models.TextField(null=True, blank=True)
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
db_table = 'task_reviews'
|
||
|
|
ordering = ['-created_at']
|