【悟凡】真正意义上的净土重生:只保留核心逻辑
This commit is contained in:
126
backend/meetings/models.py
Normal file
126
backend/meetings/models.py
Normal file
@@ -0,0 +1,126 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth import get_user_model
|
||||
import uuid
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Meeting(models.Model):
|
||||
"""会议室模型"""
|
||||
STATUS_CHOICES = [
|
||||
('pending', '待开始'),
|
||||
('active', '进行中'),
|
||||
('ended', '已结束'),
|
||||
]
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
topic = models.CharField(max_length=200, verbose_name='会议主题')
|
||||
host = models.ForeignKey(User, on_delete=models.CASCADE, related_name='hosted_meetings')
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
|
||||
invite_code = models.CharField(max_length=20, unique=True, verbose_name='邀请码')
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
started_at = models.DateTimeField(null=True, blank=True)
|
||||
ended_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'meetings'
|
||||
verbose_name = '会议室'
|
||||
verbose_name_plural = '会议室'
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.topic} ({self.host.username})"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.invite_code:
|
||||
self.invite_code = uuid.uuid4().hex[:8].upper()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class Participant(models.Model):
|
||||
"""参会者模型"""
|
||||
AGENT_TYPE_CHOICES = [
|
||||
('human', '人类'),
|
||||
('openclaw', 'OpenClaw Agent'),
|
||||
('other', '其他 AI'),
|
||||
]
|
||||
|
||||
meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE, related_name='participants')
|
||||
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
|
||||
|
||||
# Agent 信息
|
||||
agent_type = models.CharField(max_length=20, choices=AGENT_TYPE_CHOICES)
|
||||
agent_id = models.CharField(max_length=100, null=True, blank=True)
|
||||
agent_name = models.CharField(max_length=100, verbose_name='Agent 名称')
|
||||
agent_emoji = models.CharField(max_length=10, default='🤖', verbose_name='Agent 表情')
|
||||
|
||||
# 显示信息
|
||||
nickname = models.CharField(max_length=100, verbose_name='昵称')
|
||||
is_host = models.BooleanField(default=False)
|
||||
joined_at = models.DateTimeField(auto_now_add=True)
|
||||
left_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
# API 认证(Agent 用)
|
||||
api_key = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'participants'
|
||||
verbose_name = '参会者'
|
||||
verbose_name_plural = '参会者'
|
||||
indexes = [
|
||||
models.Index(fields=['meeting', 'agent_id']),
|
||||
models.Index(fields=['agent_type', 'meeting']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.agent_emoji} {self.nickname}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.api_key and self.agent_type != 'human':
|
||||
self.api_key = uuid.uuid4().hex
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class Message(models.Model):
|
||||
"""消息模型"""
|
||||
meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE, related_name='messages')
|
||||
sender = models.ForeignKey(Participant, on_delete=models.CASCADE, related_name='sent_messages')
|
||||
content = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
# 信箱机制
|
||||
is_broadcast = models.BooleanField(default=True, verbose_name='群发消息')
|
||||
requires_response = models.BooleanField(default=False, verbose_name='需要回复')
|
||||
in_reply_to = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, related_name='replies')
|
||||
|
||||
# 读取状态
|
||||
read_by = models.ManyToManyField(Participant, related_name='read_messages', blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'messages'
|
||||
verbose_name = '消息'
|
||||
verbose_name_plural = '消息'
|
||||
ordering = ['created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['meeting', 'created_at']),
|
||||
models.Index(fields=['is_broadcast', 'created_at']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.sender.nickname}: {self.content[:50]}"
|
||||
|
||||
|
||||
class MeetingMinutes(models.Model):
|
||||
"""会议纪要模型"""
|
||||
meeting = models.OneToOneField(Meeting, on_delete=models.CASCADE, related_name='minutes')
|
||||
content = models.TextField()
|
||||
generated_at = models.DateTimeField(auto_now_add=True)
|
||||
exported_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'meeting_minutes'
|
||||
verbose_name = '会议纪要'
|
||||
verbose_name_plural = '会议纪要'
|
||||
|
||||
def __str__(self):
|
||||
return f"会议纪要 - {self.meeting.topic}"
|
||||
Reference in New Issue
Block a user