* @Date: 2026-08-07 22:53:48 * @LastEditors: YwxApp * @LastEditTime: 2026-08-19 21:12:33 * @Description: * @FilePath: \ywxapp_dev\ywxapp\model\Score.php * @CustomString: Copyright (c) 2026 YwxApp */ declare(strict_types=1); namespace ywxapp\model; use ywxapp\model\BaseModel; use think\facade\Db; use think\model\concern\SoftDelete; /** * 积分规则 & 积分流水 */ class MebmberScore extends BaseModel { use SoftDelete; /** * 模型配置(BaseModel::applyOptions 约定) */ protected function getOptions(): array { return [ 'strict' => true, 'autoWriteTimestamp' => 'int', 'createTime' => 'create_at', 'updateTime' => 'update_at', 'readonly' => ['view_count'] ]; } // 规则类型 const TYPE_GAIN = 1; // 获取 const TYPE_SPEND = 2; // 消费 public static function typeList(): array { return [ self::TYPE_GAIN => '获取', self::TYPE_SPEND => '消费', ]; } /** * 确保 score_rule / score_log 关联表已就绪(静态入口可能未实例化模型) */ public static function ensureSchema(): void { $prefix = BaseModel::currentPrefix(); BaseModel::ensureTableFromInstall($prefix, 'member_score_rule'); BaseModel::ensureTableFromInstall($prefix, 'member_score_log'); BaseModel::ensureColumn("{$prefix}member_user", '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_user')->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_user')->where('uid', $uid)->update(['score' => $balance]); Db::name('member_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('member_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]; } }