hasOne(UserAuth::class, 'user_id'); } /** * @notes 搜索器-用户信息 * @param $query * @param $value * @param $data * @author 段誉 * @date 2022/9/22 16:12 */ public function searchKeywordAttr($query, $value, $data) { if ($value) { $query->where('sn|nickname|mobile|account', 'like', '%' . $value . '%'); } } /** * @notes 搜索器-注册来源 * @param $query * @param $value * @param $data * @author 段誉 * @date 2022/9/22 16:13 */ public function searchChannelAttr($query, $value, $data) { if ($value) { $query->where('channel', '=', $value); } } /** * @notes 搜索器-注册时间 * @param $query * @param $value * @param $data * @author 段誉 * @date 2022/9/22 16:13 */ public function searchCreateTimeStartAttr($query, $value, $data) { if ($value) { $query->where('create_time', '>=', strtotime($value)); } } /** * @notes 搜索器-注册时间 * @param $query * @param $value * @param $data * @author 段誉 * @date 2022/9/22 16:13 */ public function searchCreateTimeEndAttr($query, $value, $data) { if ($value) { $query->where('create_time', '<=', strtotime($value)); } } /** * @notes 头像获取器 - 用于头像地址拼接域名 * @param $value * @return string * @author Tab * @date 2021/7/17 14:28 */ public function getAvatarAttr($value) { return trim($value) ? FileService::getFileUrl($value) : ''; } /** * @notes 获取器-性别描述 * @param $value * @param $data * @return string|string[] * @author 段誉 * @date 2022/9/7 15:15 */ public function getSexAttr($value, $data) { return UserEnum::getSexDesc($value); } /** * @notes 登录时间 * @param $value * @return string * @author 段誉 * @date 2022/9/23 18:15 */ public function getLoginTimeAttr($value) { return $value ? date('Y-m-d H:i:s', $value) : ''; } /** * @notes 生成用户编码 * @param string $prefix * @param int $length * @return string * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException * @author 段誉 * @date 2022/9/16 10:33 */ public static function createUserSn($prefix = '', $length = 8) { $rand_str = ''; for ($i = 0; $i < $length; $i++) { $rand_str .= mt_rand(1, 9); } $sn = $prefix . $rand_str; if (User::where(['sn' => $sn])->find()) { return self::createUserSn($prefix, $length); } return $sn; } /** * @notes VIP等级名称映射(从数据库动态获取) */ public static function getVipLevelMap(): array { static $map = null; if ($map === null) { $map = [0 => '普通用户']; $levels = \app\common\model\vip\VipLevel::where('status', 1)->column('name', 'level'); foreach ($levels as $level => $name) { $map[(int) $level] = $name; } } return $map; } /** * @notes 获取VIP信息(含自动过期判断和免费次数重置) */ public function getVipInfo(): array { $now = time(); $isVip = $this->getData('is_vip') == 1 && $this->getData('vip_expire_time') > $now; // VIP已过期自动清除 if ($this->getData('is_vip') == 1 && $this->getData('vip_expire_time') <= $now) { $this->save(['is_vip' => 0, 'vip_level' => 0]); $isVip = false; } // 每日免费次数重置 $today = date('Y-m-d'); if ($this->getData('ai_free_date') !== $today) { $this->save(['ai_free_count' => 3, 'ai_free_date' => $today]); $freeCount = 3; } else { $freeCount = (int) $this->getData('ai_free_count'); } // 获取等级卡片背景图 $cardImage = ''; if ($isVip) { $level = (int) $this->getData('vip_level'); $cardImage = \app\common\model\vip\VipLevel::where('level', $level) ->where('status', 1) ->value('image', ''); } return [ 'is_vip' => $isVip, 'vip_level' => $isVip ? (int) $this->getData('vip_level') : 0, 'vip_level_name' => $isVip ? (self::getVipLevelMap()[$this->getData('vip_level')] ?? '会员') : '', 'vip_expire_time' => $isVip ? date('Y年m月d日', $this->getData('vip_expire_time')) : '', 'vip_expire_timestamp' => $isVip ? (int) $this->getData('vip_expire_time') : 0, 'vip_card_image' => $cardImage, 'ai_free_count' => $freeCount, ]; } /** * @notes 生成唯一邀请码 */ public static function createInviteCode($length = 8): string { $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; do { $code = ''; for ($i = 0; $i < $length; $i++) { $code .= $chars[mt_rand(0, strlen($chars) - 1)]; } } while (User::where('invite_code', $code)->find()); return $code; } }