feat: init commint

This commit is contained in:
2026-09-18 15:26:19 +08:00
parent 3b61a767a0
commit 9f47dbb5cc
95 changed files with 7712 additions and 1137 deletions

View File

@@ -108,6 +108,13 @@ class Ticket(models.Model):
on_delete=models.SET_NULL,
related_name="created_tickets",
)
follow_up_of = models.ForeignKey(
"self",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="follow_up_tickets",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
resolved_at = models.DateTimeField(null=True, blank=True)
@@ -286,6 +293,8 @@ class TicketDraft(models.Model):
message_timeline = models.JSONField(default=list)
missing_fields = models.JSONField(default=list)
questions = models.JSONField(default=list)
blocking_missing_fields = models.JSONField(default=list)
blocking_questions = models.JSONField(default=list)
guided_rounds = models.PositiveSmallIntegerField(default=0)
latest_agent_run = models.ForeignKey(
"agents.AgentRun",
@@ -549,6 +558,7 @@ class TicketSupportAnalysis(models.Model):
query = models.TextField()
references = models.JSONField(default=list)
retrieval_policy = models.JSONField(default=dict)
result_mode = models.CharField(max_length=24, default="trusted")
automation_decision = models.JSONField(default=dict, blank=True)
applied_solution = models.ForeignKey(
"solutions.Solution",
@@ -665,6 +675,131 @@ class CustomerReplyRevision(models.Model):
]
class TicketAutomationRunStatus(models.TextChoices):
QUEUED = "queued", "Queued"
RUNNING = "running", "Running"
WAITING_INPUT = "waiting_input", "Waiting input"
WAITING_APPROVAL = "waiting_approval", "Waiting approval"
WAITING_DELIVERY = "waiting_delivery", "Waiting delivery"
WAITING_CUSTOMER = "waiting_customer", "Waiting customer"
COMPLETED = "completed", "Completed"
FAILED = "failed", "Failed"
CANCELLED = "cancelled", "Cancelled"
class TicketAutomationRun(models.Model):
"""工单端到端自动处理的持久化编排状态。"""
public_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
ticket = models.ForeignKey(
Ticket,
on_delete=models.CASCADE,
related_name="automation_runs",
)
status = models.CharField(
max_length=32,
choices=TicketAutomationRunStatus.choices,
default=TicketAutomationRunStatus.QUEUED,
)
current_step = models.CharField(max_length=48, default="intake")
policy_snapshot = models.JSONField(default=dict, blank=True)
blocking_missing_fields = models.JSONField(default=list, blank=True)
blocking_questions = models.JSONField(default=list, blank=True)
retry_count = models.PositiveSmallIntegerField(default=0)
last_error_code = models.CharField(max_length=80, blank=True)
last_error_message = models.TextField(blank=True)
next_action_at = models.DateTimeField(null=True, blank=True)
support_analysis = models.ForeignKey(
TicketSupportAnalysis,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="automation_runs",
)
reply_task = models.ForeignKey(
CustomerReplyTask,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="automation_runs",
)
initiated_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="initiated_ticket_automation_runs",
)
approved_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="approved_ticket_automation_runs",
)
approved_at = models.DateTimeField(null=True, blank=True)
started_at = models.DateTimeField(null=True, blank=True)
finished_at = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
constraints = [
models.UniqueConstraint(
fields=["ticket"],
condition=models.Q(
status__in=[
TicketAutomationRunStatus.QUEUED,
TicketAutomationRunStatus.RUNNING,
TicketAutomationRunStatus.WAITING_INPUT,
TicketAutomationRunStatus.WAITING_APPROVAL,
TicketAutomationRunStatus.WAITING_DELIVERY,
TicketAutomationRunStatus.WAITING_CUSTOMER,
]
),
name="unique_active_ticket_automation_run",
)
]
indexes = [
models.Index(
fields=["ticket", "status", "created_at"],
name="tickets_tic_ticket__f9dbaf_idx",
),
models.Index(
fields=["status", "next_action_at"],
name="tickets_tic_status_9ef355_idx",
),
]
class TicketAutomationEvent(models.Model):
run = models.ForeignKey(
TicketAutomationRun,
on_delete=models.CASCADE,
related_name="events",
)
sequence = models.PositiveIntegerField()
event_type = models.CharField(max_length=80)
payload = models.JSONField(default=dict, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["sequence"]
constraints = [
models.UniqueConstraint(
fields=["run", "sequence"],
name="unique_ticket_automation_event_sequence",
)
]
indexes = [
models.Index(
fields=["run", "sequence"],
name="tickets_tic_run_id_d6464b_idx",
)
]
# Kept temporarily for imports owned by stage 2.1 integrations.
TicketDraftImage = TicketDraftMaterial