'获取', self::TYPE_SPEND => '消费', ]; } /** * 确保 score_rule / score_log 关联表已就绪(静态入口可能未实例化模型) */ public static function ensureSchema(): void { $prefix = BaseModel::currentPrefix(); BaseModel::ensureTableFromInstall($prefix, 'score_rule'); BaseModel::ensureTableFromInstall($prefix, 'score_log'); BaseModel::ensureColumn("{$prefix}member", 'score', "int unsigned NOT NULL DEFAULT 0 COMMENT '积分(做任务/互动获得)'"); } /** * 积分变动(带流水记录,事务安全) * @param int $uid 用户ID * @param int $type 1=收入 2=支出 * @param int $value 变动值(正数) * @param string $remark 备注 * @param int $ruleId 关联规则ID(默认0) * @return array [bool, string] */ public static function change(int $uid, int $type, int $value, string $remark = '', int $ruleId = 0): array { self::ensureSchema(); $uid = (int) $uid; $value = (int) $value; if ($uid <= 0 || $value <= 0) { return [false, '参数错误']; } $type = $type === self::TYPE_SPEND ? self::TYPE_SPEND : self::TYPE_GAIN; Db::startTrans(); try { $user = Db::name('member')->where('uid', $uid)->lock(true)->find(); if (!$user) { throw new \Exception('用户不存在'); } if ($type === self::TYPE_SPEND && $user['score'] < $value) { throw new \Exception('积分余额不足'); } $balance = $type === self::TYPE_SPEND ? $user['score'] - $value : $user['score'] + $value; Db::name('member')->where('uid', $uid)->update(['score' => $balance]); Db::name('score_log')->insert([ 'uid' => $uid, 'rule_id' => $ruleId, 'type' => $type, 'value' => $value, 'balance' => $balance, 'remark' => $remark, 'create_at' => time(), ]); Db::commit(); return [true, 'ok']; } catch (\Throwable $e) { Db::rollback(); return [false, $e->getMessage()]; } } /** * 积分流水列表(后台查看) */ public static function logList(int $uid = 0, int $page = 1, int $limit = 15): array { self::ensureSchema(); $query = Db::name('score_log'); if ($uid > 0) { $query->where('uid', $uid); } $count = $query->count(); $list = $query->order('id', 'desc') ->page($page, $limit) ->select() ->toArray(); return ['count' => $count, 'list' => $list]; } }