from django.db import models from django.contrib.auth import get_user_model User = get_user_model() from django.db import models from django.db import models from api.models import UserInfo class City(models.Model): name = models.CharField(max_length=50, verbose_name="城市名称") code = models.CharField(max_length=20, unique=True, verbose_name="城市代码") description = models.TextField(verbose_name="城市描述", blank=True) image = models.ImageField(upload_to='cities/', verbose_name="城市图片", null=True, blank=True) is_hot = models.BooleanField(default=False, verbose_name="是否热门") # 新增的经纬度字段 latitude = models.DecimalField( max_digits=9, decimal_places=6, verbose_name="纬度", null=True, blank=True, help_text="例如:北京的纬度是39.9042" ) longitude = models.DecimalField( max_digits=9, decimal_places=6, verbose_name="经度", null=True, blank=True, help_text="例如:北京的经度是116.4074" ) created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间") class Meta: verbose_name = "城市" verbose_name_plural = "城市" def __str__(self): return self.name class Attraction(models.Model): city = models.ForeignKey(City, on_delete=models.CASCADE, related_name='attractions') name = models.CharField(max_length=100, verbose_name="景点名称") description = models.TextField(verbose_name="景点描述") history_significance = models.TextField(verbose_name="历史意义", blank=True) learning_point = models.TextField(verbose_name="学习要点", blank=True) short_desc = models.CharField(max_length=200, verbose_name="简短描述", blank=True) address = models.CharField(max_length=200, verbose_name="地址") latitude = models.FloatField(verbose_name="纬度", null=True, blank=True) longitude = models.FloatField(verbose_name="经度", null=True, blank=True) ticket_price = models.DecimalField( max_digits=8, decimal_places=2, verbose_name="门票价格", default=0 ) ticket_info = models.CharField( max_length=100, verbose_name="门票信息", blank=True, default="凭身份证免费参观" ) open_hours = models.CharField(max_length=100, verbose_name="开放时间", blank=True) image = models.ImageField( upload_to='attractions/', verbose_name="景点图片", null=True, blank=True ) tags = models.JSONField(default=list, verbose_name="标签") history = models.TextField(verbose_name="历史背景", blank=True) is_featured = models.BooleanField(default=False, verbose_name="是否特色") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = "景点" verbose_name_plural = "景点" def __str__(self): return f"{self.name} ({self.city.name})" class RedTourismPlan(models.Model): # 行程状态选项 STATUS_CHOICES = ( ('in_progress', '进行中'), ('completed', '已完成'), ) user = models.ForeignKey( UserInfo, on_delete=models.CASCADE, related_name='red_tourism_plans', verbose_name='关联用户', null=True, blank=True ) # 新增状态字段 status = models.CharField( max_length=20, choices=STATUS_CHOICES, default='in_progress', verbose_name='行程状态' ) # 其他字段保持不变... cities = models.ManyToManyField( City, related_name='red_tourism_plans', verbose_name='关联城市' ) title = models.CharField(max_length=200, verbose_name='行程标题') description = models.TextField(verbose_name='行程描述') days = models.PositiveIntegerField(verbose_name='天数') created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') last_updated = models.DateTimeField(auto_now=True, verbose_name='最后更新时间') is_red_tourism = models.BooleanField(default=True, verbose_name='是否红色旅游') statistics = models.JSONField(default=dict, verbose_name='统计数据') education_goals = models.JSONField(default=list, verbose_name='教育目标') original_data = models.JSONField(default=dict, verbose_name='原始数据') class Meta: verbose_name = '红色旅游行程' verbose_name_plural = verbose_name ordering = ['-created_at'] def __str__(self): return f"{self.title} (用户: {self.user.phone})" class RedTourismDayPlan(models.Model): plan = models.ForeignKey( RedTourismPlan, on_delete=models.CASCADE, related_name='day_plans', verbose_name='所属行程', null=True, blank=True ) day_number = models.PositiveIntegerField(verbose_name='第几天') theme = models.CharField(max_length=100, verbose_name='当日主题') summary = models.TextField(blank=True, verbose_name='当日总结') transport = models.CharField(max_length=50, verbose_name='交通方式') travel_tips = models.JSONField(default=list, verbose_name='旅行提示') class Meta: verbose_name = '红色旅游每日行程' verbose_name_plural = verbose_name ordering = ['plan', 'day_number'] unique_together = ('plan', 'day_number') def __str__(self): return f"{self.plan.title} - 第{self.day_number}天" class RedTourismSpot(models.Model): day_plan = models.ForeignKey( RedTourismDayPlan, on_delete=models.CASCADE, related_name='spots', verbose_name='所属日计划', null=True, blank=True ) spot_id = models.CharField(max_length=50, verbose_name='景点ID') name = models.CharField(max_length=100, verbose_name='景点名称') description = models.TextField(verbose_name='景点描述') address = models.CharField(max_length=200, verbose_name='地址') open_hours = models.CharField(max_length=50, verbose_name='开放时间') ticket_info = models.CharField(max_length=100, verbose_name='门票信息') history_significance = models.TextField(verbose_name='历史意义') image = models.URLField(max_length=500, verbose_name='图片URL') latitude = models.FloatField(verbose_name='纬度') longitude = models.FloatField(verbose_name='经度') visit_time = models.CharField(max_length=50, verbose_name='参观时间') duration = models.PositiveIntegerField(verbose_name='参观时长(分钟)') order = models.PositiveIntegerField(verbose_name='排序') visiting_etiquette = models.JSONField(default=list, verbose_name='参观礼仪') is_red_tourism = models.BooleanField(default=True, verbose_name='是否红色景点') has_checked = models.BooleanField(default=False, verbose_name='是否已打卡') class Meta: verbose_name = '红色旅游景点' verbose_name_plural = verbose_name ordering = ['day_plan', 'order'] def __str__(self): return f"{self.name} (第{self.day_plan.day_number}天)" # models.py class UserCheckIn(models.Model): """用户打卡记录模型""" user = models.ForeignKey( User, on_delete=models.CASCADE, verbose_name='用户' ) spot = models.ForeignKey( 'RedTourismSpot', on_delete=models.CASCADE, verbose_name='景点' ) plan = models.ForeignKey( 'RedTourismPlan', on_delete=models.CASCADE, verbose_name='行程' ) check_in_time = models.DateTimeField( auto_now_add=True, verbose_name='打卡时间' ) image_url = models.URLField( max_length=500, blank=True, verbose_name='打卡图片URL' ) note = models.TextField( blank=True, verbose_name='打卡文案', default='' ) location = models.JSONField( default=dict, verbose_name='位置信息' ) class Meta: verbose_name = '用户打卡记录' verbose_name_plural = verbose_name unique_together = ('user', 'spot') # 防止重复打卡 def __str__(self): return f"{self.user.username}于{self.check_in_time}打卡{self.spot.name}"