新增群积分通货膨胀策略
1. 新增群聊插件积分真实消耗统计,区分成员持有积分与 SYSTEM 沉淀积分。 2. 为 plugin_points_cost 注解接入按群动态倍率,积分消耗偏低时自动提高实际扣费。 3. 优化积分不足与扣费成功提示,展示基础价、实际价与当前通胀倍率。
This commit is contained in:
@@ -610,6 +610,90 @@ class PointsDBOperator(BaseDBOperator):
|
||||
self.LOG.error(f"获取群组积分统计信息失败: {e}")
|
||||
return stats
|
||||
|
||||
def get_group_plugin_consumption_stats(self, group_id: str, lookback_hours: int = 72) -> Dict[str, Any]:
|
||||
"""
|
||||
获取群聊插件积分消耗统计信息。
|
||||
|
||||
这里专门为“积分通货膨胀”策略提供数据支撑,只统计真正会销毁积分总量的插件扣费:
|
||||
1. 用户之间转账、打劫、保释这类行为,本质上只是积分在用户之间流转,不算真实消耗;
|
||||
2. `plugin` 来源的 `spend` 流水,才代表群积分池被真正消耗掉了;
|
||||
3. 因此通胀策略应基于“当前群积分存量”与“最近一段时间插件真实消耗量”的关系来判断。
|
||||
|
||||
Args:
|
||||
group_id: 群ID
|
||||
lookback_hours: 统计最近多少小时的插件消耗
|
||||
|
||||
Returns:
|
||||
包含群积分存量、系统沉淀积分、最近插件消耗量等字段的统计字典
|
||||
"""
|
||||
normalized_hours = max(1, int(lookback_hours or 72))
|
||||
stats = {
|
||||
"group_id": group_id,
|
||||
"lookback_hours": normalized_hours,
|
||||
"total_users": 0,
|
||||
"active_points_total": 0,
|
||||
"system_points_total": 0,
|
||||
"plugin_spend_points": 0,
|
||||
"plugin_spend_count": 0,
|
||||
"plugin_spend_ratio": 0.0,
|
||||
}
|
||||
|
||||
if not group_id:
|
||||
return stats
|
||||
|
||||
try:
|
||||
# 用户积分存量统计中要把 SYSTEM 单独拆出来:
|
||||
# SYSTEM 账户通常用于承接抽水、保释金等沉淀积分,
|
||||
# 这些积分已经不在普通成员手里流通,所以需要单独记录,避免干扰真实“群成员持有积分”。
|
||||
points_result = self.execute_query(
|
||||
"""
|
||||
SELECT
|
||||
SUM(CASE WHEN user_id <> 'SYSTEM' THEN 1 ELSE 0 END) AS total_users,
|
||||
SUM(CASE WHEN user_id <> 'SYSTEM' THEN total_points ELSE 0 END) AS active_points_total,
|
||||
SUM(CASE WHEN user_id = 'SYSTEM' THEN total_points ELSE 0 END) AS system_points_total
|
||||
FROM t_user_points
|
||||
WHERE group_id = %s
|
||||
""",
|
||||
(group_id,),
|
||||
fetch_one=True,
|
||||
) or {}
|
||||
|
||||
# 最近插件消耗采用时间窗口统计。
|
||||
# 只看 plugin 来源的 spend,能更准确反映“带注解功能”对积分池的真实消耗效率。
|
||||
time_boundary = datetime.now() - timedelta(hours=normalized_hours)
|
||||
spend_result = self.execute_query(
|
||||
"""
|
||||
SELECT
|
||||
SUM(CASE WHEN transaction_type = 'spend' AND source = %s THEN ABS(points) ELSE 0 END)
|
||||
AS plugin_spend_points,
|
||||
SUM(CASE WHEN transaction_type = 'spend' AND source = %s THEN 1 ELSE 0 END)
|
||||
AS plugin_spend_count
|
||||
FROM t_point_transactions
|
||||
WHERE group_id = %s
|
||||
AND created_at >= %s
|
||||
""",
|
||||
(PointSource.PLUGIN.value, PointSource.PLUGIN.value, group_id, time_boundary),
|
||||
fetch_one=True,
|
||||
) or {}
|
||||
|
||||
stats["total_users"] = int(points_result.get("total_users") or 0)
|
||||
stats["active_points_total"] = int(points_result.get("active_points_total") or 0)
|
||||
stats["system_points_total"] = int(points_result.get("system_points_total") or 0)
|
||||
stats["plugin_spend_points"] = int(spend_result.get("plugin_spend_points") or 0)
|
||||
stats["plugin_spend_count"] = int(spend_result.get("plugin_spend_count") or 0)
|
||||
|
||||
active_points_total = stats["active_points_total"]
|
||||
if active_points_total > 0:
|
||||
stats["plugin_spend_ratio"] = round(
|
||||
stats["plugin_spend_points"] / active_points_total,
|
||||
6,
|
||||
)
|
||||
|
||||
return stats
|
||||
except Exception as e:
|
||||
self.LOG.error(f"获取群聊插件积分消耗统计失败: {e}")
|
||||
return stats
|
||||
|
||||
def imprison_user(self, user_id: str, group_id: str, hours: int = 24, reason: str = None) -> bool:
|
||||
"""关押用户
|
||||
Args:
|
||||
|
||||
Reference in New Issue
Block a user