'积分', self::REWARD_COIN => '金币', self::REWARD_PROP => '道具', self::REWARD_MEDAL => '勋章', ]; } public static function getRewardTypeText(int $type): string { return self::rewardTypeList()[$type] ?? '未知'; } /** * 启用中的任务(前台展示) */ public static function getEnabledList() { return self::where('status', 1)->order('sort', 'asc')->select(); } /** * 取某用户已领取的任务ID集合 */ public static function getClaimedTaskIds(int $uid): array { self::ensureSchema(); // 确保 member_task / member_prop 关联表已就绪(静态入口可能未实例化模型) if ($uid <= 0) { return []; } return Db::name('member_task')->where('uid', $uid)->column('task_id') ?: []; } /** * 领取任务并发放奖励(幂等:同一任务仅可领取一次) * @return array [bool $ok, string $msg] */ public static function claim(int $uid, int $taskId): array { self::ensureSchema(); // 确保 user_task / user_prop 等关联表已就绪(静态入口可能未实例化模型) if ($uid <= 0) { return [false, '请先登录']; } $task = self::where('id', $taskId)->where('status', 1)->find(); if (!$task) { return [false, '任务不存在或未启用']; } $task = $task->toArray(); // 是否已领取 $exists = Db::name('member_task')->where('uid', $uid)->where('task_id', $taskId)->find(); if ($exists) { return [false, '该任务已领取']; } $num = (int) $task['reward_num']; if ($num <= 0) { return [false, '奖励数量无效']; } Db::startTrans(); try { // 发放奖励 switch ((int) $task['reward_type']) { case self::REWARD_SCORE: [$ok, $msg] = \ywxapp\model\Score::change($uid, \ywxapp\model\Score::TYPE_GAIN, $num, '完成任务:' . $task['title']); if (! $ok) { throw new \Exception($msg); } break; case self::REWARD_COIN: Db::name('member_wallets')->where('uid', $uid)->inc('coins', $num)->update(); Db::name('member_bill')->insert([ 'uid' => $uid, 'currency' => 2, // 2=金币 'type' => 1, // 1=收入 'amount' => $num, 'balance' => Db::name('member_wallets')->where('uid', $uid)->value('coins') ?: $num, 'remark' => '完成任务:' . $task['title'], 'create_at' => time(), ]); break; case self::REWARD_PROP: Db::name('member_prop')->insert([ 'uid' => $uid, 'prop_id' => $num, // reward_num 存道具ID 'num' => (int) ($task['prop_num'] ?: 1), 'create_at' => time(), ]); break; case self::REWARD_MEDAL: // reward_num 存勋章ID $grant = Medal::grant($uid, $num); if (!$grant[0]) { throw new \Exception($grant[1]); } break; default: throw new \Exception('未知奖励类型'); } // 领取记录 Db::name('member_task')->insert([ 'uid' => $uid, 'task_id' => $taskId, 'reward_type' => $task['reward_type'], 'reward_num' => $num, 'create_at' => time(), ]); Db::commit(); return [true, '领取成功']; } catch (\Throwable $e) { Db::rollback(); return [false, '领取失败:' . $e->getMessage()]; } } /** * 表自愈:确保任务相关表(member_prop / member_task)与扩展列已就绪。 */ public static function ensureSchema(): void { $prefix = BaseModel::currentPrefix(); BaseModel::ensureTableFromInstall($prefix, 'task'); BaseModel::ensureTableFromInstall($prefix, 'member_prop'); BaseModel::ensureTableFromInstall($prefix, 'member_task'); BaseModel::ensureColumn("{$prefix}member", 'score', "int unsigned NOT NULL DEFAULT 0 COMMENT '积分(做任务/互动获得)'"); BaseModel::ensureColumn("{$prefix}task", 'prop_num', "int NOT NULL DEFAULT 1 COMMENT '道具数量(奖励类型为道具时生效)'"); } }