Files
meeting-room/backend/meetings/models.py

127 lines
4.6 KiB
Python
Raw Normal View History

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}"