WR-002 UserLevelRewardGrant.device on_delete CASCADE → SET_NULL,加 device_snapshot_id, unique 改为 partial(device 非空时唯一),与 AffinityLog.device SET_NULL 对齐 WR-003 AffinityLog 删除 3 个低价值索引(user/rule_key/source -created_at 复合) WR-004 event_id 改为 null=True,partial unique 用 isnull=False;RunPython '' → NULL WR-005 seed 加 companion_30min 默认规则 WR-006 description 显式 default='';DEFAULT_LEVELS 全部补 description WR-007 seed_affinity 每条 spec 独立事务,部分失败可重跑 WR-008 ParadiseUser.favorability 字段保留 + UserInfoSerializer 移除暴露 + [DEPRECATED] 标记 WR-009(见 Commit B:AffinityLevel.clean + save full_clean 多层兜底) IN-001 5 个弃用字段 help_text 加 [DEPRECATED — 计划于 P2 完成后删除] IN-002 DEFAULT_RULES/LEVELS/SETTING 抽到 userapp/affinity/defaults.py IN-003 AffinitySetting.daily_cap RenameField → global_daily_cap(区分 AffinityRule.daily_cap) IN-004 AffinityLog.__str__ 用 pk or 'new' 兜底 None IN-005(见 Commit A:is_active → is_bound 改名) IN-006(见 Commit C:0006 print 前缀改为 [migration 0006_...]) 迁移 0009 手工修正:daily_cap 改名用 RenameField(保留数据),不是 Remove+Add; event_id '' → NULL 数据兜底;UserLevelRewardGrant on_delete + conditional unique 重建。 详见 docs/REVIEW-affinity-P1.md WR-* / IN-* 与 FIX-REPORT.md。
141 lines
5.8 KiB
Python
141 lines
5.8 KiB
Python
"""好感度系统默认数据常量
|
||
|
||
供 seed_affinity management command、单元测试、P2 服务层(fallback 配置)等共享。
|
||
|
||
与设计文档对应:
|
||
DEFAULT_RULES — 「好感度系统功能与规则设计.md」§4.2 互动规则
|
||
DEFAULT_LEVELS — 同文档 §6.2 等级表
|
||
DEFAULT_SETTING — 同文档 §3.2 全局参数 + §5.1 衰减字段
|
||
|
||
IN-002:从 management/commands/seed_affinity.py 抽取,避免 management command
|
||
文件膨胀,且让测试代码 / P2 服务层可以正规 import:
|
||
from userapp.affinity.defaults import DEFAULT_RULES, DEFAULT_LEVELS, DEFAULT_SETTING
|
||
"""
|
||
|
||
# 默认规则,与设计文档 §4.2 一致
|
||
# WR-005:新增 1 条 trigger_type='companion_time' 规则(陪伴 30 分钟)
|
||
# WR-006:所有 description 显式填写,不依赖 model blank=True 隐式默认
|
||
DEFAULT_RULES = [
|
||
{
|
||
'rule_key': 'card', 'name': '使用卡片', 'description': '用户使用洛天依卡片',
|
||
'trigger_type': 'action',
|
||
'min_change': 1, 'max_change': 3, 'single_cap': 3, 'daily_cap': 10,
|
||
'cooldown_seconds': 0, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'chat', 'name': '对话', 'description': '与洛天依进行对话',
|
||
'trigger_type': 'action',
|
||
'min_change': 1, 'max_change': 5, 'single_cap': 5, 'daily_cap': 15,
|
||
'cooldown_seconds': 30, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'feed', 'name': '喂食', 'description': '给洛天依喂食',
|
||
'trigger_type': 'action',
|
||
'min_change': 2, 'max_change': 8, 'single_cap': 8, 'daily_cap': 16,
|
||
'cooldown_seconds': 0, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'touch', 'name': '抚摸', 'description': '抚摸洛天依',
|
||
'trigger_type': 'action',
|
||
'min_change': 1, 'max_change': 3, 'single_cap': 3, 'daily_cap': 9,
|
||
'cooldown_seconds': 10, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'dress', 'name': '换装', 'description': '为洛天依更换服装',
|
||
'trigger_type': 'action',
|
||
'min_change': 2, 'max_change': 6, 'single_cap': 6, 'daily_cap': 12,
|
||
'cooldown_seconds': 0, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'prop', 'name': '使用道具', 'description': '使用互动道具',
|
||
'trigger_type': 'action',
|
||
'min_change': 1, 'max_change': 4, 'single_cap': 4, 'daily_cap': 12,
|
||
'cooldown_seconds': 0, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'gift', 'name': '送礼物', 'description': '赠送礼物给洛天依',
|
||
'trigger_type': 'action',
|
||
'min_change': 5, 'max_change': 15, 'single_cap': 15, 'daily_cap': 20,
|
||
'cooldown_seconds': 0, 'is_negative': False, 'is_enabled': True,
|
||
},
|
||
{
|
||
'rule_key': 'decay', 'name': '无互动衰减', 'description': '长时间不互动导致好感度下降',
|
||
'trigger_type': 'decay',
|
||
'min_change': -3, 'max_change': -1, 'single_cap': 3, 'daily_cap': 5,
|
||
'cooldown_seconds': 0, 'is_negative': True, 'is_enabled': True,
|
||
},
|
||
# WR-005:陪伴时长类规则(数值参考设计文档 §4.2,具体值可由运营在 admin 调整)
|
||
{
|
||
'rule_key': 'companion_30min', 'name': '陪伴 30 分钟',
|
||
'description': '与洛天依持续陪伴 30 分钟可获得好感度(数值待产品最终对齐,先用保守默认)',
|
||
'trigger_type': 'companion_time',
|
||
'min_change': 1, 'max_change': 2, 'single_cap': 2, 'daily_cap': 8,
|
||
'cooldown_seconds': 0, 'is_negative': False, 'is_enabled': True,
|
||
'min_continuous_minutes': 30, 'max_count_per_day': 4,
|
||
},
|
||
]
|
||
|
||
|
||
# 默认等级,与设计文档 §6.2 一致
|
||
# WR-006:所有 description 显式填写
|
||
DEFAULT_LEVELS = [
|
||
{
|
||
'level': 1, 'name': '初识',
|
||
'description': '初次相识阶段,了解彼此的基础互动',
|
||
'min_affinity': 0, 'max_affinity': 20,
|
||
'unlock_content': '基础对话功能',
|
||
'reward_type': 'unlock', 'reward_currency': 0, 'reward_items': [],
|
||
'is_enabled': True,
|
||
},
|
||
{
|
||
'level': 2, 'name': '相识',
|
||
'description': '熟悉彼此个性,解锁基础道具与服装',
|
||
'min_affinity': 21, 'max_affinity': 40,
|
||
'unlock_content': '基础服装、道具使用',
|
||
'reward_type': 'unlock', 'reward_currency': 0, 'reward_items': [],
|
||
'is_enabled': True,
|
||
},
|
||
{
|
||
'level': 3, 'name': '熟悉',
|
||
'description': '互动深入,解锁更多内容',
|
||
'min_affinity': 41, 'max_affinity': 60,
|
||
'unlock_content': '更多服装、特殊对话',
|
||
'reward_type': 'unlock', 'reward_currency': 0, 'reward_items': [],
|
||
'is_enabled': True,
|
||
},
|
||
{
|
||
'level': 4, 'name': '亲密',
|
||
'description': '亲密互动阶段,解锁限定内容',
|
||
'min_affinity': 61, 'max_affinity': 80,
|
||
'unlock_content': '限定服装、特殊互动',
|
||
'reward_type': 'unlock', 'reward_currency': 0, 'reward_items': [],
|
||
'is_enabled': True,
|
||
},
|
||
{
|
||
'level': 5, 'name': '挚友',
|
||
'description': '最高亲密度,解锁专属剧情',
|
||
'min_affinity': 81, 'max_affinity': 100,
|
||
'unlock_content': '专属内容、特殊剧情',
|
||
'reward_type': 'unlock', 'reward_currency': 0, 'reward_items': [],
|
||
'is_enabled': True,
|
||
},
|
||
]
|
||
|
||
|
||
# 默认全局设置(用于 seed_affinity 在表为空时创建)
|
||
DEFAULT_SETTING = {
|
||
'initial_affinity': 10,
|
||
'max_affinity': 100,
|
||
'global_daily_cap': 20, # IN-003:重命名 daily_cap → global_daily_cap
|
||
'decay_rate': 2,
|
||
'decay_threshold': 3,
|
||
'decay_min_decay': 1,
|
||
'decay_max_decay': 3,
|
||
'decay_cap': 5,
|
||
'decay_min_floor': 0,
|
||
'enable_notify': True,
|
||
'enable_rewards': True,
|
||
'notify_decay': True,
|
||
'timezone': 'Asia/Shanghai',
|
||
}
|