// +---------------------------------------------------------------------- namespace app\common\model\groupon; use cores\BaseModel; use cores\exception\BaseException; use app\common\service\User as UserService; use app\common\model\groupon\TaskUsers as TaskUsersModel; use app\common\enum\groupon\TaskStatus as TaskStatusEnum; use app\common\enum\groupon\ActiveType as ActiveTypeEnum; use think\model\relation\BelongsTo; /** * 拼团拼单模型 * Class Task * @package app\common\model\groupon */ class Task extends BaseModel { // 定义表名 protected $name = 'groupon_task'; // 定义主键 protected $pk = 'task_id'; // 定义别名 protected string $alias = 'task'; // 追加的字段 protected $append = ['joined_people']; /** * 关联模型:拼团商品 * @return BelongsTo */ public function groupGoods(): BelongsTo { return $this->belongsTo('Goods'); } /** * 关联模型:用户信息 * @return BelongsTo */ public function user(): BelongsTo { $module = self::getCalledModule(); return $this->BelongsTo("app\\{$module}\\model\\User")->field(['user_id', 'nick_name', 'avatar_id']); } /** * 获取器:已拼的人数 (实际人数+模拟机器人) * @param $value * @param $item * @return false|string */ public function getJoinedPeopleAttr($value, $item) { return $item['actual_people'] + $item['robot_people']; } /** * 获取器:拼单开始时间 * @param $value * @return false|string */ public function getStartTimeAttr($value) { return format_time($value); } /** * 获取器:拼单结束时间 * @param $value * @return false|string */ public function getEndTimeAttr($value) { return format_time($value); } /** * 获取拼单详情记录 * @param int $taskId 拼单ID * @param array $with * @return static|array|null */ public static function detail(int $taskId, array $with = []) { return static::get($taskId, $with); } /** * 获取拼单详情 (基础) * @param int $taskId * @return static|array|null * @throws BaseException */ public static function getBasic(int $taskId) { $detail = static::detail($taskId); if (empty($detail) || $detail['is_delete']) { throwError('很抱歉,未找到该拼团'); } return $detail; } /** * 验证当前拼单是否已完成 * @param int $taskId 拼单ID * @return bool * @throws BaseException */ public function checkTaskComplete(int $taskId): bool { $detail = static::getBasic($taskId); return in_array($detail['status'], [TaskStatusEnum::SUCCESS, TaskStatusEnum::FAIL]); } /** * 验证当前拼单是否已成功 * @param int $taskId 拼单ID * @return bool * @throws BaseException */ public function checkTaskSuccess(int $taskId): bool { $detail = static::getBasic($taskId); return $detail['status'] == TaskStatusEnum::SUCCESS; } /** * 验证当前拼单是否允许加入新成员 * @param int $taskId 拼单ID * @param int|null $userId 用户ID (新成员) * @return bool * @throws BaseException */ public function checkToJoinByTaskId(int $taskId, ?int $userId = null): bool { // 获取拼单详情 $detail = static::getBasic($taskId); return $this->checkToJoin($detail, $userId); } /** * 验证当前拼单是否允许加入新成员 * @param mixed $detail 拼单记录详情 * @param int|null $userId 用户ID (新成员) * @param bool $checkIsNewUser 是否验证老带新拼团是否允许加入 * @return bool */ public function checkToJoin($detail, ?int $userId = null, bool $checkIsNewUser = true): bool { if ($detail['status'] != TaskStatusEnum::NORMAL) { $this->error = '当前拼单已结束'; return false; } if (time() > $detail->getData('end_time')) { $this->error = '当前拼单已结束'; return false; } if (($detail['actual_people'] + $detail['robot_people']) >= $detail['people']) { $this->error = '当前拼单人数已满'; return false; } if ($userId > 0 && TaskUsersModel::isJoin($detail['task_id'], $userId)) { $this->error = '当前用户已参与该拼单'; return false; } // 验证老带新拼团是否允许加入 if ($checkIsNewUser && !$this->checkToJoinByNew($detail['active_type'], $userId)) { $this->error = '很抱歉,您当前不是新用户 无法参与该拼团'; return false; } return true; } /** * 验证老带新拼团是否允许加入 * @param int $activeType * @param int|null $userId * @return bool */ private function checkToJoinByNew(int $activeType, ?int $userId = null): bool { return $activeType != ActiveTypeEnum::PULL_NEW || UserService::checkIsNewUser($userId); } }